快如閃電的vite

或許你曾經有過這樣的經驗,專案採用 webpack 開發,一開始 bundle 的速度還算快,但時間一久,隨著專案的增長,套件的相依關係變得越來越冗長,能明顯感受到 webpack bundle 速度越來越緩慢,改了一個小地方卻要等上好幾秒才能看到網頁畫面更新,而 vite 就是為了解決這個問題而誕生的! vite 採用 ES Module 的方式,不需要提前做 bundle,讓瀏覽器發出 request 來跟 dev server 請求需要的 module,因此即使 dependency(第三方套件)變多,vite 的熱更新也不會有延遲的問題,啟動的速度也是輾壓 webpack

甚麼是 bundle?

將專案中所有的 module(模組)編譯成一隻 JavaScript 檔案

webpack 必須將全部有相依關係的 module 先處理過一次,bundle 好之後再由瀏覽器載入 js,如下圖的 main.js,因此要等上一段時間才能看到畫面更新


而 vite 是利用 ES Module 來載入套件,所以會有很多 request 依序加載,也就是把載入 module 的工作丟給瀏覽器來處理


除了 ES Module,esbuild 也是讓 vite 提升速度的一大功臣,esbuild 會將第三方套件預先構建好(Dependency Pre-Bundling),將 Dependency 整合在同一個 module,減少網路的 request,另外,vite dev server 會將所有的 module 視作 ES module,因此套件格式為 CommonJS 或是 UMD 的,esbuild 會統一轉成 ES Modules 的格式

為甚麼可以這麼快?

Vite 将会使用 esbuild 预构建依赖esbuild 使用 Go 编写,并且比以 JavaScript 编写的打包器预构建依赖快 10–100 倍。(引用自 vite 官網)

看看 esbuild 這鬼神一般的速度…

變快真的很有感?

以一個全新的專案來說,採用的前端框架如果為 vue 的感受比較細微,使用 vue cli(webpack)和 vite 所建立的專案,兩者跑 dev server 的速度差異不大,但 React 就很有感了,以近期開發的 React 專案來說,剛開始是用 create-React-app (webpack)建立的,光一個空白專案的 bundle 速度就非常慢,最後慢到大家都受不了,因此決定改用 vite,雖然那時也是左思右想,擔心 vite 還不夠穩定,不過想說剛出的 vite 2.0 版本,有做大幅度的優化,就大膽的用在工作上的專案了(很小很小的專案),習慣 vite 之後,再回去使用 webpack 會很不習慣那個速度 😂,這裡有個比較速度的影片我覺得很有趣,分享給大家

關於 vite 打包

vite 採用 rollup 進行打包,不過這邊的行為模式就跟 webpack 相差無幾了,為甚麼 vite 還是需要經過打包,不能像開發模式那樣靠瀏覽器載入需要的模組呢?

  1. 因為發佈的程式碼是放在伺服器上,每個使用者打開網頁都會發出好幾個請求,伺服器的負擔會大大增加,這肯定行不通
  2. 上線版本還是需要對程式碼做一些優化處理,例如 lazy load、tree-shaking 等等

vite 起來!

接下來實際來體驗 vite 有多快吧!要注意的是,vite 需要的 node 版本必須大於 12.0.0,如果版本太低要先記得升級,因為我習慣用 yarn,所以使用 yarn 來安裝 vite ,也可以用 npm 或是 pnpm 安裝

1
$ yarn create vite

執行完上述指令,就會詢問專案名稱以及要使用的框架為何,vite 不只支援 vue,react、svelte 等等的前端框架都可以,可說是海納百川 😂,這邊先選擇 React


選好框架後,會詢問是否要建立 typeScript 版本,這裡先選擇一般版本,選好版本後專案以迅雷不及掩耳的速度建立完成

執行 yarn dev 會發現 dev server 馬上就起好了,修改檔案也是一存檔,就跟著熱更新(HMR)

假設有 a, b, c 三個模組,只有 c 模組更新,那麼只會重新編譯 c,a 和 b 直接從快取拿編譯結果,就不需要全部的模組都重新編譯,這就是為甚麼 vite 的熱更新並不會因為套件變多而變慢

專案建好之後,可以在根目錄底下看到 vite.config.js

我們可以在 vite.config.js 撰寫打包相關設定

接下來會介紹個人常使用到的 vite 設定

plugins

要引入的套件 import 完之後,必須寫在 plugins 的陣列裡

讀取 env 的變數

在 webpack 中,我們只要寫上 process.env.xxx 就能取到我們要的環境變數,但是在 vite.config.js 中,這樣寫是取不到值的,必須額外引入 loadEnv 這個套件,export default 改為一個 return defineConfig 的函式,並且傳入 mode 參數

設置別名

dev server 相關設定

假設 port 不想用預設的 3000,則可以設定成其他的 port

複製檔案並且移動到指定位置

將檔案複製到指定資料夾並且更換檔名,設定 hook 可以更改複製的時機

全域引入 scss 變數

可以全域引入多個 scss,這樣就不需要每個檔案都引入 scss 變數了

打包時檔案分類

vite 打包的時候 js、 css、素材都會在同一個資料夾底下,雖然不影響功能運作,但是看起來不夠清爽,假設要像之前 webpack 打包那樣將檔案依類型分類就可以這樣設定

套件大小分析工具(rollup-plugin-visualizer)

專案上線後發現網頁載入速度過慢,就需要幫 js 瘦身,因此需要工具來幫我們分析套件的大小,每次打包會生成 stats.html,打開 stats.html,哪個套件最肥一目了然


不過說實話我個人還是比較喜歡 webpack 的套件分析工具就是了 😂

跳槽 vite 之前有哪些顧慮?

  1. 支援度 —  舊瀏覽器的支援度一直都是都是讓人頭疼的問題,那些不支援 ES Modules 的瀏覽器該怎麼辦呢  ? 可以透過 @vitejs/plugin-legacy 套件來處理相容性的問題,不過為了因為多了向下相容的程式碼,所以打包出來的檔案會變蠻大的
  2. 套件的豐富度 — vite 可以相容 rollup 現有的套件,雖然數量不如 webpack 那麼多,不過也是綽綽有餘了
  3. 穩定度 —我想這應該是所有人對 vite 最有疑慮的一點了,不得不說 vite 目前還是有蠻多 bug 的,我用 vite 開發的時候的確也遇到不少問題,所以如果要用在工作的專案的話,必須在開發效率和穩定度之間做出取捨

從 webpack 跳過來 vite 要習慣甚麼?

假設要在 env 檔裡面設置環境變數,記得變數名稱要是 VITE(大寫)開頭,不然就會被忽略 ex. VITE_APP_HOST,以 vue cli 來說,假如要在.vue 檔或是.js 檔中讀取環境變數會是用 process.env.VUE_APP_HOST,而在 vite 裡面就會變成 import.meta.env.VITE_APP_HOST

結論

在這個分秒必爭的時代,vite 有效的提升了開發的效率,不是一點點,而是非常有感的提升,也難怪 vite 的 slogan 會寫著 Next Generation Fronted Tooling,如果你從未用過 vite,非常推薦你玩看看,至於要不要用在工作的專案上,大部分的人還是持保留態度,畢竟 vite 還很年輕,穩定度一定不比行之有年的 webpack,究竟 vite 能否會取代 webpack 成為下個世代的前端開發工具呢  ? 這部分就留給時間去做驗證了

參考資料

Vite 官網

Vite 怎麼能那麼快?從 ES modules 開始談起