美文网首页
《vite技术揭秘、还原与实战》第4节--加载index.htm

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

作者: 习惯水文的前端苏 | 来源:发表于2024-01-07 10:56 被阅读0次

    前言

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

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

    源码获取

    传送门

    更新进度

    公众号:更新至第9

    博客:更新至第4

    源码分析

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

    // packages/vite/src/node/server/index.ts
    
    const middlewares = connect() as Connect.Server
    ...
    const { createServer } = await import('node:http')
    createServer(middlewares)
    

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

    middlewares.use(htmlFallbackMiddleware(root, true));
    

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

    // 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,它应该返回一个函数

    export function htmlFallbackMiddleware(): Connect.NextHandleFunction {
      return function viteHtmlFallbackMiddleware(req, res, next) {};
    }
    

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

    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到下一个中间件`即可

    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可以被正常渲染

    image.png

    总结

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

    相关文章

      网友评论

          本文标题:《vite技术揭秘、还原与实战》第4节--加载index.htm

          本文链接:https://www.haomeiwen.com/subject/aoegndtx.html