《vite技术揭秘、还原与实战》第7节--在svite中引入defineConfig类型辅助函数

前言

上一小节,我们发现直接引入defineConfig会导致程序报错,于是分析了产生报错的原因并查看了vite中的解决思路

本节,在svite中解决这个问题

好文推荐

源码获取

传送门

更新进度

公众号:更新至第17

博客:更新至第7

代码实现

结合上一节分析,我们知道问题出在buildBoundle函数中,并且我们已经知道了通过esbuild pluginonResolve钩子可以解决这个问题

如下,第一步我们需要对一些条件进行守卫:入口点本身、绝对路径、node内置模块

ts 复制代码
// packages\vite\src\node\config.ts
async function buildBoundle(fileName: string) {
  const result = await build({
    ...
    plugins:[{
      name: 'externalize-deps',
      setup(build) {
        build.onResolve({filter:/^[^.].*/},async ({path:id,importer,kind})=>{
            // id:导入的依赖地址,如import xxx from 'svite'语句中指的是svite
            // importer:当前正在处理的文件地址,如svite所在的文件地址为playground\config\svite.config.ts
            // kind:导入的类型,如entry-point表示导入入口点;entry-point表示导入依赖
            if (kind === "entry-point" || isAbsolute(id) || isBuiltin(id)) {
                return;
            }
            return {
                path:analizePathValue(id,importer,kind),
                external:true
            }
        })
      }
    }]
  });
  const { text } = result.outputFiles[0];
  return text;
}

当程序通过if守卫条件后,则说明命中了裸依赖,在我们的svite.config.ts文件中即指命中了svite。此时通过将钩子返回的对象的external设置为true从而将依赖从boundle中排除则能有效避免上一小节中我们遇到的报错问题:Dynamic require of "fs" is not supported

由于我们跳过了svite的处理,则最终代码里将无法找到defineConfig而引发报错,为了解决这个问题,我们要将导入的路径替换为绝对路径,这样node就能正确加载啦

因此我们的关键点就是去生成path的值来对引入模块路径做替换,即analizePathValue是如何实现的

ts 复制代码
function analizePathValue(id: string, importer: string, kind: string) {
  ...
}

想要实现这一点,我们需要从包的元数据中找相关的定义,即packages\vite\package.json中与模块引入相关的字段

json 复制代码
{
  "main": "./dist/node/index.js",
  "types": "./dist/node/index.d.ts",
  "exports": {
    ".": {
      "types": "./dist/node/index.d.ts",
      "import": "./dist/node/index.js"
    }
  }
}

vite中是自己去读取该json文件并对导出字段做比对的,且针对svite/xxx的形式也需要做额外的兼容处理。这里我们借助local-pkg来达到同样的目的

js 复制代码
pnpm i local-pkg

该包提供的resolveModule函数会自动帮我们完成路径的识别和转换工作,当然,我们要先判断对应的依赖包是否存在,当获取到路径之后,还需要通过node内置的pathToFileURL将其转换为URL路径

ts 复制代码
if (isPackageExists(id)) {
  const fileUrl = resolveModule(id);
  if (fileUrl) {
    return pathToFileURL(fileUrl).href;
  }
}

如果你是跟着笔者一起实现的话,当你运行的时候,你会得到如下的错误

txt 复制代码
Error [ERR_PACKAGE_PATH_NOT_EXPORTED]: No "exports" main defined in C:\Users\11574\Desktop\git\mini-vite\node_modules\svite\package.json

这是因为resolveModule本质上是cjs的导入方式,而我们一开始在创建项目时缺少了对require的支持,为因此,需要找到packages\vite\package.json文件的exports并增加如下代码

json 复制代码
{
  "exports": {
    ".": {
      ...
      "require":"./dist/node/index.js"
    }
  },
}

设置好后,再次启动,程序正常运行即可

总结

本小节,依据上一节的分析思路解决了svite中引入ts辅助函数的报错问题,其实就是在打包处理该配置文件时将引入排除就可以了

相关推荐
用户9714171814273 天前
前端开发中的跨域问题:Vite 开发环境配置指南
vue.js·vite
kuromiluu3 天前
从原理到实践:Vite
vite
菜市口的跳脚长颌5 天前
一个 Vite 打包配置,引发的问题—— global: 'globalThis'
前端·vue.js·vite
苏卫苏卫苏卫8 天前
【码源】智能无人仓库管理系统(详细码源下~基于React+TypeScript+Vite):
前端·react.js·typescript·vite·项目设计·智能无人仓库管理系统·码源
前端赵哈哈12 天前
Vite 构建后产品详情页图片失效?从路径匹配到映射表的完美解决
前端·vue.js·vite
念念不忘 必有回响12 天前
nginx前端部署与Vite环境变量配置指南
前端·nginx·vite
我爱甜妹16 天前
vite项目保存代码后不刷新页面 vite热更新
vite
jason_yang16 天前
vue3+element-plus按需自动导入-正确姿势
vue.js·vite·element
WujieLi18 天前
初识 Vite+:一文了解 Rust 驱动的新一代前端工具链
javascript·rust·vite
却尘19 天前
Vite 炸裂快,Webpack 稳如山,Turbopack 想两头要:谁才是下一个王?
前端·面试·vite