前言
上一小節(jié),我們發(fā)現(xiàn)直接引入defineConfig會(huì)導(dǎo)致程序報(bào)錯(cuò),于是分析了產(chǎn)生報(bào)錯(cuò)的原因并查看了vite中的解決思路
本節(jié),在svite中解決這個(gè)問題
好文推薦
源碼獲取
更新進(jìn)度
公眾號(hào):更新至第18節(jié)
博客:更新至第7節(jié)
代碼實(shí)現(xiàn)
結(jié)合上一節(jié)分析,我們知道問題出在buildBoundle函數(shù)中,并且我們已經(jīng)知道了通過esbuild plugin的onResolve鉤子可以解決這個(gè)問題
如下,第一步我們需要對(duì)一些條件進(jìn)行守衛(wèi):入口點(diǎn)本身、絕對(duì)路徑、node內(nèi)置模塊
// 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:導(dǎo)入的依賴地址,如import xxx from 'svite'語句中指的是svite
// importer:當(dāng)前正在處理的文件地址,如svite所在的文件地址為playground\config\svite.config.ts
// kind:導(dǎo)入的類型,如entry-point表示導(dǎo)入入口點(diǎn);entry-point表示導(dǎo)入依賴
if (kind === "entry-point" || isAbsolute(id) || isBuiltin(id)) {
return;
}
return {
path:analizePathValue(id,importer,kind),
external:true
}
})
}
}]
});
const { text } = result.outputFiles[0];
return text;
}
當(dāng)程序通過if守衛(wèi)條件后,則說明命中了裸依賴,在我們的svite.config.ts文件中即指命中了svite。此時(shí)通過將鉤子返回的對(duì)象的external設(shè)置為true從而將依賴從boundle中排除則能有效避免上一小節(jié)中我們遇到的報(bào)錯(cuò)問題:Dynamic require of "fs" is not supported
由于我們跳過了svite的處理,則最終代碼里將無法找到defineConfig而引發(fā)報(bào)錯(cuò),為了解決這個(gè)問題,我們要將導(dǎo)入的路徑替換為絕對(duì)路徑,這樣node就能正確加載啦
因此我們的關(guān)鍵點(diǎn)就是去生成path的值來對(duì)引入模塊路徑做替換,即analizePathValue是如何實(shí)現(xiàn)的
function analizePathValue(id: string, importer: string, kind: string) {
...
}
想要實(shí)現(xiàn)這一點(diǎn),我們需要從包的元數(shù)據(jù)中找相關(guān)的定義,即packages\vite\package.json中與模塊引入相關(guān)的字段
{
"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文件并對(duì)導(dǎo)出字段做比對(duì)的,且針對(duì)svite/xxx的形式也需要做額外的兼容處理。這里我們借助local-pkg來達(dá)到同樣的目的
pnpm i local-pkg
該包提供的resolveModule函數(shù)會(huì)自動(dòng)幫我們完成路徑的識(shí)別和轉(zhuǎn)換工作,當(dāng)然,我們要先判斷對(duì)應(yīng)的依賴包是否存在,當(dāng)獲取到路徑之后,還需要通過node內(nèi)置的pathToFileURL將其轉(zhuǎn)換為URL路徑
if (isPackageExists(id)) {
const fileUrl = resolveModule(id);
if (fileUrl) {
return pathToFileURL(fileUrl).href;
}
}
如果你是跟著筆者一起實(shí)現(xiàn)的話,當(dāng)你運(yùn)行的時(shí)候,你會(huì)得到如下的錯(cuò)誤
Error [ERR_PACKAGE_PATH_NOT_EXPORTED]: No "exports" main defined in C:\Users\11574\Desktop\git\mini-vite\node_modules\svite\package.json
這是因?yàn)?code>resolveModule本質(zhì)上是cjs的導(dǎo)入方式,而我們一開始在創(chuàng)建項(xiàng)目時(shí)缺少了對(duì)require的支持,為因此,需要找到packages\vite\package.json文件的exports并增加如下代碼
{
"exports": {
".": {
...
"require":"./dist/node/index.js"
}
},
}
設(shè)置好后,再次啟動(dòng),程序正常運(yùn)行即可
總結(jié)
本小節(jié),依據(jù)上一節(jié)的分析思路解決了svite中引入ts輔助函數(shù)的報(bào)錯(cuò)問題,其實(shí)就是在打包處理該配置文件時(shí)將引入排除就可以了