vite修仙傳4-依賴預(yù)構(gòu)建

依賴預(yù)構(gòu)建?

當(dāng)你首次啟動(dòng) vite 時(shí),Vite 在本地加載你的站點(diǎn)之前預(yù)構(gòu)建了項(xiàng)目依賴。默認(rèn)情況下,它是自動(dòng)且透明地完成的。

原因?

這就是 Vite 執(zhí)行時(shí)所做的“依賴預(yù)構(gòu)建”。這個(gè)過程有兩個(gè)目的:

  1. CommonJS 和 UMD 兼容性: 在開發(fā)階段中,Vite 的開發(fā)服務(wù)器將所有代碼視為原生 ES 模塊。因此,Vite 必須先將以 CommonJS 或 UMD 形式提供的依賴項(xiàng)轉(zhuǎn)換為 ES 模塊。

    在轉(zhuǎn)換 CommonJS 依賴項(xiàng)時(shí),Vite 會(huì)進(jìn)行智能導(dǎo)入分析,這樣即使模塊的導(dǎo)出是動(dòng)態(tài)分配的(例如 React),具名導(dǎo)入(named imports)也能正常工作:

    js

    // 符合預(yù)期
    import React, { useState } from 'react'
    
    
  2. 性能: 為了提高后續(xù)頁(yè)面的加載性能,Vite將那些具有許多內(nèi)部模塊的 ESM 依賴項(xiàng)轉(zhuǎn)換為單個(gè)模塊。

    有些包將它們的 ES 模塊構(gòu)建為許多單獨(dú)的文件,彼此導(dǎo)入。例如,lodash-es 有超過 600 個(gè)內(nèi)置模塊!當(dāng)我們執(zhí)行 import { debounce } from 'lodash-es' 時(shí),瀏覽器同時(shí)發(fā)出 600 多個(gè) HTTP 請(qǐng)求!即使服務(wù)器能夠輕松處理它們,但大量請(qǐng)求會(huì)導(dǎo)致瀏覽器端的網(wǎng)絡(luò)擁塞,使頁(yè)面加載變得明顯緩慢。

    通過將 lodash-es 預(yù)構(gòu)建成單個(gè)模塊,現(xiàn)在我們只需要一個(gè)HTTP請(qǐng)求!

注意

依賴預(yù)構(gòu)建僅適用于開發(fā)模式,并使用 esbuild 將依賴項(xiàng)轉(zhuǎn)換為 ES 模塊。在生產(chǎn)構(gòu)建中,將使用 @rollup/plugin-commonjs。

自動(dòng)依賴搜尋?

如果沒有找到現(xiàn)有的緩存,Vite 會(huì)掃描您的源代碼,并自動(dòng)尋找引入的依賴項(xiàng)(即 "bare import",表示期望從 node_modules 中解析),并將這些依賴項(xiàng)作為預(yù)構(gòu)建的入口點(diǎn)。預(yù)打包使用 esbuild 執(zhí)行,因此通常速度非??臁?/p>

在服務(wù)器已經(jīng)啟動(dòng)后,如果遇到尚未在緩存中的新依賴項(xiàng)導(dǎo)入,則 Vite 將重新運(yùn)行依賴項(xiàng)構(gòu)建過程,并在需要時(shí)重新加載頁(yè)面。

Monorepo 和鏈接依賴?

在一個(gè) monorepo 啟動(dòng)中,該倉(cāng)庫(kù)中的某個(gè)包可能會(huì)成為另一個(gè)包的依賴。Vite 會(huì)自動(dòng)偵測(cè)沒有從 node_modules 解析的依賴項(xiàng),并將鏈接的依賴視為源碼。它不會(huì)嘗試打包被鏈接的依賴,而是會(huì)分析被鏈接依賴的依賴列表。

然而,這需要被鏈接的依賴被導(dǎo)出為 ESM 格式。如果不是,那么你可以在配置里將此依賴添加到 optimizeDeps.includebuild.commonjsOptions.include 這兩項(xiàng)中。

js

export default defineConfig({
  optimizeDeps: {
    include: ['linked-dep'],
  },
  build: {
    commonjsOptions: {
      include: [/linked-dep/, /node_modules/],
    },
  },
})

當(dāng)對(duì)鏈接的依賴進(jìn)行更改時(shí),請(qǐng)使用 --force 命令行選項(xiàng)重新啟動(dòng)開發(fā)服務(wù)器,以使更改生效。

重復(fù)刪除

由于鏈接的依賴項(xiàng)解析方式不同,傳遞依賴項(xiàng)(transitive dependencies)可能會(huì)被錯(cuò)誤地去重,從而在運(yùn)行時(shí)出現(xiàn)問題。如果遇到此問題,請(qǐng)使用 npm pack 命令來(lái)修復(fù)它。

自定義行為?

有時(shí)候默認(rèn)的依賴啟發(fā)式算法(discovery heuristics)可能并不總是理想的。如果您想要明確地包含或排除依賴項(xiàng),可以使用 optimizeDeps 配置項(xiàng) 來(lái)進(jìn)行設(shè)置。

optimizeDeps.includeoptimizeDeps.exclude 的一個(gè)典型使用場(chǎng)景,是當(dāng) Vite 在源碼中無(wú)法直接發(fā)現(xiàn) import 的時(shí)候。例如,import 可能是插件轉(zhuǎn)換的結(jié)果。這意味著 Vite 無(wú)法在初始掃描時(shí)發(fā)現(xiàn) import —— 只能在文件被瀏覽器請(qǐng)求并轉(zhuǎn)換后才能發(fā)現(xiàn)。這將導(dǎo)致服務(wù)器在啟動(dòng)后立即重新打包。

includeexclude 都可以用來(lái)處理這個(gè)問題。如果依賴項(xiàng)很大(包含很多內(nèi)部模塊)或者是 CommonJS,那么你應(yīng)該包含它;如果依賴項(xiàng)很小,并且已經(jīng)是有效的 ESM,則可以排除它,讓瀏覽器直接加載它。

你也可以使用 optimizeDeps.esbuildOptions 選項(xiàng) 來(lái)進(jìn)一步自定義 esbuild。例如,添加一個(gè) esbuild 插件來(lái)處理依賴項(xiàng)中的特殊文件。

緩存?

文件系統(tǒng)緩存?

Vite 將預(yù)構(gòu)建的依賴項(xiàng)緩存到 node_modules/.vite 中。它會(huì)基于以下幾個(gè)來(lái)源來(lái)決定是否需要重新運(yùn)行預(yù)構(gòu)建步驟:

  • 包管理器的鎖文件內(nèi)容,例如 package-lock.json,yarn.lockpnpm-lock.yaml,或者 bun.lockb
  • 補(bǔ)丁文件夾的修改時(shí)間;
  • vite.config.js 中的相關(guān)字段;
  • NODE_ENV 的值。

只有在上述其中一項(xiàng)發(fā)生更改時(shí),才需要重新運(yùn)行預(yù)構(gòu)建。

如果出于某些原因你想要強(qiáng)制 Vite 重新構(gòu)建依賴項(xiàng),你可以在啟動(dòng)開發(fā)服務(wù)器時(shí)指定 --force 選項(xiàng),或手動(dòng)刪除 node_modules/.vite 緩存目錄。

瀏覽器緩存?

已預(yù)構(gòu)建的依賴請(qǐng)求使用 HTTP 頭 max-age=31536000, immutable 進(jìn)行強(qiáng)緩存,以提高開發(fā)期間頁(yè)面重新加載的性能。一旦被緩存,這些請(qǐng)求將永遠(yuǎn)不會(huì)再次訪問開發(fā)服務(wù)器。如果安裝了不同版本的依賴項(xiàng)(這反映在包管理器的 lockfile 中),則會(huì)通過附加版本查詢自動(dòng)失效。如果你想通過本地編輯來(lái)調(diào)試依賴項(xiàng),您可以:

  1. 通過瀏覽器開發(fā)工具的 Network 選項(xiàng)卡暫時(shí)禁用緩存;
  2. 重啟 Vite 開發(fā)服務(wù)器指定 --force 選項(xiàng),來(lái)重新構(gòu)建依賴項(xiàng);
  3. 重新載入頁(yè)面。
?著作權(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),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

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

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