Vite(法語單詞,“快” 的意思)是一種新型的前端構建工具
最初是配合 Vue3.0 一起使用的,后來適配了各種前端項目,目前提供了 Vue、React、Preact 框架模板
目前來說,Vue 使用的是 vue-cli 腳手架,React 一般使用 create-react-app 腳手架。雖然腳手架工具不一樣,但是內部的打包工具都是 Webpack
為什么要開發一個全新的構建工具,是 Webpack 不香了嗎?
Vite 方式構建的項目,和使用 Webpack 構建的項目,有什么不同?
一個新工具的出現,一定是為了解決現有工具存在的問題的,否則新工具就沒有存在的價值和意義
vite
vite —— 一個由 vue 作者尤雨溪開發的 web 開發工具,它具有以下特點:
-
快速的冷啟動
-
即時的模塊熱更新
-
真正的按需編譯
從作者在微博上的發言:
Vite,一個基於瀏覽器原生 ES imports 的開發服務器。利用瀏覽器去解析 imports,在服務器端按需編譯返回,完全跳過了打包這個概念,服務器隨起隨用。同時不僅有 Vue 文件支持,還搞定了熱更新,而且熱更新的速度不會隨着模塊增多而變慢。針對生產環境則可以把同一份代碼用 rollup 打。雖然現在還比較粗糙,但這個方向我覺得是有潛力的,做得好可以徹底解決改一行代碼等半天熱更新的問題
中可以看出 vite 主要特點是基於瀏覽器 native 的
基於瀏覽器 ES module 來開發 web 應用也不是什么新鮮事,snowpack 也基於此,不過目前此項目社區中並沒有流行起來,vite 的出現也許會讓這種開發方式再火一陣子
有趣的是 vite 算是革了 webpack 的命了(生產環境用 rollup)
vite 的使用方式
同常見的開發工具一樣,vite 提供了用 npm 或者 yarn 一建生成項目結構的方式,使用 yarn 在終端執行
$ yarn create vite-app <project-name> $ cd <project-name> $ yarn $ yarn dev
即可初始化一個 vite 項目(默認應用模板為 vue3.x),生成的項目結構十分簡潔
|____node_modules |____App.vue // 應用入口 |____index.html // 頁面入口 |____vite.config.js // 配置文件 |____package.json
Vite 解決了 Webpack 哪些問題
隨着項目的復雜度升級,代碼規范和管理就必須要同步提升。於是,編程社區中提出了多種模塊化規范,服務端選擇了 CommonJS 規范,客戶端選擇 AMD 規范較多,但是,兩種模塊化規范也都存在一定的問題,都是 JS 編程,有兩個不同的模塊化規范,在 JS 語言層面還是不夠的,終於在 ES6 中,ECMA 委員會推出了語言層面模塊系統:ES Modules 規范
模塊化可以幫助我們更好地解決復雜應用開發過程中的代碼組織問題,但是隨着模塊化思想的引入,我們的前端應用又會產生了一些新的問題,比如:
-
首先,我們所使用的 ES Modules 模塊系統本身就存在環境兼容問題。盡管現如今主流瀏覽器的最新版本都支持這一特性,但是目前還無法保證用戶的瀏覽器使用情況。所以我們還需要解決兼容問題
-
其次,模塊化的方式划分出來的模塊文件過多,而前端應用又運行在瀏覽器中,每一個文件都需要單獨從服務器請求回來。零散的模塊文件必然會導致瀏覽器的頻繁發送網絡請求,影響應用的工作效率
-
最后,談一下在實現 JS 模塊化的基礎上的發散。隨着應用日益復雜,在前端應用開發過程中不僅僅只有 JavaScript 代碼需要模塊化,HTML 和 CSS 這些資源文件也會面臨需要被模塊化的問題。而且從宏觀角度來看,這些文件也都應該看作前端應用中的一個模塊,只不過這些模塊的種類和用途跟 JavaScript 不同
對於開發過程而言,模塊化肯定是必要的,所以我們需要在前面所說的模塊化實現的基礎之上引入更好的方案或者工具,去解決上面提出的 3 個問題,讓我們的應用在開發階段繼續享受模塊化帶來的優勢,又不必擔心模塊化對生產環境所產生的影響
本質上,webpack 是一個現代 JavaScript 應用程序的靜態模塊打包器(module bundler)
Vue 腳手架工具 vue-cli 使用 webpack 進行打包,開發時可以啟動本地開發服務器,實時預覽。因為需要對整個項目文件進行打包,開發服務器啟動緩慢
而對於開發時文件修改后的熱更新 HMR 也存在同樣的問題
Webpack 的熱更新會以當前修改的文件為入口重新 build 打包,所有涉及到的依賴也都會被重新加載一次
Vite 則很好地解決了上面的兩個問題
打包問題
vite 只啟動一台靜態頁面的服務器,對文件代碼不打包,服務器會根據客戶端的請求加載不同的模塊處理,實現真正的按需加載
熱更新問題
vite 采用立即編譯當前修改文件的辦法。同時 vite 還會使用緩存機制( http 緩存 => vite 內置緩存 ),加載更新后的文件內容
所以,vite 具有了快速冷啟動、按需編譯、模塊熱更新等優良特質
綜上所述,vite 構建項目與 vue-cli 構建的項目在開發模式下還是有比較大的區別:
-
Vite 在開發模式下不需要打包可以直接運行,使用的是 ES6 的模塊化加載規則;Vue-CLI 開發模式下必須對項目打包才可以運行
-
Vite 基於緩存的熱更新,Vue-CLI 基於 Webpack 的熱更新
vite 啟動鏈路
命令解析
這部分代碼在 src/node/cli.ts 里,主要內容是借助 minimist —— 一個輕量級的命令解析工具解析 npm scripts,解析的函數是 resolveOptions
,精簡后的代碼片段如下
function resolveOptions() { // command 可以是 dev/build/optimize if (argv._[0]) { argv.command = argv._[0] } return argv }
if (!options.command || options.command === 'serve') { runServe(options) } else if (options.command === 'build') { runBuild(options) } else if (options.command === 'optimize') { runOptimize(options) }
server
這部分代碼在 src/node/server/index.ts 里,主要暴露一個 createServer
方法
vite 使用 koa 作 web server,使用 clmloader 創建了一個監聽文件改動的 watcher,同時實現了一個插件機制,將 koa-app 和 watcher 以及其他必要工具組合成一個 context 對象注入到每個 plugin 中
context 組成如下
plugin 依次從 context 里獲取上面這些組成部分,有的 plugin 在 koa 實例添加了幾個 middleware,有的借助 watcher 實現對文件的改動監聽,這種插件機制帶來的好處是整個應用結構清晰,同時每個插件處理不同的事情,職責更分明
plugin
plugin大致分類如下
-
用戶注入的 plugins —— 自定義 plugin
-
hmrPlugin —— 處理 hmr
-
htmlRewritePlugin —— 重寫 html 內的 script 內容
-
moduleRewritePlugin —— 重寫模塊中的 import 導入
-
moduleResolvePlugin ——獲取模塊內容
-
vuePlugin —— 處理 vue 單文件組件
-
esbuildPlugin —— 使用 esbuild 處理資源
-
assetPathPlugin —— 處理靜態資源
-
serveStaticPlugin —— 托管靜態資源
-
cssPlugin —— 處理 css/less/sass 等引用
接下來看看 plugin 的實現方式,開發一個用來攔截 json 文件 plugin 可以這么實現
interface ServerPluginContext { root: string app: Koa server: Server watcher: HMRWatcher resolver: InternalResolver config: ServerConfig } type ServerPlugin = (ctx:ServerPluginContext)=> void; const JsonInterceptPlugin:ServerPlugin = ({app})=>{ app.use(async (ctx, next) => { await next() if (ctx.path.endsWith('.json') && ctx.body) { ctx.type = 'js' ctx.body = `export default json` } }) }
vite 背后的原理都在 plugin 里,有興趣可以每一個都了解一下
build
這部分代碼在 node/build/index.ts 中,build 目錄的結構雖然與 server 相似,同樣導出一個 build 方法,同樣也有許多 plugin,不過這些 plugin 與 server 中的用途不一樣,因為 build 使用了 rollup ,所以這些 plugin 也是為 rollup 打包的 plugin
結語:Vite原理下期再見