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

相关推荐
垣宇16 小时前
Vite 和 Webpack 的区别和选择
前端·webpack·node.js
爱吃南瓜的北瓜17 小时前
npm install 卡在“sill idealTree buildDeps“
前端·npm·node.js
翻滚吧键盘17 小时前
npm使用了代理,但是代理软件已经关闭导致创建失败
前端·npm·node.js
浪九天18 小时前
node.js的版本管理
node.js
浪九天20 小时前
node.js的常用指令
node.js
浪九天1 天前
Vue 不同大版本与 Node.js 版本匹配的详细参数
前端·vue.js·node.js
小纯洁w1 天前
Webpack 的 require.context 和 Vite 的 import.meta.glob 的详细介绍和使用
前端·webpack·node.js
熬夜不洗澡1 天前
Node.js中不支持require和import两种导入模块的混用
node.js
bubusa~>_<1 天前
解决npm install 出现error,比如:ERR_SSL_CIPHER_OPERATION_FAILED
前端·npm·node.js
天下皆白_唯我独黑2 天前
npm 安装扩展遇到证书失效解决方案
前端·npm·node.js