《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辅助函数的报错问题,其实就是在打包处理该配置文件时将引入排除就可以了

相关推荐
景天科技苑16 小时前
【vue3+vite】新一代vue脚手架工具vite,助力前端开发更快捷更高效
前端·javascript·vue.js·vite·vue项目·脚手架工具
niech_cn3 天前
vite + vue3 + ts解决别名引用@/api/user报错找不到相应的模块
vite
Amd7944 天前
Nuxt.js 应用中的 vite:compiled 事件钩子
自定义·vite·编译·nuxt·热更新·性能·钩子
黑色的糖果5 天前
npm上传自己封装的插件(vue+vite)
前端·vue.js·npm·vite
软件小伟5 天前
Vite是什么?Vite如何使用?相比于Vue CLI的区别是什么?(一篇文章帮你搞定!)
前端·vue.js·ecmascript·vite·vue vli
Amd7945 天前
Nuxt.js 应用中的 vite:serverCreated 事件钩子
中间件·开发·vite·日志·nuxt·跨域·钩子
亦世凡华、6 天前
React--》如何高效管理前端环境变量:开发与生产环境配置详解
react·vite·环境变量·env·env配置
19组清风6 天前
对于模块动态加载,Vite 内部做了哪些优化
前端·vite·前端工程化
Amd7946 天前
Nuxt.js 应用中的 vite:configResolved 事件钩子
vite·配置·nuxt·构建·钩子·动态·调整