《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属性时发起相应的请求

相关推荐
Stream_Silver2 天前
【Node.js 安装报错解决方案:解决“A later version of Node.js is already installed”问题】
node.js
Anthony_2312 天前
基于 Vue3 + Node.js 的实时可视化监控系统实现
node.js
说给风听.2 天前
解决 Node.js 版本冲突:Windows 系统 nvm 安装与使用全指南
windows·node.js
森叶2 天前
Node.js 跨进程通信(IPC)深度进阶:从“杀人”的 kill 到真正的信号
node.js·编辑器·vim
虹科网络安全3 天前
艾体宝新闻 | NPM 生态系统陷入困境:自我传播恶意软件在大规模供应链攻击中感染了 187 个软件包
前端·npm·node.js
摇滚侠3 天前
PNPM 包管理工具和 NPM 包管理工具
vscode·npm·node.js·pnpm
心柠3 天前
webpack
前端·webpack·node.js
FreeBuf_3 天前
vm2 Node.js库曝严重沙箱逃逸漏洞(CVE-2026-22709)可导致任意代码执行
node.js
147API3 天前
改名后的24小时:npm 包抢注如何劫持开源项目供应链
前端·npm·node.js
抵梦3 天前
NPM、CNPM、PNPM:Node.js 依赖工具对比与选择
前端·npm·node.js