依賴(lài)預(yù)構(gòu)建

依賴(lài)預(yù)構(gòu)建是什么?

一句話(huà)總結(jié):在你首次使用 Vite 啟動(dòng)項(xiàng)目的時(shí)候,會(huì)把你的項(xiàng)目依賴(lài)預(yù)先構(gòu)建一次。

思考??:前面不是說(shuō) Vite 相比 Webpack 的優(yōu)點(diǎn)不就是不打包么?這里預(yù)構(gòu)建又是怎么一回事兒?
實(shí)際上,預(yù)構(gòu)建和打包是并不沖突的,vite的工作原理:利用現(xiàn)代瀏覽器對(duì)es模塊的支持,來(lái)避免傳統(tǒng)的打包過(guò)程,直接通過(guò)瀏覽器發(fā)送的http請(qǐng)求,動(dòng)態(tài)的去加載所請(qǐng)求的模塊。

vite存在的問(wèn)題:

  1. 依賴(lài)文件過(guò)多,導(dǎo)致請(qǐng)求過(guò)多
  2. 某些第三方包仍然是以 CommonJS 格式發(fā)布的,它們并不兼容原生 ESM 環(huán)境

為了解決上面的兩個(gè)問(wèn)題,Vite在第一次啟動(dòng)項(xiàng)目的時(shí)候,會(huì)針對(duì) 依賴(lài) 進(jìn)行一個(gè)預(yù)構(gòu)建(打包)

預(yù)構(gòu)建階段所使用的打包工具是 esbuild,這是一個(gè)用 Go 語(yǔ)言編寫(xiě)的構(gòu)建工具,效率極高,大部分工作都是并行處理的,esbuild 能夠迅速將依賴(lài)轉(zhuǎn)換為有效的 ES 模塊格式,并進(jìn)行打包,從而優(yōu)化依賴(lài)管理和加載效率。

esbuild 所做的事情:

  1. 轉(zhuǎn)換:將一些 CommonJS、UMD 格式的模塊轉(zhuǎn)換為 ES 模塊的格式。
  2. 打包:針對(duì)依賴(lài)進(jìn)行打包,減少瀏覽器在開(kāi)發(fā)環(huán)境的請(qǐng)求次數(shù)。
  3. 最小化和壓縮:這個(gè)是在構(gòu)建階段,針對(duì)代碼的最小化和壓縮也是 esbuild 來(lái)做的。
  4. 編譯:將代碼轉(zhuǎn)換成 ES 模塊格式。

另外,esbuild還支持增量編譯,即:當(dāng)文件內(nèi)容發(fā)生變化的時(shí)候,esbuild會(huì)只編譯發(fā)生變化的部分,而不是去編譯整個(gè)項(xiàng)目,進(jìn)一步提升了開(kāi)發(fā)時(shí)的構(gòu)建速度和響應(yīng)時(shí)間

緩存
esbuild會(huì)針對(duì)預(yù)構(gòu)建的產(chǎn)物進(jìn)行緩存

緩存分為兩種:

  1. 文件緩存
  2. 瀏覽器緩存

針對(duì)依賴(lài)項(xiàng)做構(gòu)建后,會(huì)將構(gòu)建產(chǎn)物做緩存,緩存到 node_modules/.vite 目錄下面。

什么時(shí)候需要重新運(yùn)行預(yù)構(gòu)建步驟:

  • 包管理器的鎖文件內(nèi)容,例如 package-lock.json,yarn.lock,pnpm-lock.yaml,或者 bun.lockb 發(fā)生了變化(鎖文件一般記錄的都是依賴(lài)性項(xiàng)的精確地版本)
  • 補(bǔ)丁文件夾的修改時(shí)間發(fā)生了變化
  • vite.config.js 中的相關(guān)字段發(fā)生了變化,在配置文件中也存在依賴(lài)預(yù)構(gòu)建的相關(guān)配置,依賴(lài)預(yù)構(gòu)建相關(guān)配置發(fā)生了變化,自然需要重新預(yù)構(gòu)建。
  • NODE_ENV 的值變動(dòng)(NODE_ENV指定環(huán)境變量,開(kāi)發(fā)環(huán)境或者生產(chǎn)環(huán)境)

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

另外,已預(yù)構(gòu)建的依賴(lài),在瀏覽器端也會(huì)存在緩存。會(huì)使用 HTTP 頭 max-age=31536000, immutable 進(jìn)行強(qiáng)緩存,以提高開(kāi)發(fā)期間頁(yè)面重新加載的性能。一旦被緩存,這些請(qǐng)求將永遠(yuǎn)不會(huì)再次訪(fǎng)問(wèn)開(kāi)發(fā)服務(wù)器。

如果安裝了不同版本的依賴(lài)項(xiàng)(這反映在包管理器的 lockfile 中),則會(huì)通過(guò)附加版本查詢(xún)把之前的強(qiáng)緩存自動(dòng)失效。

例如:當(dāng)前項(xiàng)目使用了 lodash,版本為 4.17.19

http://localhost:3000/node_modules/.vite/lodash.js?v=4.17.19

之后對(duì) lodash 版本升級(jí),升級(jí)到 4.17.20,鎖文件內(nèi)容變化會(huì)導(dǎo)致重新預(yù)構(gòu)建

http://localhost:3000/node_modules/.vite/lodash.js?v=4.17.20

URL發(fā)生變化后,瀏覽器就會(huì)發(fā)送新的請(qǐng)求到開(kāi)發(fā)服務(wù)器,而不再使用舊的緩存。

自定義預(yù)構(gòu)建行為

在配置文件中,通過(guò) optimizeDeps 對(duì)預(yù)構(gòu)建行為進(jìn)行配置。一個(gè)基本的格式:

// vite.config.js
import { defineConfig } from 'vite';

export default defineConfig({
  optimizeDeps: {
    // 其他的配置
  }
});

1. entries

默認(rèn)情況下,Vite 會(huì)抓取 index.html 來(lái)檢測(cè)需要預(yù)構(gòu)建的依賴(lài)項(xiàng)(忽略node_modules、build.outDir、_tests_ 和 coverage)。如果指定了 build.rollupOptions.input,Vite 將轉(zhuǎn)而去抓取這些入口點(diǎn)。

如果這兩者都不合意,則可以使用 entries 選項(xiàng)指定自定義條目,在 Vite 中明確指定應(yīng)當(dāng)被預(yù)構(gòu)建的依賴(lài)入口

示例 1:基本用法

my-project/
├── src/
│   ├── main.js         // 主入口文件
│   ├── admin.js        // 管理員入口文件
│   └── vendor/
│       └── custom.js   // 自定義庫(kù)
├── index.html
└── vite.config.js

配置如下:

// vite.config.js
import { defineConfig } from 'vite';

export default defineConfig({
  optimizeDeps: {
    entries: ['src/main.js', 'src/admin.js']  // 顯式指定入口文件
  }
});

示例 2:使用 glob 模式

// vite.config.js
import { defineConfig } from 'vite';

export default defineConfig({
  optimizeDeps: {
    // vite會(huì)掃描src目錄下面的所有的.js文件,之后會(huì)將這些文件引用的依賴(lài)做一個(gè)預(yù)構(gòu)建處理
    entries: ['src/**/*.js']  // 使用 glob 模式匹配所有 JS 文件
  }
});

示例 3:忽略特定目錄

// vite.config.js
import { defineConfig } from 'vite';

export default defineConfig({
  optimizeDeps: {
    entries: [
      'src/**/*.js',              // 匹配所有 JS 文件
      '!src/experimental/**/*.js' // 但忽略 experimental 目錄
    ]
  }
});

2. include和exclude

include用于包含某個(gè)包,exclude用于排除某個(gè)包。

默認(rèn)情況下,預(yù)構(gòu)建主要是針對(duì)依賴(lài),也就是 node_modules 下面的包。

export default defineConfig({
  optimizeDeps: {
    include: ['my-lib/components/**/*.vue'],
  },
})

3. esbuildOptions

Vite 使用 esbuild 來(lái)預(yù)構(gòu)建項(xiàng)目依賴(lài),以提高開(kāi)發(fā)服務(wù)器的啟動(dòng)速度和整體構(gòu)建性能。

在大多數(shù)情況下,Vite 的默認(rèn)設(shè)置已經(jīng)足夠高效。然而,有時(shí)可能需要對(duì) esbuild 的行為進(jìn)行特定的調(diào)整,例如,更改源映射生成、定義宏替換等,以適應(yīng)特定的項(xiàng)目需求或解決兼容性問(wèn)題。

示例 1:自定義源映射

// vite.config.js
import { defineConfig } from 'vite';

export default defineConfig({
  optimizeDeps: {
    esbuildOptions: {
      sourcemap: 'inline'  // 將源映射直接嵌入到輸出文件中
    }
  }
});

示例 2:使用宏替換

// vite.config.js
import { defineConfig } from 'vite';

export default defineConfig({
  optimizeDeps: {
    esbuildOptions: {
      define: {
        'process.env.NODE_ENV': '"production"',
        '__VERSION__': '"1.0.0"'
      }
    }
  }
});

示例 3:調(diào)整目標(biāo) JavaScript 版本

// vite.config.js
import { defineConfig } from 'vite';

export default defineConfig({
  optimizeDeps: {
    esbuildOptions: {
      // esbuild在對(duì)依賴(lài)進(jìn)行預(yù)構(gòu)建的時(shí)候,會(huì)將其編譯為ES2015兼容的代碼
      target: 'es2015'
    }
  }
});

4. force

設(shè)置為 true 可以強(qiáng)制依賴(lài)預(yù)構(gòu)建,而忽略之前已經(jīng)緩存過(guò)的、已經(jīng)優(yōu)化過(guò)的依賴(lài)。

?著作權(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)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

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

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