通俗的解釋下Vite能用來干嘛?是怎么回事?
本文轉載自微信公眾號「秋風的筆記」,作者藍色的秋風。轉載本文請聯系秋風的筆記公眾號。
最近在B乎看到了這么一個問題,能不能通俗地講 Vite 到底是用來干嘛的,一開始覺得這個問題沒什么意思,因為 Vite 這個話題有太多的人講了。
但是我看了看其他的回答,大部分都會從 Vite 的特性,ES Modules 去講整件事情,然后還是會時不時要和 webpack 去做比較。
而且我又仔細看了看題主的疑問。
我也陷入了深深的思考,到底是大家學習一些新知識的時候急迫了呢?還是說前端常常容易把一些簡單的東西復雜化,容易形成套娃式的知識?又或者是知識太零散了,分不清到底是哪些是有關系的?
探索Vite
我打開了 Vite 的官網,他的標語是 「 下一代前端開發與構建工具」,因為一般標語需要言簡意賅地表達出它的意思,所以會用最精簡的去概括(也是為了宣傳)。我認為確實也沒有啥毛病,但是對于一些新手而且,確實這句話不知所云,官網也沒有足夠清楚的圖,如果是一些不了解的人,確實也容易迷失。
那么這句話到底要表達出什么意思呢?我用通俗的話表述了一遍(可能不一定準確,僅代表個人的理解):
目前大部分瀏覽器已經支持了ESM(ES Modules)模塊的方式了,因此我寫了一個轉化工具,可以讓一些瀏覽器不支持的格式(.vue/.svelte/.ts)以及不支持的語法(最新的es語法/特性)讓瀏覽器支持,它將會成為趨勢。
很多人會從 ES Modules 、Dev Server 、Vue 集成度高、速度快啊各種方向來講解它,更像是在說它的優點,我覺得有點神話它了,所以才讓它變得那么神秘(迷惑)?
而在我看來 Vite 就是一個轉化器,而 Webpack 就是 模塊器 + 轉化器。
轉化器的用途就是,將一些瀏覽器無法解析的文件,轉化成可以被瀏覽器解析的 js 文件,Vite 做的核心就是這個。什么用 Vite 快啊,都是瀏覽器自己的功勞,瀏覽器統一了模塊化方案,Vite 只是吃了一波瀏覽器的性能紅利而已。
用一張圖來描述就是(這里我盜用了 Webpack 的官方圖,改了改)
Vite 就是把所有的資源都轉化成了 js 的形式去引入,因為瀏覽器只支持 js 文件的 ES Modles 方式,畢竟 ES Modules 屬于 ECMAscript 規范,當然只能是適用于 js 了。而整個模塊化過程都是瀏覽器的功勞。
這里再來看看 Webpack 的整體流程圖,如果你對 Webpack 了解,可能能加深印象,但是不了解 webpack 也沒關系。
由于 Webpack 要自己的模塊化方式,因此需要將所有的資源都打包成一個 js,這個圖很形象地解釋了 Webpack 的作用。(對于不了解 Webpack 的也沒有關系,知道 Vite 的圖就夠了。)
我舉一個例子,可能能讓你更加清楚地去理解 Vite 的真面目。
- // index.html
- <script type="module" src="main.js"></script>
- // main.js
- import { element, text } from './el.js';
- const container = element('div');
- const h1 = element('h1');
- const t = text('Hello ES Modules');
- h1.appendChild(t);
- container.appendChild(h1);
- document.body.appendChild(container);
- // el.js
- export function element(name) {
- return document.createElement(name);
- }
- export function text(data) {
- return document.createTextNode(data);
- }
在 VS Code 裝一個 Live Server , 然后啟動這個 html, 然后我們隨便改點東西,可以看到,更新速度的非常快。
也許你會說,我文件數量太少了,沒事,我們這次來整活20個文件。
- const fs = require('fs');
- const LENGTH = 20;
- new Array(LENGTH).fill(0).forEach((item, index) => {
- fs.writeFileSync(`child-${index}.js`, `
- export { child } from './child-${index+1}.js';
- `)
- })
- fs.writeFileSync(`child-${LENGTH}.js`, `
- import { element, text } from '../el.js';
- export function child() {
- const c = element('div');
- const t = text('child');
- c.appendChild(t);
- document.body.appendChild(c);
- }
- `)
所以我說,Vite 本質是撥除了 webpack 模塊化功能后的一個轉化器。
但是盡管瀏覽器解決了模塊化的依賴,依舊是有兩個問題:
但是沒辦法支持一些樣式/文件(css/ttf/jpg...)資源的 import 語法
無法支持.ts/.vue/.svelte 等模板語法(或者高級特性)的直接引用
所以,才會有我們看到 Vite 仿佛又做了很多事情,因為 Vite 能夠去加載 .ts/.vue/.svelte 等文件, 它整合了很多插件去做這些轉化工作,將所有的資源都轉化成瀏覽器可識別的 js 的方式去導入,將 css 文件經過包裝,轉化為一個 js 文件等等。
剩余的就是原文件中的內容替換,因為類似于像第三方包中的資源沒辦法直接引入,需要做一層替換,例如一下代碼就被轉化成了這樣。
在編譯的時候需要去替換我們實際寫代碼的地址,去讓瀏覽器加載,然后為了不讓瀏覽器加載文件太多,還要將第三方包導成一個模塊,然后還有熱更新功能(這部分功能稍微復雜一些)。并且為了能夠在生產環境打包(Tree shaking / 壓縮啊,等等之前常規的優化),使用了 Rollup ,不僅提供了 ESM 的打包方式,以及你需要的其他模塊化方式(umd/amd/cmd/iife)。
因此核心是簡單的,但是相關的生態想要好用,卻是要花大量的精力,Vite 團隊也是花了大力氣去解決了周邊的生態問題,各種插件的適配啊等等。
首創的ESM
而首次提出利用瀏覽器原生ESM能力的工具并非是Vite,而是一個叫做Snowpack的工具(可以看我這篇文章 《模塊化系列》snowpack,提高10倍打包速度。)。前身是@pika/web,從1.x版本開始更名為Snowpack。
Snowpack在其官網是這樣進行自我介紹的:“Snowpack是一種閃電般快速的前端構建工具,專為現代Web設計。它是開發工作流程較重,較復雜的打包工具(如Webpack或Parcel)的替代方案。Snowpack利用JavaScript的模塊化方式(稱為ESM)來避免不必要的工作并保持流暢的開發體驗”。
為此,Pika團隊開發并維護了兩個技術體系:構建相關的Snowpack和造福大眾的Skypack。其中 skypack 上還有很多特殊處理過的 ES Modules 形式的包(例如 React 等)直接用來調用,由于那些包原先是不支持 ES Modules 形式,他們單獨維護了 ES Modules 版本。
看完了 ES Modules 的現狀以及 Vite 的本質,我們就再來把模塊化來回顧一下,這樣整個時間線就完整了以及我們的開發方式變化到現在,Web 真的做出了巨大的努力。
模塊化簡史
把時間回退到2006年,這個時候 「jQuery」 剛呱呱落地,那個時候雖然沒有模塊化,使用 jQuery 相比傳統那樣寫已經提高極大的速度,當然雖然已經很方便了,單還是阻擋不了愛研究的程序員們。
在2009年的時候 「CommonJS」 誕生了,但是 「CommonJS」 由于有兩個重要問題沒能得到解決,所以遲遲不能推廣到瀏覽器上。(1.由于外層沒有 function 包裹,被導出的變量會暴露在全局中。2.在服務端 require 一個模塊,只會有磁盤 I/O,所以同步加載機制沒什么問題;但如果是瀏覽器加載,一是會產生開銷更大的網絡 I/O,二是天然異步,就會產生時序上的錯誤。)中間百家爭鳴(「AMD、CMD、UMD」)一直到2016年5月,經過了兩年的討論,ECMAScript 6.0 終于正式通過決議,成為了國際標準。在這一標準中,首次引入了 import 和 export 兩個 JavaScript 關鍵字,并提供了被稱為 「ES Module」 的模塊化方案。在 JavaScript 出生的第 21 個年頭里,JavaScript 終于迎來了屬于自己的模塊化方案。而在這期間想要使用模塊化,只能通過打包工具來解決。
有了標準之后,也不是能立馬讓所有設備都支持 「ES Module」 因為瀏覽器的推進是一個漫長的過程,不像服務端,如果做一個升級,只需要對服務端升級,而瀏覽器的升級伴隨著電腦/手機等一系列的因素,因素非常不可控,因為用戶總是可以有多種多樣的選擇,「ES Modules(ESM)」 是 JavaScript 官方的標準化模塊系統,而它這一走,卻在標準化的道路上已經花費了近 10 年的時間。在2018 年 5 月 Firefox 60 發布之后,所有的主流瀏覽器就都支持 「ESM」 了。直到現在,「ES Module」 還并不能真正地用在生產環境使用,還是需要轉化成以舊的方式(非ESM方式)。
寫在最后
當回答完這個問題的時候,不禁會想,前端的發展過程中卻是會有一些新瓶裝舊酒的東西,然后神話它,然后讓小白覺得它很高大上,讓人懼怕,然后大佬就會覺得這個東西很簡單,也不愿意去拆解它,是否我們需要轉化一些思考,當我們講一個東西的時候,剝離那些高大上的詞匯,做一些更加親民的解釋?當然我不否則這些新的工具帶來的便利以及背后的付出,但是親民是否也是一種方式,或許會變得更加美好?答案我也不得而知,本文只是作出了自己的一個思考,如有錯誤請大家批評指出。
參考
https://segmentfault.com/a/1190000039370642