從這個API能看到整個前端的縮影
大家好,我卡頌。
如果要從JS中找一個API作為整個前端的縮影,ESM規(guī)范中的import再合適不過了。
本文我們從這個API出發(fā),來聊聊web的發(fā)展。
web的本質(zhì)是開放
在所有JS?運行時中,web?是最開放的(緊隨其后的可能是deno?)。這一點可以從import語法的「模塊說明符」窺探一絲端倪。
在ES規(guī)范中只明確「模塊說明符是一個字符串字面量」,并沒有限制「如何解析模塊說明符」,所以「解析模塊說明符」的任務(wù)就交給了宿主環(huán)境。
在web?的HTML規(guī)范中,「模塊說明符」可以是如下形式:
- 絕對路徑的url,比如:
- 以/、./、../開頭的相對路徑,比如:
- 定義模塊名到url的映射,再以模塊名的形式引入,比如:
再引入模塊:
PS:這種方式被稱為import-maps[1],當前瀏覽器兼容性還不高:
可以發(fā)現(xiàn),這三種方式對「模塊說明符」的來源都很開放。反觀??Node.js?
?運行時,如果以包名的形式引入模塊,比如:
背后是一套指向node_modules,并最終指向npm庫的機制。npm是家私人公司,被github收購,而github被微軟收購。
所以,如果某一天國內(nèi)無法直接安裝npm包,也不必驚訝,畢竟他的背后是一家私人公司。
與之相對,web的開放讓他不會面臨這種囧境。
兼容性的迭代
web?的發(fā)展史,就是一部「新三年、舊三年、修修補補又三年」的兼容史。很多API?的兼容性問題可以通過polyfill解決。
所以,很自然的,庫作者在面對模塊規(guī)范的兼容性問題時,也想替用戶做到最好。但是,這份努力也讓代碼行為變得更撲朔迷離。
比如:在ESM?模塊中是可以引入CJS?模塊的。對于如下CJS模塊:
在同級的ESM模塊中引入,并通過解構(gòu)或者對象方法來使用hello:
為什么不能直接以「具名引入」的形式使用hello呢:
這是因為ESM規(guī)范的導(dǎo)入聲明都是靜態(tài)的,而CJS規(guī)范的導(dǎo)出是動態(tài)的,所以當ESM模塊引入CJS模塊時,在編譯時是沒法知道有哪些導(dǎo)出的。
這很符合規(guī)范,但看起來有點不符合直覺。
比如,React只提供了CJS規(guī)范的包,所以在ESM模塊中正確的引入方式是:
而大家日常開發(fā)顯然下面這種方式用的更多:
之所以這么引入不會報錯,是因為庫作者(比如vite、babel)在編譯時默默做了轉(zhuǎn)換。
為了方便開發(fā)者而違背規(guī)范,這其實是個很不好的事(類似的事還有npm、yarn的影子依賴)。
但開發(fā)者喜聞樂見的API就是好API,整個web的發(fā)展就是修修補補螺旋向上的。
bundle將長期存在
在vite橫空出世,帶來極致的開發(fā)時速度后,社區(qū)就掀起一股「bundle vs bundleless」的討論。
既然bundleless能為開發(fā)環(huán)境帶來提速,同樣的優(yōu)勢能不能也帶到生產(chǎn)環(huán)境?或者更極端點,未來前端會逐漸拋棄打包工具么?
從ESM?規(guī)范的角度出發(fā),答案是否定的。有兩個剛需現(xiàn)階段bundleless還無法解決:
- tree shaking
- ESM模塊過多,導(dǎo)致發(fā)起大量請求
所以,在未來很長一段時間內(nèi),打包工具仍會存在。
總結(jié)
在我的技術(shù)群中,經(jīng)??吹叫氯饲岸税l(fā)出感嘆:「不知道該學(xué)啥」。
究其原因,當前的前端開發(fā),主要是使用「集成了最佳實踐的各種大型框架」(比如Nuxt?、Next.js?、UmiJS...)。而這些封裝完備的框架為了降低上手門檻,隱藏了大量技術(shù)細節(jié)。
如果你也有這種迷茫,我建議你從ESM規(guī)范開始學(xué)起。
他就像一張地圖,能夠串聯(lián)起前端的方方面面。
參考資料
[1]import-maps:https://github.com/WICG/import-maps