Vite 入門篇:學會它,一起提升開發(fā)幸福感
相信大部分兄弟都體驗過 Vite 了,知道它很快。但你知道它為什么快,相比 Webpack 有哪些不同嗎?今天咱們就來全面了解一下 Vite ,尤其適合新手兄弟。一起學起來吧!
什么是構建工具
很多人對構建工具沒有什么概念,只知道是用來打包的。那么到底什么是構建工具呢?
大家都知道瀏覽器只支持 Html、CSS、JavaScript,但一個企業(yè)級項目可能會用到各種各樣的前端技術,如 Less、Sass、TS、Vue組件、語法降級、體積優(yōu)化等,這時候我們就需要相應的工具去處理這些內容:
- 使用 less-loader/sass-loader處理 less / sass。
- 使用 tsc將 typescript 轉換為 javascript。
- 使用 vue-complier將 vue 組件模板轉換為 render 函數(shù)。
- 使用 babel將 es 的新語法轉換為舊版瀏覽器認識的語法。
- 使用 uglifyjs將我們的代碼壓縮成體積更小的文件。
我們可以手動把代碼挨個處理一遍,但這樣效率非常低,當我們稍微修改一點代碼,這個流程又要重新走一遍,非常麻煩。有個神奇的東西,可以把以上工具集成到一起,整個流程交給它自動處理。而且當代碼發(fā)生變化時,自動幫我們重新走一遍,這個東西就叫做構建工具。當然構建工具做的事情遠不止于此,比如:
- 模塊化開發(fā)支持:支持直接從 node_modules 里引入代碼。
- 提高項目性能:壓縮文件、代碼分割。
- 優(yōu)化開發(fā)體驗:熱更新、跨域問題。
- ......
構建工具減輕了我們的心智負擔,讓我們不用關心我們寫的代碼如何在瀏覽器運行,只需要關心代碼怎么寫就可以了。市面上主流的構建工具有 Webpack、Vite、esbuild、Rollup、Parcel,以及最近剛出的 turbopack ,但目前最流行的依然是 Webpack 和 Vite 。
Vite 相較于 Webpack 的優(yōu)勢
當項目體積越來越龐大時,構建工具需要處理的代碼量呈指數(shù)級增長,包含數(shù)千個模塊的項目也是相當普遍。類似 Webpack 的構建工具就會遇到性能瓶頸:通常需要很長時間,甚至幾分鐘項目才能啟動起來。熱更新(HMR)也可能需幾秒,甚至十幾秒。不知道大家目前的項目怎么樣,反正我們公司稍微大一點的 Vue2 項目是真的慢,等的捉急。這種情況已經很大程度影響到了我們的開發(fā)效率和幸福感。
Webpack 有沒有辦法進行優(yōu)化呢?很難。Webpack 先遞歸分析各模塊依賴關系-構建依賴圖譜,然后進行打包,再啟動本地服務器。而且 Webpack 支持多種模塊化規(guī)范,比如 CommonJS 、ES-Module ,一開始就要統(tǒng)一模塊化代碼,將所有的依賴全部處理一遍。整個流程如下圖:
即使使用按需加載,也有一系列工作需要做,所以 Webpack 基本沒有優(yōu)化空間。
那么 Vite 為什么能解決這個問題呢?
- 底層語言。Vite 使用 esbuild預構建依賴。esbuild使用 Go 編寫,比用 JS 編寫的打包器預構建依賴快 10-100 倍。
- 先啟動服務器,再按需請求模塊并編譯。Vite 利用的是現(xiàn)代瀏覽器本身支持 ES-Module這個特性,直接向依賴的模塊發(fā)出請求。Vite 啟動時不需要分析模塊之間的依賴關系,也不用打包,項目越大,優(yōu)勢越明顯。
這個是 Vite 的啟動過程:
這樣大家應該看得出來 Vite 為什么快了吧!
依賴預構建
上面提到了依賴預構建,可能很多兄弟對這個不太理解,這里我也來講一下?,F(xiàn)代瀏覽器已經支持 ES-Module ,但導入模塊只能用相對路徑或絕對路徑,直接使用模塊名稱的方式是行不通的:
依賴預構建就可以很好的解決這個問題。Vite 首先會找到依賴的模塊,然后調用 esbuild,將 CommonJS 等其他規(guī)范的代碼轉換成 ES-Module 規(guī)范,然后把它放在 node_modules/.vite/deps 目錄下,接著再修改相應的引入路徑。
由于瀏覽器是通過 HTTP 來請求模塊文件的,一旦模塊的依賴關系比較多的話,就會發(fā)起很多個網絡請求。例如,lodash-es 內置模塊超過 600 個,它們之前相互導入。當我們執(zhí)行以下代碼時,瀏覽器會同時發(fā)出 600 多個 HTTP 請求!大量的請求造成網絡堵塞,導致頁面的加載非常的慢。
這時候還得靠依賴預構建,預構建將 lodash-es 整體轉換為一個模塊,這樣我們就只需要發(fā)起一個 HTTP 請求了!
總結一下,依賴預構建為我們解決了以下三個頭痛的問題:
- 兼容其他規(guī)范。不同的第三方依賴包會有不同的導出格式(如 CommonJS規(guī)范)。
- 重寫導入路徑。例如 lodash或重寫為/node_modules/.vite/deps/lodash.js?v=fef37e66,以便瀏覽器能夠正確導入。
- 網絡性能優(yōu)化。Vite 會將內部有眾多依賴關系的 ES-Module模塊轉換為一個模塊,提高頁面的加載性能。
對不同內容的處理
學習一項技術,最好的方式是單獨使用它。拋開腳手架工具,Vite 使用起來也非常的簡單,直接在項目中安裝 vite ,給個配置就可以了。當然不給也可以,Vite 會使用內置的默認配置:
為了方便使用,可以在 package.json 添加啟動和打包命令。
然后在根目錄下新建一個 index.html,npm run dev 項目就跑起來了!
對 CSS 的處理
「CSS Modules」
在不同模塊中定義相同類名,會導致樣式被覆蓋,這時候就要用到 CSS module 。以 .module.css 結尾的文件都會被認為是一個 CSS modules 文件。導入這樣的文件會返回一個相應的對象:
「CSS 預處理器」
Vite 同時提供了對 .scss,.sass,.less,.styl 和 .stylus 文件的內置支持,僅需安裝相應的預處理器就可以了:
感覺這塊要比 Webpack 簡單的多,Webpack 需要給不同類型的文件配置不同的 loader 去處理,而 Vite 內部直接幫我們配置好了。如果使用的是 Vue 單文件組件,可以通過 <style lang="less"> 自動開啟。
「PostCSS」
PostCSS 也是用來處理 CSS 的,只不過它更像是一個工具箱,可以添加各種各樣的插件來處理 CSS 。像我們經常遇到的樣式兼容性問題,如高級 CSS 語法的降級、前綴補全等,都可以通過 PostCSS 來解決。
Vite 對 PostCSS 有良好的支持,我們只需安裝需要使用的插件就可以了。
postcss-preset-env 是一個預設環(huán)境插件,包含高級 CSS 語法的降級、前綴補全等眾多功能。接下來我們在 vite.config.js 中配置一下:
然后我們來寫一些特別的樣式:
打開瀏覽器,可以看到 CSS 已經幫我們處理好了:
整體來說 PostCSS 還是非常實用的,可以幫助我們處理各種各樣的 CSS 問題。
對靜態(tài)資源的處理
- 將資源引入為 URL 。默認情況下引入一個靜態(tài)資源,會返回這個資源的 URL 路徑,也就是絕對路徑。
我們可以通過添加后綴的方式,修改文件的引入方式。默認的引入方式等同于添加 ?url 后綴。
- 將資源引入為字符串。使用 ?raw后綴可以將資源作為字符串引入,這個字符串其實就是源文件信息。
- 導入腳本作為 Worker 。JS 腳本可以通過 ?worker或?sharedworker后綴導入為 web worker。
對 JSON 的處理
JSON 文件可以被直接導入。同時也支持具名導入,幫助我們更好地利用 treeshaking :
對 Vue 的處理
Vite 為 Vue 提供第一優(yōu)先級支持,直接使用相應的插件就好了:
- Vue 3 支持:@vitejs/plugin-vue
- Vue 3 JSX 支持:@vitejs/plugin-vue-jsx
- Vue 2.7 支持:@vitejs/vite-plugin-vue2
- Vue <2.7 支持:underfin/vite-plugin-vue2
對 TS 的處理
Vite 天然支持引入 .ts 文件。Vite 使用 esbuild 將 TypeScript 轉譯到 JavaScript,約是 tsc 速度的 20~30 倍,同時 HMR 熱更新也是非常的快 。
Vite 僅執(zhí)行 .ts 文件的轉譯工作,并不執(zhí)行任何類型檢查。換句話來說,即使 IDE 提示報錯,也不影響正常開發(fā)和生成環(huán)境打包。這樣肯定是不行的,不然很難對代碼進行有效約束。我們可以使用插件來實現(xiàn)這個功能:
然后在根目錄創(chuàng)建 tsconfig.json 文件:
這樣 TS 的報錯信息就會在命令行和頁面上顯示出來,不修正就無法繼續(xù)往下開發(fā)啦!
如果要在類型檢查不通過時阻止生產環(huán)境打包,直接在 build 命令中添加一個指令即可:
環(huán)境變量與模式
Vite 和 Webpack 類似,都是使用 dotenv 從特定的文件中加載額外的環(huán)境變量:
在客戶端中我們使用 import.meta.env 獲取環(huán)境變量。為了防止意外地將一些環(huán)境變量泄漏到客戶端,只有以 VITE_ 為前綴的變量才會暴露到客戶端,例如使用以下環(huán)境變量:
客戶端控制臺打印結果:
在服務端,也就是 vite.config.js 中,通過 process.env 獲取環(huán)境變量。但是 vite 考慮到和其他配置的一些沖突問題,Vite 不會將環(huán)境變量直接注入到 process.env 對象下。這時候我們可以手動進行處理:
實際開發(fā)中,我們可能還會用到測試環(huán)境和預發(fā)布環(huán)境,這時候需要創(chuàng)建兩個環(huán)境變量文件:.env.test 和 .env.staging 。
然后在 package.json 中添加一下運行指令就可以了。
生產環(huán)境構建
盡管原生 ES-Module 現(xiàn)在得到了廣泛支持,但由于嵌套導入會導致額外的網絡往返,在生產環(huán)境中發(fā)布未打包的 ES-Module 效率仍然非常低(即使使用 HTTP/2)。為了在生產環(huán)境中獲得最佳的加載性能,更好的利用 tree-shaking、懶加載和 chunk 分割等,Vite 把生產環(huán)境構建全權交給了 Rollup 。
我們可以通過 構建配置選項 自定義構建過程,比如,通過 build.rollupOptions 直接調整底層的 Rollup 選項 ,使用 build.assetsInlineLimit 修改圖片轉 base64 的閾值。
生產環(huán)境中,我們不得不考慮一個問題,就是瀏覽器的兼容性問題。默認情況下,Vite 的目標是支持 原生 ESM script 標簽 、支持原生 ESM 動態(tài)導入 和 import.meta 的現(xiàn)代瀏覽器:
- Chrome >=87
- Firefox >=78
- Safari >=13
- Edge >=88
但我們可以通過 Vite 自帶的 @vitejs/plugin-legacy 插件,來兼容舊版本的瀏覽器。
生產環(huán)境還有很多實用的配置,我就不一一介紹了,大家可以在官網查看。
小結
今天的分享內容比較多,不知道大家吸收的怎么樣。其實 Vite 還是有很多東西可以講的,這次主要是幫助大家對 Vite 有一個整體的了解,后面我會繼續(xù)分享 Vite 配置篇和性能優(yōu)化篇。