在現代 JavaScript 的動態特性中,必須牢記 “舊” 並不一定意味著 “過時”,而 “新” 也不一定意味著 “更好”。
選擇正確技術的關鍵在於它是否符合您的專案需求。在考慮 JavaScript 模組打包程式時,這一原則引起了強烈反響。無論打包工具是經受了時間的考驗,還是剛剛問世,每種打包工具都有其獨特的優勢和侷限性。
本文將探討兩個重要的流行工具:Vite 和 Webpack。我們將根據這些打包工具的功能、區別、架構理念以及它們如何整合到開發人員生態系統中進行評估。
什麼是 JavaScript 模組打包程式?
JavaScript 打包
JavaScript 打包程式是網路開發中使用的一種工具,用於將多個 JavaScript 檔案合併為一個檔案,即打包檔案。它通過減少網路應用程式所需的請求次數來簡化 JavaScript 程式碼的管理,最終提高效能。
例如,假設有兩個獨立的 JavaScript 檔案:module1.js 和 module2.js。module1.js 包含以下內容:
// module1.js export const greet = (name) => { console.log(`Hello, ${name}!`); }
而 module2.js 包含:
// module2.js export const farewell = (name) => { console.log(`Goodbye, ${name}!`); }
要將這些模組打包到一個檔案中,可以使用 Rollup、Webpack 或 Parcel 等打包工具。例如,在專案目錄下建立一個 index.js 檔案,程式碼如下:
// index.js import { greet } from './module1.js'; import { farewell } from './module2.js'; greet('Wbolt'); farewell('Server Troubles');
在使用 JavaScript 打包程式時,它會將 module1.js、module2.js 和 index.js 組合成一個為您的網路應用程式量身定製的優化打包程式。
雖然現代網路瀏覽器支援 ES 模組和 HTTP/2 等技術,從而解決了請求開銷問題,但 JavaScript 打包程式對於一系列程式碼增強仍然不可或缺。它們可以執行基本的程式碼轉換,包括最小化、轉碼和優化。
此外,JavaScript 模組打包程式還能確保不同瀏覽器之間的相容性。無論使用者選擇何種網路瀏覽器,它們都能幫助解決瀏覽器特有的問題,確保使用者獲得一致的體驗。
這種打包過程不僅能加快網路應用程式的載入速度,還能確保高效的效能,尤其是在生產環境中。現在,您已經瞭解了 JavaScript 打包程式及其在網路開發中的作用,讓我們把重點轉移到 Vite 和 Webpack 上。
Vite 和 Webpack:簡介和概述
很明顯,Vite 和 Webpack 在快速發展的現代網路開發領域處於領先地位,在這一領域,資源管理和優化打包至關重要。不過,在進行詳細比較之前,讓我們先快速瞭解一下這兩個打包程式,並瞭解它們的優勢所在。
Vite:Swift 和按需開發
Vite 的發音是 “veet”,它改變了網路開發人員的遊戲規則,將速度和效率放在首位。讓 Vite 脫穎而出的是它的按需打包方法。Vite 不預先打包所有程式碼和資產,而是利用現代瀏覽器中的本地 ES 模組,在開發過程中直接向瀏覽器提供程式碼。這使得熱模組替換(HMR)幾乎立竿見影,減少了冷啟動時間。
Vite 的開發伺服器採用這種按需方法,使開發人員無需重新編譯即可快速檢視更改。它還使用 Rollup,實現高效的生產構建。因此,Vite 的開發速度快如閃電,生產效能穩定可靠。
Webpack:組織有序、適應性強
Webpack 是現代網路開發的基石,自 2012 年以來一直在穩步發展。Webpack 的優點在於它如何組織網站元件。它通過將程式碼組織成模組來優化載入時間和使用者體驗。
Webpack 的適應性是一個顯著優勢。開發人員可以為簡單或複雜的任務定製專案。它使開發人員能夠定製工作流程,並精確地構建流程。
Vite 和 Webpack 的異同
既然我們已經掌握了 Vite 和 Webpack 的基本概念,下面就讓我們來詳細探討它們的異同。在分析這兩個打包程式時,我們將從各個方面進行研究,以全面瞭解它們之間的比較以及各自的優勢所在。
- 構建與哲學
- 受歡迎程度、社羣和生態系統
- 配置和易用性
- 開發伺服器
- 構建時間和軟體包大小
- 構建優化
- 靜態資產處理
- 靜態網站支援
- 伺服器端渲染支援
- JSON 支援
- Vue.js 和 JSX 支援
- TypeScript 支援
- 全域性匯入支援
- Web Workers 支援
- 庫開發能力
- 瀏覽器相容性
1. 構建與哲學
這兩種打包程式都從獨特的角度構建和優化網路應用程式。它們的共同點是都採用了外掛方式,允許社羣建立更多有益的外掛來擴充套件其功能,從而使它們成為開發人員的多功能工具。
Vite 的核心理念是精簡和可擴充套件性。它堅持極簡策略,專注於最常見的網路應用程式開發模式。這種方法確保了專案的長期可維護性。
Vite 依靠基於卷積的外掛系統,通過外部外掛實現功能,防止核心臃腫。這有助於精簡核心,並鼓勵維護良好的外掛生態系統蓬勃發展。此外,Vite 還積極與 Rollup 專案合作,以保持相容性和共享的外掛生態系統。
Webpack 為開發人員提供了自定義功能,使他們能夠根據從基本任務到複雜工作的具體需求定製專案。它可以靈活配置構建過程的方方面面,是尋求個性化開發體驗的開發人員的首選。
此外,Webpack 引入了模組化方法,類似於為網路專案組裝樂高積木。對於 Webpack 來說,程式碼庫中的所有內容都是一個模組,它可以通過多種方式表達其依賴關係。以下是幾個例子:
- ES2015
import
語句。 - CommonJS
require()
語句。 - AMD
define
和require
語句 - css/sass/less 檔案中的
@import
語句。 - 樣式表
url()
或 HTML<img src="">
檔案中的圖片 URL。
Vite 哲學
Vite 精益和可擴充套件的架構理念在其構建網路應用程式的方法中體現得淋漓盡致。假設您正在開發一個網路應用程式,並希望加入 ES 模組等現代 JavaScript 功能。有了 Vite,您可以毫不費力地做到這一點。下面是一個簡化的示例:
// app.js import { greet } from './utilities.js'; const worker = new Worker(new URL('./worker.js', import.meta.url)); // Simulate a calculation in the web worker worker.postMessage({ input: 42 }); worker.onmessage = (e) => { const result = e.data.result; console.log(`Result from the web worker: ${result}`); }; const message = greet('Hello, Vite!'); console.log(message);
在這個程式碼片段中,Vite 使用了 ES 模組,它能毫不費力地即時打包程式碼,避免了開發過程中耗時的打包步驟。這種模組化方法可以有效管理依賴關係,建立可維護的程式碼庫。這體現了 Vite 對極簡主義和開發人員友好體驗的承諾。
Webpack 哲學
Webpack 的模組化理念對大型專案尤其有益。想象一下,您正在用各種 JavaScript 模組構建一個大型網路應用程式。有了 Webpack,您就可以無縫地組合這些模組,從而提高可讀性、可維護性和網站載入時間。下面是一個簡化的示例:
// webpack.config.js const path = require('path'); module.exports = { entry: './app.js', output: { filename: 'bundle.js', path: path.resolve(__dirname, 'dist'), }, module: { rules: [ { test: /.js$/, use: 'babel-loader', exclude: /node_modules/, }, ], }, };
在本示例中,Webpack 可讓您配置構建流程、優化程式碼並高效處理資產。通過將專案組織成模組並使用 Babel 等載入器,您可以編寫簡潔的模組化程式碼,從而改善使用者體驗。這表明 Webpack 致力於提供定製化和靈活性,確保開發人員可以根據特定需求定製自己的專案。
雖然 Vite 和 Webpack 的架構理念各不相同,但它們都致力於推動現代網路開發的發展。Vite 專注於現代編碼模式,推廣原始碼的 ECMAScript 模組(ESM),並鼓勵採用現代標準,如 Web Worker 的新 Worker 語法。
另一方面,Webpack 是為了應對 Node.js 和 CommonJS 帶來的挑戰而發展起來的,推動了模組在網路開發中的應用。Webpack 的自動依賴關係收集和效能改進確保了開發人員的無縫體驗。
2. 受歡迎程度、社羣和生態系統
Vite 和 Webpack 有著不同的時間線,這決定了它們的受歡迎程度和社羣。
Vite 和 Webpack 在過去 5 年的谷歌趨勢對比。
Vite 才誕生不到 5 年,於 2020 年首次亮相。儘管誕生時間相對較短,但 Vite 已迅速獲得關注,成為現代網路開發領域的一個有前途的參與者。
相比之下,Webpack 成立於 2012 年,起步較早。它在業界的時間使其發展出一個成熟的生態系統和一個強大的社羣。
過去 5 年中 Vite 和 Webpack 在 npmtrends 上的對比。
上圖來自 npmtrends,展示了 Vite 和 Webpack 的下載量對比。它清楚地表明,Webpack 在下載次數方面始終保持著突出的地位,這凸顯了它在開發者社羣中的長期存在和廣泛使用。
Vite 和 Webpack 獲得星星數的歷史資料對比。
當我們使用 star-history(衡量受歡迎程度和社羣支援度的標準)檢視 GitHub 星星資料時,我們發現 Vite 擁有令人印象深刻的 60,318 個星星,而 Webpack 則擁有 63,598 個星星,保持著強大的影響力。這些星星數量反映了這兩個專案的認可度和活躍度。Vite 的快速發展和 Webpack 的持續流行使它們成為網路開發領域的寶貴財富。
3. 配置和易用性
Vite 和 Webpack 都提供了大量配置選項,可根據您的特定需求量身定製打包包。不過,它們之間也有明顯的區別,值得您注意。讓我們來探討一下這兩種工具的配置和易用性。
Vite 的精簡配置
Vite 與眾不同之處在於其零配置理念,旨在簡化您的網站開發過程。這意味著您只需花費最少的精力就能建立一個基本的 Vue 3 元件庫。下面是這樣一個專案的簡單 Vite 配置:
import { defineConfig } from 'vite' import vue from '@vitejs/plugin-vue' export default defineConfig({ plugins: [vue()], })
在上述示例中,我們只匯入並安裝了 Vite 的 Vue.js 官方外掛。Vite 的神奇之處在於它能自動檢測大多數專案的正確設定。
Webpack 配置的複雜性
另一方面,Webpack 往往需要更詳細的配置。雖然在最近的版本中,Webpack 已經趨向於零配置方法,但它並不像 Vite 那樣自動。對於 Vue 3,Webpack 的基本設定可能如下所示:
const webpack = require('webpack'); const path = require('path'); const { HotModuleReplacementPlugin } = require('webpack'); const { VueLoaderPlugin } = require('vue-loader'); module.exports = { entry: './src/main.js', output: { path: path.resolve(__dirname, './build'), filename: 'bundle.js', }, module: { rules: [ { test: /.js$/, exclude: /(node_modules|bower_components)/, use: { loader: 'babel-loader', options: { presets: ['@babel/preset-env'], }, }, }, { test: /.vue$/, use: { loader: 'vue-loader', }, }, { test: /.css$/, use: ['vue-style-loader', 'css-loader'], }, ], }, resolve: { alias: { vue: 'vue/dist/vue.js', }, }, plugins: [ new HotModuleReplacementPlugin(), new VueLoaderPlugin(), ] };
與 Vite 相比,Webpack 的配置需要更多的手動設定。其複雜性包括指定入口和輸出路徑、為不同檔案型別配置載入器,以及為特定功能設定外掛。下面讓我們對配置的每個部分進行分解,並指出其中的複雜之處:
- Entry 和 Output:
entry
指定應用程式的入口點,即 Webpack 開始打包的位置。在本例中,它被設定為 ./src/main.js,假設應用程式的主 JavaScript 檔案在 src 目錄中,而output
則定義了打包檔案的儲存位置。輸出路徑使用path.resolve
解析,生成的打包檔案命名為 bundle.js,並儲存在 build 目錄中。 - 模組規則:
module.rules
部分定義瞭如何處理不同型別的檔案。在本例中,有針對 JavaScript 檔案(用於轉譯的babel-loader
)、Vue 單檔案元件(vue-loader
)和 CSS 檔案(用於處理樣式的vue-style-loader
和css-loader
)的規則。 - 別名配置:
resolve.alias
部分定義了模組匯入的別名。在本例中,它將 Vue 的別名配置為 vue/dist/vue.js。 - 外掛:外掛部分包括支援熱模組替換的
HotModuleReplacementPlugin
,該功能可讓你在開發過程中無需重新載入整個頁面即可檢視更改,而VueLoaderPlugin
則是處理 Vue 單檔案元件所必需的。
最後,Vite 在易用性方面表現突出,提供了簡化的設定和精簡的開發體驗。它的配置要求最低,並使用本地 ES 模組,因此非常適合初學者和快速開發。
相比之下,Webpack 廣泛的可配置性雖然有利於複雜的專案,但也會給新手開發者帶來挑戰。複雜的設定和維護會拖慢開發速度,尤其是對於小型專案而言。
4. 開發伺服器
開發伺服器在開發人員的工作流程中起著至關重要的作用,影響著效率和生產力。讓我們對 Vite 和 Webpack 進行比較,評估它們的開發伺服器效能和可用性,從而為您的網站開發專案找到最合適的工具。
伺服器配置
Vite 憑藉其內建的、開箱即用的開發伺服器脫穎而出,通常無需進行大量配置。
相比之下,Webpack 具有靈活性,但需要額外的設定。開發人員可以選擇 Webpack 的觀察模式、webpack-dev-server
和 webpack-dev-middleware
等選項,以便在變更時自動編譯程式碼。不過,通常需要對這些選項進行配置和微調。
冷啟動速度
傳統的基於打包程式的設定涉及急切抓取,需要在提供服務前構建整個應用程式,從而導致明顯的延遲,尤其是在複雜的專案中。
Vite 從根本上改變了冷啟動方式,大大縮短了初始化時間:
Esbuild 使用預設設定從頭開始製作了一個包含 10 份 three.js 庫的生產打包。(圖片來源:Esbuild)
(1)高效的依賴關係處理:Vite 利用基於 Go 語言的高效能打包程式 esbuild 來預打包依賴項,包括純 JavaScript 和大型模組。作為預打包流程的一部分,Vite 通過將 ESM 依賴項與眾多內部模組合併為一個模組來優化效能。例如,lodash-es 包含 600 多個內部模組。例如,lodash-es 包含 600 多個內部模組。使用傳統方法匯入 debounce
這樣的函式時,會觸發 600 多個 HTTP 請求。Vite 的解決方案是將 lodash-es
預先打包成一個模組,從而將 HTTP 請求減少到一個。請求的大幅減少大大提高了開發伺服器的頁面載入速度。
基於 ESM 的開發伺服器圖 (圖片來源:Vite)
(2)按需載入原始碼:Vite 利用本地 ES 模組提供原始碼,最大限度地減少伺服器負載和延遲。原始碼轉換和服務在瀏覽器請求時進行,從而提高了效率,減少了等待時間。
基於打包的開發伺服器圖。(圖片來源:Vite)
另一方面,Webpack 採用基於打包的方法,預先打包原始碼和依賴項,從而延長了開發過程中的伺服器啟動時間。與 Vite 的高效初始化相比,Webpack 的伺服器設定時間本來就更長。
不過,當使用者導航到需要額外資料、CSS 和資產的路由時,Vite 的按需載入方法可能會帶來輕微的延遲。如果這些資源需要進一步的打包步驟,這種延遲就尤為明顯。相反,Webpack 的策略能確保所有網站資料可用,從而加快瀏覽器導航到開發伺服器內新網頁的速度。
HMR(熱模組替換)
Vite 採用 HMR 而非本地 ESM,通過將一些打包工作解除安裝到瀏覽器來減少伺服器負載和延遲。這可確保快速更新,而無需重新載入整個頁面,這對開發過程中的實時反饋至關重要。
Webpack 也支援 HMR,可在開發過程中實現實時更新並保留應用程式狀態。不過,利用本地 ES 模組的潛在限制可能會導致更高的伺服器負載和延遲。
快取效能
快取對於提高網路應用效能、通過重複使用儲存資產來減少負載和構建時間至關重要。
Vite 中的快取由檔案系統快取管理,根據 package.json、lockfiles 和 vite.config.js 中的變化更新依賴關係。它通過快取已解決的依賴請求來優化頁面過載。
Webpack 也使用檔案系統快取,在監視模式下清除修改過的檔案,在非監視模式下每次編譯前清除快取,需要自定義配置以優化快取。
在開發伺服器的比較中,Vite 和 Webpack 提供了不同的開發伺服器方法:
- Vite 提供了開箱即用的開發伺服器,最大限度地減少了配置開銷。
- Webpack 配置靈活,但需要額外設定。
- Vite 在冷啟動速度和快速更改程式碼的 HMR 方面表現出色
- 由於預先打包了網站資料,Webpack 在瀏覽器導航速度方面表現更好。
- 兩者都支援 HMR,但有不同的模組服務機制。
- Vite 可無縫管理本地和瀏覽器快取,而 Webpack 則需要自定義配置。
5. 構建時間和軟體包大小
現在,讓我們比較一下 Vite 和 Webpack 的構建時間和打包包大小(考慮到開發構建、開發伺服器期間的熱更改和生產構建)。
我們的測試環境包括:
- 在配備蘋果 M1 晶片和 8 核 GPU 的 MacBook Air 上執行測試。
- 一箇中等規模的 Vue 3 專案,包含 10 個元件,使用 Vuex 進行狀態管理,使用 Vue Router 進行路由。
- 包含樣式表(CSS/SASS)、圖片和字型等資產,以及適量的依賴關係。
我們先來比較一下打包時間:
Vite [v4.4.11] | Webpack [v5.89.0] | |
---|---|---|
開發人員首次構建 | 376ms | 6s |
熱更新 | 立即 | 1.5s |
最終打包 | 2s | 11s |
在打包速度方面,Vite 明顯勝出,大大縮短了構建時間。雖然 Webpack 提供了可配置性和強大的開發工具,但還是落後於 Vite。
Vite [v4.4.11] (KB) | Webpack [v5.89.0] (KB) | |
---|---|---|
最終打包檔案大小 | 866kb | 934kb |
這些資料基於一箇中等規模的 Vue.js 應用程式,其依賴項數量適中。實際的打包包大小會因專案複雜性、依賴關係和優化技術的不同而變化。
Vite 的打包大小較小,這是因為它使用 esbuild 和本地 ES 模組進行了高效的預打包。
Webpack 的打包包大小可以通過各種配置選項和外掛進行優化,但由於其打包過程非常全面,通常會產生較大的打包包。
6. 構建優化
說到優化現代網路開發中的構建流程,Vite 和 Webpack 提供了不同的方法,每種方法都有自己的特性和功能。讓我們通過探討 Vite 和 Webpack 之間的主要區別來深入瞭解構建優化。
生成預載入指令
Vite 會自動為入口塊生成 <link>
指令,並在構建的 HTML 中直接匯入。這樣就能根據需要有效地預載模組,從而縮短載入時間。
因此,在檢查頁面時,可能會出現以下情況:
<!-- Vite - Module Preloading --> <link rel="modulepreload" href="/module-a.js">
Webpack 本身並不支援瀏覽器對資源的提示。但從 Webpack v4.6.0
開始,它支援預取和預載入。在宣告匯入時使用內聯指令可以讓 Webpack 輸出資源提示,為瀏覽器提供有關何時載入匯入檔案的資訊。例如
import(/* webpackPreload: true */ '/module-a.js');
這將輸出:
<!-- Webpack - Manual Module Preloading --> <link rel="preload" as="script" href="/module-a.js">
CSS 程式碼拆分
Vite 以其精簡的 CSS 程式碼分割方法脫穎而出。它能自動提取模組在非同步分塊中使用的 CSS,並生成單獨的檔案。這意味著在載入相關的非同步塊時,只需通過 <link>
標籤載入必要的 CSS。
值得注意的是,Vite 可確保在載入 CSS 後才對非同步分塊進行評估,從而防止出現無樣式內容 Flash (FOUC)。由於該功能已預先配置,因此您可以繼續匯入 CSS 檔案,無需任何額外步驟:
import './main.css';
Webpack 提供了靈活性,但在拆分 CSS 程式碼時需要更多配置。它允許開發人員使用各種外掛和配置選項(如 mini-css-extract-plugin
)來拆分 CSS。
// Webpack - CSS Code Splitting const MiniCssExtractPlugin = require('mini-css-extract-plugin');
程式碼拆分和分塊載入
程式碼分割是一種基本技術,用於將程式碼分割成更小、更易於管理的片段,只在需要時載入所需的內容。這種做法大大縮短了初始載入時間,節約了資源。
(1)Vite 的分塊方法
在某些情況下,Vite 會使用 Rollup 自動將程式碼分割成獨立的程式碼塊,如動態載入或多個入口點,也有一種方法可以通過 output.manualChunks 選項明確告訴 Rollup 哪些模組要分割成獨立的程式碼塊。
除了 Vite 預配置的程式碼分割功能外,Vite 還支援使用變數的動態匯入:
const module = await import(`./dir/${wbolt}.js`)
Vite 還允許開發人員使用官方的 splitVendorChunkPlugin()
來分割 vendor 塊:
import { splitVendorChunkPlugin } from 'vite' export default defineConfig({ plugins: [splitVendorChunkPlugin()], })
在動態匯入和程式碼拆分的過程中,程式碼通常會結構化為模組或塊,其中一些模組會在網路應用程式的不同部分之間共享。Vite 可以識別常見的模組,並優化載入過程。為了更好地理解這一點,讓我們看看 Vite 官方文件中的示例。
顯示兩個非同步分塊所需的普通分塊的圖表(圖片來源:Vite)
在沒有優化的情況下,當使用者開啟網路應用程式的某個部分(我們稱之為依賴於共享程式碼 “Common Chunk C” 的 Section A)時,瀏覽器會首先獲取 Section A,在解析 Section A 時,瀏覽器會意識到它需要 “Common Chunk C“:
Entry (Section A) ---> async chunk A ---> common chunk C
另一方面,Vite 採用了一種名為 “非同步大塊載入優化“(Async Chunk Loading Optimization)的複雜功能。它不會等待瀏覽器發現自己的需求,而是主動做好準備。當使用者請求 Section A 時,Vite 會同時傳送 Section A 和 Common Chunk C。這種並行獲取所需資料塊的方式大大加快了載入過程:
Entry (Section A) ---> (async chunk A + common chunk C)
然而,問題並不止於此。Common Chunk C 可能有自己的依賴關係,在非優化方案中可能會造成更多的往返。Vite 不會忽視這一點。它會嚴格分析這些依賴關係,確保一次性高效載入所需的所有內容(無論其深度如何)。這就消除了額外網路往返的必要性,保證了網路應用程式的高度響應性。
Vite 的非同步分塊載入方法通過主動獲取和並行提供所有必要的程式碼塊來優化載入過程。這樣就避免了額外的網路往返,從而帶來更快的網路體驗。這就好比為瀏覽器提供了一個精心準備的旅行路線,確保瀏覽器能接收到所有必要的資源,而不會出現不必要的延遲。
(2)Webpack 的程式碼拆分方法
對於 Webpack,有三種通用的程式碼拆分技術:
- Entry points:這是分割一段程式碼最簡單的方法。我們只需在配置檔案中定義一個新的入口點,Webpack 就會將其新增為一個單獨的塊:
const path = require('path');module.exports = {mode: 'development',entry: {index: './src/index.js',another: './src/separate-module.js',},output: {filename: '[name].bundle.js',path: path.resolve(__dirname, 'dist'),},};const path = require('path'); module.exports = { mode: 'development', entry: { index: './src/index.js', another: './src/separate-module.js', }, output: { filename: '[name].bundle.js', path: path.resolve(__dirname, 'dist'), }, };
const path = require('path'); module.exports = { mode: 'development', entry: { index: './src/index.js', another: './src/separate-module.js', }, output: { filename: '[name].bundle.js', path: path.resolve(__dirname, 'dist'), }, };
不過,這種方法也有侷限性。如果模組以不同的入口塊匯入,它們最終會同時出現在兩個打包包中,導致程式碼重複。此外,在需要拆分核心應用程式邏輯時,這種方法的適應性也不強。
- Prevent duplication:另一種方法是使用
entry
依賴關係或SplitChunksPlugin
來分割程式碼塊,這有助於減少冗餘。下面舉例說明如何使用entry
依賴關係配置程式碼分割:const path = require('path');module.exports = {mode: 'development',entry: {index: {import: './src/index.js',dependOn: 'shared',},another: {import: './src/another-module.js',dependOn: 'shared',},shared: 'lodash',},output: {filename: '[name].bundle.js',path: path.resolve(__dirname, 'dist'),},optimization: {runtimeChunk: 'single',},};const path = require('path'); module.exports = { mode: 'development', entry: { index: { import: './src/index.js', dependOn: 'shared', }, another: { import: './src/another-module.js', dependOn: 'shared', }, shared: 'lodash', }, output: { filename: '[name].bundle.js', path: path.resolve(__dirname, 'dist'), }, optimization: { runtimeChunk: 'single', }, };const path = require('path'); module.exports = { mode: 'development', entry: { index: { import: './src/index.js', dependOn: 'shared', }, another: { import: './src/another-module.js', dependOn: 'shared', }, shared: 'lodash', }, output: { filename: '[name].bundle.js', path: path.resolve(__dirname, 'dist'), }, optimization: { runtimeChunk: 'single', }, };
- Dynamic imports:最後,Webpack 支援動態匯入,這是一種按需載入程式碼的重要功能。它使用的語法符合 ECMAScript 關於動態匯入的提議。這種方法更加靈活和細化,適用於各種程式碼拆分場景。
const { default: _ } = await import('lodash');const { default: _ } = await import('lodash');
const { default: _ } = await import('lodash');
我們還可以使用 Webpack 的 “魔法註釋“(Magic Comments)來設定分塊的名稱、懶載入分塊、指定模組匯出並設定獲取優先順序:
import(/* webpackChunkName: "my-chunk-name" *//* webpackMode: "lazy" *//* webpackExports: ["default", "named"] *//* webpackFetchPriority: "high" */'module');import( /* webpackChunkName: "my-chunk-name" */ /* webpackMode: "lazy" */ /* webpackExports: ["default", "named"] */ /* webpackFetchPriority: "high" */ 'module' );import( /* webpackChunkName: "my-chunk-name" */ /* webpackMode: "lazy" */ /* webpackExports: ["default", "named"] */ /* webpackFetchPriority: "high" */ 'module' );
Tree-Shaking
樹形抖動(Tree-Shaking)是一項重要的優化技術,Vite 和 Webpack 都使用它來縮減 JavaScript 包的大小。
Vite 利用 Rollup,它不僅能使用 ES 模組,還能靜態分析您匯入的程式碼。這意味著 Vite 可以排除模組中不使用的部分,從而縮小打包包的大小。例如,如果您的模組有多個函式,但只使用了其中一個,Vite 就會在打包包中只包含該函式。下面是一個簡單的例子:
- 如果不使用 ES 模組,要從 ./utils.js 匯入
ajax
,就需要匯入整個檔案。const utils = require('./utils');const query = 'Wbolt';// Use the 'ajax' method of the 'utils' objectutils.ajax(`https://api.example.com?search=${query}`).then(handleResponse);const utils = require('./utils'); const query = 'Wbolt'; // Use the 'ajax' method of the 'utils' object utils.ajax(`https://api.example.com?search=${query}`).then(handleResponse);const utils = require('./utils'); const query = 'Wbolt'; // Use the 'ajax' method of the 'utils' object utils.ajax(`https://api.example.com?search=${query}`).then(handleResponse);
- 另一方面,使用 ES 模組可以只匯入所需的內容,從而使庫和應用程式更輕、更快、更復雜。由於 Vite 使用顯式
import
和export
語句,因此它可以執行高效的樹狀結構轉換,而無需完全依賴自動精簡器來檢測未使用的程式碼。import { ajax } from './utils';const query = 'Wbolt';// Call the 'ajax' functionajax(`https://api.example.com?search=${query}`).then(handleResponse);import { ajax } from './utils'; const query = 'Wbolt'; // Call the 'ajax' function ajax(`https://api.example.com?search=${query}`).then(handleResponse);import { ajax } from './utils'; const query = 'Wbolt'; // Call the 'ajax' function ajax(`https://api.example.com?search=${query}`).then(handleResponse);
最後,對於 Vite,我們可以使用 Rollup 預配置的樹狀抖動選項。
Webpack 也支援樹狀結構,但其機制不同。它會分析程式碼中的依賴關係,並在打包過程中刪除未使用的部分。雖然這種方法很有效,但可能不如 Vite 的方法徹底,尤其是在處理大型模組或庫時。
此外,根據 Webpack 的文件。我們需要將檔案標記為 side-effect free,以保證不會移除任何在生產中依賴於該檔案的程式碼。
實現這一點的方法是使用 sideEffects
package.json 屬性:
{ "name": "wbolt-app", "sideEffects": false }
值得注意的是,在 Vite 的 Rollup 選項中也有類似的配置選項來定義 side effects。
7. 靜態資產處理
靜態資產(如影象、字型和其他檔案)是網頁開發不可或缺的一部分。Vite 和 Webpack 處理這些資產的方式各不相同,各有優勢和優化之處。
Vite 的資產處理
Vite 處理靜態資產的方法精簡高效。匯入靜態資產時,Vite 會在提供時返回已解析的公共 URL。例如,當您匯入這樣一張圖片時:
import wboltImage from './wbolt-image.png';
在開發過程中, imgUrl
將解析為 /img.png
。在生產構建過程中,它將變成類似 /assets/img.2d8efhg.png
,為快取和效能進行了優化。
Vite 可以使用絕對公共路徑或相對路徑來處理這些匯入,從而靈活地滿足專案需求。Vite 還能無縫處理 CSS 中的 URL 引用。
此外,如果您在 Vue 單檔案元件(SFC)中使用 Vite,模板中的資產引用會自動轉換為匯入,從而簡化您的開發工作流程。
Vite 的資產處理功能更進一步,它可以檢測常見的影象、媒體和字型檔案型別,並將其視為資產。這些資產將作為構建資產圖的一部分,獲得雜湊檔名,並可由外掛進行優化處理。
Webpack 的資產處理
另一方面,Webpack 在處理靜態資產時採用了不同的方法。使用 Webpack,你可以像平常一樣匯入資產:
import wboltImage from './wbolt-image.png';
Webpack 在處理該匯入時,會將圖片新增到輸出目錄中,併為您提供圖片的最終 URL。這樣就能輕鬆處理資產,還能在 CSS 中使用 url('./my-image.png')
進行處理。Webpack 的 css-loader
會將其識別為本地檔案,並將路徑替換為輸出目錄中的最終圖片 URL。當使用 html-loader
來處理 <img src="./wbolt-image.png" />
時也是如此。
第 5 版中引入的 Webpack 資產模組可以處理各種型別的資產,而不僅僅是圖片。例如,您可以配置 Webpack 來處理字型檔案:
module.exports = { module: { rules: [ { test: /\.(woff|woff2|eot|ttf|otf)$/, type: 'asset/resource', }, ], }, };
該配置允許您通過 @font-face
宣告在專案中加入字型。
8. 靜態網站支援
靜態網站具有眾多優勢,如載入時間快、安全性高、託管簡單等。靜態網站由 HTML、CSS 和 JavaScript 組成,可提供簡化的使用者體驗和高效的內容交付。Vite 和 Webpack 都能幫助開發人員生成效能良好的靜態網站,但效率卻不盡相同。
Vite 靜態網站生成方法
Vite 提供專門的靜態網站部署說明,利用其簡化的開發和部署方法,特別適合靜態網站。
Vite 的另一個亮點是它有一個 preview
指令碼,可以幫助開發人員在本地啟動生產構建,檢視應用程式的最終執行結果。這一功能允許開發人員在將生產構建部署到實時伺服器之前對其進行測試和預覽。
不過,需要注意的是,Vite 的 preview
指令碼是用於在本地預覽構建,而不是用作生產伺服器。這意味著它是開發人員在部署前測試應用程式的好工具,但不適合託管實時生產網站。
{ "scripts": { "preview": "vite preview --port 3000" } }
值得強調的是 VitePress,它是 Vite 生態系統中最強大的工具之一。VitePress 是一種靜態網站生成器(SSG),用於快速生成以內容為重點的網站。VitePress 採用基於 Markdown 的源文字,應用一個主題,然後輸出靜態 HTML 頁面,這些頁面可以在雲伺服器上快速部署。
Webpack 的靜態網站生成方法
雖然 Webpack 並不是專門為生成靜態網站而設計的,但它可以通過各種外掛和配置來建立靜態網站。不過,與 Vite 相比,Webpack 的過程通常更為複雜,而且不夠精簡。Webpack 的主要重點在於打包和優化 JavaScript 模組,這使其成為構建複雜網路應用程式的強大工具。
9. 伺服器端渲染支援
伺服器端渲染(SSR)是一種網路開發技術,它在伺服器上渲染網頁,並將完全渲染後的 HTML 傳送到客戶端瀏覽器。讓我們比較一下這兩種打包程式對 SSR 的支援:
- Vite:Vite 支援伺服器端渲染,為需要 SSR 的應用程式提供了一種簡化的方法。有了 Vite,可以在 Node.js 中執行同一應用程式、將其預渲染為 HTML 並隨後在客戶端進行水合的前端框架就可以無縫整合。這使得 Vite 成為需要 SSR 功能的應用程式的絕佳選擇,為開發人員提供了優化伺服器渲染應用程式所需的工具。
- Webpack:Webpack 也可用於伺服器端渲染。不過,使用 Webpack 實現 SSR 往往更為複雜,需要對配置和設定有更深入的瞭解。與 Vite 提供的更精簡的方法相比,開發人員可能需要投入更多時間來使用 Webpack 設定 SSR。
10. JSON 支援
Vite 和 Webpack 都支援匯入 JSON 檔案。除 Vite 外,還支援以 JSON 命名的匯入,以幫助實現 tree-shaking。
// import an object import json from './example.json' // import a root field as named exports. import { test } from './example.json'
11. Vue.js 和 JSX 支援
著名的 JavaScript 框架 Vue.js 遵循 SFC(單檔案元件)語法,簡化了建立使用者介面的過程。相比之下,JSX 是一種 JavaScript 語法擴充套件,主要用於 React,使開發人員能夠使用類似 HTML 的標記和元素來定義使用者介面結構。
Vite 提供一流的 Vue.js 支援,其官方外掛可將 Vite 與 Vue 無縫整合。由於採用了 esbuild 轉譯技術,它還能處理開箱即用的 JSX 檔案( .jsx
和 .tsx
)。Vue.js 使用者可以使用 @vitejs/plugin-vue-jsx
外掛,該外掛專為 Vue 3 量身定製,提供 HMR、全域性元件解析、指令和插槽等功能。
如果 JSX 與 React 或 Preact 等其他框架一起使用,Vite 允許通過 esbuild 選項配置自定義的 jsxFactory
和 jsxFragment
。這種靈活性對於需要定製 JSX 的專案來說非常有價值。
// vite.config.js import { defineConfig } from 'vite' export default defineConfig({ esbuild: { jsxFactory: 'h', jsxFragment: 'Fragment', }, })
另一方面,Webpack 缺乏對 Vue.js 或任何其他特定庫或框架的本地支援。開發人員需要安裝相關的載入器和依賴項,才能為現代 JavaScript 框架建立專案,這就使得開發過程變得更加手動和複雜。
12. TypeScript 支援
Vite 為 TypeScript 提供本機支援,可將 .ts
檔案無縫整合到專案中。它使用 esbuild 轉譯器在開發過程中快速轉換程式碼。Vite 專注於轉譯,而非型別檢查。它希望你的整合開發環境和構建過程能處理型別檢查。
Webpack 缺乏對 TypeScript 的原生支援,因此開發人員需要使用 typescript 編譯器和 ts-loader
手動設定 TypeScript。這需要配置 tsconfig.json,以指定 TypeScript 選項。設定完成後,Webpack 會使用 ts-loader
來編譯 TypeScript 程式碼。雖然這引入了額外的配置步驟,但它提供了靈活性並與其他 Webpack 功能相容。
13. 全域性匯入支援
Vite 支援全域性匯入。該功能用於通過 import.meta.glob
函式從檔案系統匯入多個模組:
const modules = import.meta.glob('./wbolt/*.js')
這將輸出:
const modules = { './wbolt/isCool.js': () => import('./wbolt/isCool.js'), './wbolt/isAwesome.js': () => import('./wbolt/isAwesome.js'), './wbolt/isFun.js': () => import('./wbolt/isFun.js'), }
Vite 還支援 Glob Import As,使用 import.meta.glob
將檔案匯入字串。下面是一個程式碼示例:
const modules = import.meta.glob('./wbolt/*.js', { as: 'raw', eager: true })
它將變成這個樣子:
const modules = { './wbolt/rocks.js': 'export default "rocks"\n', './wbolt/rules.js': 'export default "rules"\n', }
{ as: 'url' }
也支援將資產載入為 URL。
Webpack 需要額外的外掛,如 webpack-import-glob-loader
和 glob-import-loader
來執行 Glob Imports。它們將擴充套件此功能:
import modules from "./test/**/*.js";
為:
import * as moduleOne from "./foo/1.js"; import * as moduleTwo from "./test/bar/2.js"; import * as moduleThree from "./test/bar/3.js"; var modules = [moduleOne, moduleTwo, moduleThree];
14. Web Workers 支援
Web Worker 是在後臺執行繁重任務而不凍結主網頁的關鍵。下面介紹 Vite 和 Webpack 如何處理它們:
Vite 可讓您輕鬆使用 Web Worker。您可以建立一個單獨的 Web Worker 檔案,將其匯入主程式碼並與之通訊。Vite 提供了兩種在主程式碼中匯入 Worker 的方法:
1. 新 Worker()
和新 SharedWorker()
建構函式:
const worker = new Worker(new URL('./worker.js', import.meta.url)); // OR const worker = new SharedWorker(new URL('./worker.js', import.meta.url));
2. 通過附加 ?worker
或 ?sharedworker
直接匯入:
import MyWorker from './worker?worker'; const worker = new MyWorker(); myWorker.postMessage('Hello from the main thread!');
Webpack 還支援 Web Worker,而且從 Webpack 5 開始,我們就不需要使用載入器來使用 Worker 了。
Const worker = new Worker(new URL('./worker.js', import.meta.url));
15. 庫開發能力
庫和框架使開發人員能夠建立和共享工具,從而加快網路應用程式的開發。Vite 和 Webpack 都提供了強大的解決方案。
Vite 通過其專門的庫模式將庫開發提升到一個新的水平,簡化了建立以瀏覽器為中心的庫的過程。此外,Vite 還能靈活地將特定的依賴關係(如 Vue 或 React)外部化,而您可能不希望在庫打包中包含這些依賴關係。
另一方面,Webpack 是一個多功能的打包工具,也能滿足庫作者的需求。如果您使用 Webpack 建立 JavaScript 庫,您可以對其進行配置,以滿足您打包庫的獨特需求。它允許你定義如何打包庫的程式碼,因此適合構建各種庫。
16. 瀏覽器相容性
Vite 優先使用現代瀏覽器,目標是那些支援本地 ES 模組的瀏覽器,如 Chrome 瀏覽器 >=87、Firefox 瀏覽器 >=78、Safari 瀏覽器 >=14 和 Edge 瀏覽器 >=88。
也可以從 es2015 開始,通過 build.target
設定自定義目標。通過 @vitejs/plugin-legacy
支援傳統瀏覽器。
Webpack 支援所有相容 ES5 的瀏覽器(不包括 IE8 及以下版本)。為適應舊版瀏覽器,需要對 import()
和 require.ensure()
等功能進行多填充。
就瀏覽器相容性而言,兩者都很不錯,但您的選擇應取決於專案的目標受眾及其瀏覽器功能。
小結
Vite 採用原生 ES 模組方法,開發速度快如閃電,更新迅速,並提供廣泛的自定義選項。相反,Webpack 以其健壯性和廣泛的生態系統而著稱,在生產構建中表現出色,但需要更陡峭的學習曲線。
在 Vite 和 Webpack 之間做出選擇時,應考慮專案需求和對複雜配置的熟悉程度。兩者各有優勢,請根據專案的具體要求進行選擇。
評論留言