為什麼前端不愛用 Webpack 了? Vite 簡介

閱讀時間約 9 分鐘

Vite 是由 Vue 開發者 Evan You 所開發出來,用來加快、優化程式碼打包的工具,在這裡我們不免會需要提到大部分前端開發者可能都會聽過、使用過的前端工具:Webpack。

在那之前,我們先來聊聊為什麼前端會需要所謂的打包工具呢?

在 ES6 釋出前,有一段前端社群大亂鬥的年代,在那段時間沒有所謂「官方的模組化」技術,各家實作前端技術的標準不一,或是當前端有了新的技術,瀏覽器卻沒有支援的窘境,為了要讓開發者所寫的各式各樣程式碼能在瀏覽器端更有效率及更相容地運行,就有了所謂打包工具。

在過往,我們會使用 Webpack 這個工具來打包在正式環境所需要的程式碼,簡單概括 Webpack 的一些機制:

  • Webpack 是一個模組打包工具,用來解決瀏覽器載入程式碼所遇到的一些問題,多框架底層也應用了 webpack,例如:React、Angular 等。
  • Webpack 會透過使用者自定義的進入點來進行打包,這個進入點可以透過引入的方式指向其他模組,在這個過程中,webpack 會依照我們所引入的模組產生相依圖(Dependency Graph),再根據設定檔產出最後的結果,透過定義分割點(split points),webpack 可以將檔案切割成多個塊狀(chunks)。
  • Webpack 支援 ESM、CommonJS、MJS、AMD 等模組,同時也支援 WebAssembly 技術(將 JavaScript 轉譯成 C++ 這種機器語言,優化運行效能的技術)。

Webpack 除了上述的特點外,有幾個為人所詬病的缺點:

  • 打包速度慢
  • 近代的瀏覽器已經支援 ESM 這個原生的模組載入技術,不像一、二十年前瀏覽器實作技術跟不上 ECMA Script 規範,需要將新的語法透過 Babel 搭配 Webpack 轉譯為瀏覽器所看到的語言,不再需要支援舊的語法
  • 配置複雜,學習曲線高
  • 較適合大型的專案,對中小型專案來說有點大材小用

簡而言之,現有的打包技術不敷使用造就了 Vite 的崛起。

快還要再快的 Vite

為了優化 Webpack 的執行速度,Vite 有了以下特色:

  • 使用瀏覽器原生的 ESM 動態加載,去掉過往針對 CommonJS、MJS、AMD 等模組的支援
  • 針對 TypeScript 去掉 Type Check 的過程,交給 IDE(例如:VS code) 工具來解決
  • 將程式碼拆分為相依模組(Dependencies)與 原始碼(Source Code)兩種類型,相依模組為純 JavaScript,像是一些會需要花很多資源處理,但在開發過程中不怎麼會變動內容的 JavaScript 大型函式庫,Vite 透過 esbuild 工具針對這些相依模組進行預先打包(pre-bundle dependencies),這個機制使用 Go 來進行打包,執行速度為 JavaScript-based 打包加快 10-100 倍。
  • 而原始碼為非純 JavaScript 的程式碼,例如:JSX、CSS 或是 Vue 元件等,這類型的程式碼會在開發過程中不斷編輯,但並不會同時載入,所以會使用 route-based 或是 code-spliting 的方式來動態加載這些程式碼。Vite 在這邊會使用原生的 ESM 來載入這些原始碼,在這個部分 Vite 會讓瀏覽器接手原本屬於打包工具的任務,Vite 只需要在瀏覽器針對特定原始碼進行請求時,將原始碼進行轉換及提供程式碼給瀏覽器。Vite 可以把 ESM 本身看作是獨立的 Chunks 進行拆分載入,使用原生瀏覽器的狀況下就能實踐動態載入,降低打包工具在 Build 過程時的時間。Vite 與其他打包工具的差異可以透過下圖簡單了解,透過 Vite 我們可以減少過往開發時,產生新的 Bundle 或是 Chunks 花不少時間等待新的打包檔的產生的過程,除了減少打包過程的時間,Vite 的 HMR 也會基於原生 ESM 的關係比其他打包工具快上不少:
raw-image
raw-image


瀏覽器相容性

由於 Vite 原生的 ESM ,對於支援性較差的瀏覽器來說,以往我們會在使用一些打包工具時,在指定的生命週期使用 Babel 將一些 ES6 以後的語法編譯成相容性較好的程式碼。

不過 Vite 官方提供 @vitejs/plugin-legacy 插件來快速處理瀏覽器相容的問題,可以將這個插件想像成強化版的 Babel 來做使用。

講了那麼多,接著我們就來使用 Vite 快速啟動環境吧:

Vite 安裝流程

Vite 官方要求使用 14.18 以上的 node 版本,因為 Vite 支援多前端框架的模板(vanilla、vue、react、preact、lit、svetle 與其對應的 typeScript 模板),所以在使用較新的前端框架時,可能會需要使用更新版本的 node.js。

  • 使用 NPM:
$ npm create vite@latest
  • 使用 yarn
$ yarn create vite
  • 使用 pnpm
pnpm create vite

接著就會出現一些提示文字,選取你所需要的模板就會獲得你所需要的框架模板,或者是可以使用以下指令獲得指定的版本:

# npm 6.x
$ npm create vite@latest my-react-ts-app --template react-ts

# npm 7+, extra double-dash is needed:
$ npm create vite@latest my-react-ts-app -- --template react-ts

# yarn
$ yarn create vite my-react-ts-app --template react-ts

# pnpm
$ pnpm create vite my-react-ts-app --template react-ts

Vite 指令介面(CLI)

當你安裝好 vite 模板後,可以在 package.json 中看到 vite 預設幫我們寫好的指令介面:

{
"scripts": {
"dev": "vite", // 啟動本地 server
"build": "vite build", // 打包正式環境程式碼
"preview": "vite preview" // 預覽打包好的正式環境程式碼
}
}

如果想要知道有哪一些指令可以使用,可以使用以下指令查詢:

$ npx vite --help

Vite 進階功能介紹

了解了基本的安裝與其爆紅的原因後,來了解一下 Vite 還有一些什麼樣的配置與功能:

NPM 依賴解析和預打包

原生的 ESM 其實並不支援所謂的裸模組(Bare Module import)的引入,舉例來說,下方這種引入模組的方式如果未經處理,直接丟到瀏覽器的話是沒有辦法運行的:

import { someMethod } from 'my-dep'; // bare module import 

如果要使用裸模組來加載模組的話,通常要仰賴第三方的套件或是進行額外的配置才有辦法使用,但 Vite 本身幫我們預先處理好了裸模組配置:

  1. 透過以 Go 為底層的 EsBuild 進行預打包,提前將 CommonJS / UMD 轉為 ESM,提升頁面的載入速度。
  2. 改寫裸模組路徑為絕對路徑,讓瀏覽器看得懂

Hot Module Replacement

Vite 自帶以 ESM 為基礎的 HMR 機制,可以在不重新刷頁面的狀況下,僅載入有被更新的模組,相較於 Webpack 的 HMR ,在開發速度加快不少。

TypeScript

Vite 在 TypeScript 上有一些不一樣的處理方式,由於 TypeScript 是一種靜態的語言,要檢查型別是否正確會是在程式碼在編譯階段時檢查,由於 TypeScript 的型別檢查會需要整體模組圖(module gragh)沒辦法像 ESM 一樣以模組作為單位來檢查,這與 Vite 的設計風格有所衝突。

因此 Vite 不會針對 TypeScript 去做型別的檢查,而是將這個工作交給 IDE 完成,例如:IDE 的 Typescript 檢查插件,或是我們可以透過第三方工具,例如: ESLint,來協助靜態型別的檢查。

不過 Vite 本體本身雖然不支援編譯時的型別檢查,但還是有提供額外的擴充讓開發者依然可以進行型別檢查。

CSS

Vite 支援大部分主流的 CSS 工具,例如:原生 CSS 、PostCSS、CSS modules,也可以額外使用其他預處理器:SASS、SCSS 等,我們可以在 vite.config.js 針對專案的需要進行配置。

  • 原生 CSS:
import "./index.css";

會直接將引入的 CSS 文件內容複製一份,生成 <style> 標籤後丟到 <head> 標籤中,引入幾個檔案就丟幾個 <style> ,因此在不經處理的狀況下原生的 CSS 會有全域污染、覆蓋的問題,所以通常會搭配 CSS Modules 取得獨一無二的選擇器名稱。

SVG 的載入

在 Vite React 專案中,我們可以使用 @vite-plugin-svgr 這個擴充插件,讓我們把 svg 作為一個 React Component 使用,可以透過以下指令安裝這個套件:

  • 使用 NPM:
$ npm i vite-plugin-svgr

在 Vite 設定檔載入這個插件:

// vite.config.js
import svgr from 'vite-plugin-svgr'

export default {
// ...
plugins: [svgr()],
}

就可以透過以下的方式載入 svg 檔囉:

import { ReactComponent as Logo } from './logo.svg'


參考資料:Vitejs


關於我:

一名從英文系畢業的前端工程師,喜歡閱讀、寫東西及自我成長。

|Instagram: Vivian Yeh|vivian_enlife

|聯絡我:[email protected]

為了追求可以窩在座位上、可以心無旁騖思考問題、座位可以亂七八糟沒關係、不需要到處哈腰點頭跑客戶,不用腳踩十公分、連妝都可以不用化的職場人生,文組少女毅然決然踏上RD的養成日常。
留言0
查看全部
發表第一個留言支持創作者!