《vite技術(shù)揭秘、還原與實(shí)戰(zhàn)》第7節(jié)--在svite中引入defineConfig類型輔助函數(shù)

前言

上一小節(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 pluginonResolve鉤子可以解決這個(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í)將引入排除就可以了

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容