《vite技术揭秘、还原与实战》第4节--加载index.html

前言

在上一节,我们创建了一个http服务器,但是当你进行访问的时候,会发现被拒绝,这是因为我们还没有对对应的请求做处理

本节我们将优先对index.html文件进行加载处理,它是整个预构建的入口点,非常重要

源码获取

传送门

更新进度

公众号:更新至第9

博客:更新至第3

源码分析

vite中,通过connect包来为http服务器提供中间件能力

ts 复制代码
// packages/vite/src/node/server/index.ts

const middlewares = connect() as Connect.Server
...
const { createServer } = await import('node:http')
createServer(middlewares)

因此,可以在中间件中去对指定的请求做处理

ts 复制代码
middlewares.use(htmlFallbackMiddleware(root, true));

中间件本身是一个函数,通过参数reqres就能够监听特定请求并做客制化处理后return到客户端

ts 复制代码
// packages/vite/src/node/server/middlewares/htmlFallback.ts

import history from 'connect-history-api-fallback'

export function htmlFallbackMiddleware(
  root: string,
  spaFallback: boolean
): Connect.NextHandleFunction {
  const historyHtmlFallbackMiddleware = history({
    // 打印日志
    logger: createDebugger("vite:html-fallback"),
    // 需要拦截和重写的接口路径
    // 此处意为将'/'路径重定向到'/index.html'
    rewrites: [
      {
        from: //$/,
        to({ parsedUrl, request }: any) {
          const rewritten =
            decodeURIComponent(parsedUrl.pathname) + "index.html";

          if (fs.existsSync(path.join(root, rewritten))) {
            return rewritten;
          }

          return spaFallback ? `/index.html` : request.url;
        },
      },
    ],
  });

  // 使用具名函数,当出现错误时,有利于快速定位
  return function viteHtmlFallbackMiddleware(req, res, next) {
    return historyHtmlFallbackMiddleware(req, res, next);
  };
}

代码实现

首先,在packages\vite\src\node\server文件夹下新建middlewares文件夹,它用来管理所有的中间件,比如后续对proxy的处理、对index.html的分析转换等

middlewares文件夹下新建htmlFallback.ts,它应该返回一个函数

ts 复制代码
export function htmlFallbackMiddleware(): Connect.NextHandleFunction {
  return function viteHtmlFallbackMiddleware(req, res, next) {};
}

并且将其在_createServer中作为中间件引入

ts 复制代码
async function _createServer(userConfig:UserConfig){
    ...
    const middlewares = connect() as Connect.Server
    ...
    middlewares.use(htmlFallbackMiddleware(//$/))
    ...
}

返回htmlFallback.ts文件,开始处理默认请求,在vite中,是采用的connect-history-api-fallback包来进行处理的,调库本身挺无聊的,而且这里的功能也不复杂,因此在这里我们就自己手动进行实现

如下,我们针对GET请求,匹配请求路径是否是/,然后到用户文件根目录中查找index.html 文件,找到后对其进行读取并返回到客户端,若找不到,则next到下一个中间件`即可

ts 复制代码
export function htmlFallbackMiddleware(
  target: RegExp
): Connect.NextHandleFunction {
  return function viteHtmlFallbackMiddleware(req, res, next) {
    // 对于svite加载资源而言,不存在POST请求
    if (req.method === "GET") {
      // req.url本身就是以'/'开头的
      const intactUrl = `http://127.0.0.1${req.url || "/"}`;
      const url = new URL(intactUrl);
      // target是注册中间件时的入参://$/
      const m = url.pathname.match(target);
      if (m) {
        const rewritten = decodeURIComponent(url.pathname) + "index.html";
        const intacFiletPath = join(process.cwd(), rewritten);
        if (existsSync(intacFiletPath)) {
          req.url = rewritten;
          res.statusCode = 200;
          res.setHeader("Content-Type", "text/html");
          // 将index.html文件内容作为响应返回
          res.end(readFileSync(intacFiletPath, "utf-8"));
        }
      }
    }
    return next();
  };
}

调试

启动playground/dev下的示例,打开浏览器,index.html可以被正常渲染

总结

本节,针对默认的/请求,将其转换为/index.html并读取和返回对应的文件内容,这样一来,浏览器就能够正常加载并解析html文件,并且在遇到srclink属性时发起相应的请求

相关推荐
Rain5099 小时前
2.1 Nest.js 项目初始化与模块化架构
开发语言·前端·javascript·后端·架构·数据分析·node.js
矩阵科学16 小时前
Langchain.js 实战五:Agent 实战
langchain·node.js
终将老去的穷苦程序员19 小时前
npm : 无法加载文件 C:\Program Files\nodejs\npm.ps1,因为在此系统上禁止运行脚
前端·npm·node.js
之歆19 小时前
Day10_Node.js 与 Express 开发实战指南:从零到一构建专业级 Web 服务
前端·node.js·express
天蓝色的鱼鱼1 天前
Vite 8 换上 Rolldown 后,前端构建真的会快很多吗?
前端·vite
之歆2 天前
Node.js 与 NPM 包管理完全指南
前端·npm·node.js
12点一刻2 天前
npx 使用入门教程:是什么、怎么用、和 npm 有什么区别
前端·npm·node.js
Sca_杰2 天前
速通抖音开放平台API-生活服务商应用
javascript·node.js
console.log('npc')2 天前
核心实战篇 生成式 UI+A2UI 协议 + 全栈 Agent 项目落地
node.js·react·#生成式ui·a2ui协议·ui agent·ai前端实战
Rain5092 天前
1.3. Next.js与Nest.js在AI数据分析中的角色
前端·javascript·人工智能·后端·数据分析·node.js·ai编程