前言
上一小节,我们发现直接引入defineConfig
会导致程序报错,于是分析了产生报错的原因并查看了vite
中的解决思路
本节,在svite
中解决这个问题
好文推荐
源码获取
更新进度
公众号:更新至第17
节
博客:更新至第7
节
代码实现
结合上一节分析,我们知道问题出在buildBoundle
函数中,并且我们已经知道了通过esbuild plugin
的onResolve
钩子可以解决这个问题
如下,第一步我们需要对一些条件进行守卫:入口点本身、绝对路径、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
辅助函数的报错问题,其实就是在打包处理该配置文件时将引入排除就可以了