對於公司內部現有的Webpack打包流程認識後,發現因爲WebGL,threejs,pixijs等包的自己性能、體量瓶頸,致使咱們代碼進行rebuild或者HotReplacement熱更新的時候會致使速度很是慢的狀況javascript
場景大,業務複雜,代碼多致使現有開發模式有如下業務痛點:css
我最初有這個想法是看到尤雨溪尤大在Vue3.0計劃直播中用到的vite打包工具,當時介紹就說這個打包工具編譯速度極快,用的ESModule的規範,當時就產生了濃厚的興趣html
當時就想到咱們公司內部的代碼,在webpack加持下,那是一個「重」,每次跑項目的時候,個人16G內存的MBP就扛不住了,風扇很響,燙的能夠煮雞蛋,編譯時間也是很是頭疼。前端
隨後在後續的開發中,我也一直持續在關注尤大倉庫的vite代碼更新,發現他更新得比較頻繁,能夠看出尤大對於這個項目仍是有必定的投入的。java
後續關注中我又瞭解了snowpack,esbuild等半成品的工具,瞭解其中的原理後,以爲如今是合適的機會去推廣ESModule規範下的實踐,在對於前期探索階段,到底能不能給咱們開發帶來質的提高,還有待勘察。node
對於ESModule的原理起點,能夠從script
標籤的type="module"
提及:react
<script type="module"> import foo from '../foo.js'; import bar from '../bar.js' foo(bar); //... to do </script>
複製代碼
如今隨着瀏覽器的發展和技術規範的推動,當代大部分瀏覽器都已經支持在type="module"
的script
標籤下直接執行解析import
語句,在直接執行到這一步的時候,瀏覽器會自動根據目錄路徑去請求路徑下的資源,只要觸發了請求,咱們就能夠「攔截」了,把請求的assets資源截取進行處理,返回給瀏覽器執行。webpack
依照上述的技術理論,只要有一個index.js
就能夠一步一步import不停地向下收集依賴,直至最後一個依賴,依次執行,前幾年的打包工具(相似webpack)不就作了這個事嗎?固然他作的整合更加複雜和詳細,可是如今瀏覽器都已經支持了,這一步就能夠交給瀏覽器作了,咱們要作的,就是對依賴進行解析。ios
對於前期的技術調研,我看到阿里的一篇文章Webpack 打包太慢?來試試 Bundleless 吧!,當時看到這裏時,以爲跟咱們的業務場景的痛點很是類似:git
咱們內部也是依賴底層支撐,整合多方業務插件的業務架構,因爲WebGL,Threejs,pixjs過於臃腫的包而致使總體熱更新體驗很差,而sourceMap的輸出更加加劇了架構的負擔,首次的build開發體驗差勁。
對於當下ESM推廣程度的調研,發現存在一些技術問題:
由於ESM規範下的全部開發體驗都是強依賴於瀏覽器的,因此對於模塊的依賴收集,咱們也是依靠瀏覽器直接解析下列語句而作的:
import foo from '../foo.js'
複製代碼
foo文件會根據上下文去尋找路徑文件,而後直接發起請求,可是問題來了,咱們原先不都是這麼寫的嗎?
import React from 'react';
複製代碼
他會按照預期,找當前目錄下的react.js
嗎?答案固然是否認的,原來的打包器會根據require(commonJs規範)去進行映射,引入node_modules
下對應的模塊。
可是如今會報錯,瀏覽器會報如下錯誤:
考慮到瀏覽器的安全性,是不支持這樣直接找模塊引入的,而要指定具體的路徑,解決辦法有嗎?固然有
咱們在觸發import
語句以前,能夠經過轉譯成AST,重寫當前import節點路徑後,映射到咱們服務器的靜態資源目錄(vite就是這麼作的)或者直接映射到node_modules:
// 轉譯前
import React from 'react'
// 轉譯後
import React from '__Module__react';
// 路徑解析的時候替換 __Module__
import React from '../node_modules/react/entry.js'
複製代碼
解析成__Module__react
後能夠替換關鍵字,映射到真實node_module模塊,經過package.json
的main
字段(尋找主入口,此處爲例)進行lookupFiles
的操做,找到打包後的真實入口,而後直接根據模塊路徑引入。
固然,記得每一個模塊引入的時候進行緩存。
此次調研中,發現強如React,也沒有支持ESModule導出,他們給出的答覆是:The React team is working on ESM support,他們在dist打包中並無支持ESModule的導出,這也致使了你若是用ESM規範去引入React勢必會報錯,那麼現有解決方案能夠解決嗎?答案是確定的
rollup也崇尚ES模塊:
Why are ES modules better than CommonJS Modules?
ES modules are an official standard and the clear path forward for JavaScript code structure, whereas CommonJS modules are an idiosyncratic legacy format that served as a stopgap solution before ES modules had been proposed. ES modules allow static analysis that helps with optimizations like tree-shaking and scope-hoisting, and provide advanced features like circular references and live bindings.
能夠說更好的ES標準生態,更能明確將來的發展大方向,咱們能夠經過rollup在服務器啓動時進行預優化,能夠很好地優化到每一個不支持ESM的模塊。
仍是經過rollup,能夠再預啓動階段,打包一些文件,有條件的話能夠緩存(service-worker),優化下一次請求依賴,減小瀏覽器由於import語句過多而產生的請求數過多的問題。
對於如下寫法
import './index.module.less'
複製代碼
其實瀏覽器是沒法解析的,這一點咱們也能夠借鑑原來打包器的經驗,經過import一個js模塊的模式引入,經過post-css,less等處理預編譯的能力,學習相似css-loader, style-loader
相似的方式,進行style標籤的嵌入樣式,此處也能夠處理一些hash值和前綴等
我發現了一個很是好用的基於ESModule規範下的工具esbuild,能夠支持構建和轉譯代碼,而且速度極快(go語言併發高),以native代碼直接構建,構建速度也是極快的。在加載的時候,就能夠經過轉譯器進行翻譯。
咱們運用瀏覽器支持ESModule規範的原理,固然能夠享受很是快速的編譯和開發,可是隨之而來的問題就是,你開發環境的這些配置確定沒法應用到生產環境?畢竟你不能要求全部人都用ESModule支持的瀏覽器。還有一些語法是須要polyfill來解決兼容問題的。
rollup能夠支持這個操做,同時要保證在開發環境的一些rollup打包和生產環境表現是一致的,另外要注意一些babel-runtime的操做,babel應該尚未徹底支持相似的打包解析,可能請求路徑或者資源和實際會有出入。
對於一些不常變更的資源,由於都是請求,咱們甚至能夠在SW層面作一些緩存,在對於一些依賴的收集後,能夠給出一個配置字段,來配置一些須要長時間本地緩存的打包文件,直接經過SW返回,加快傳輸速度,提升開發效率
對於HTTP2提供的Header 壓縮和二進制傳輸對於咱們場景內的大模型數據傳輸慢的問題能夠有效解決?這個問題待驗證,可是不失爲一種思路,能夠進行探索,而多路複用對於咱們場景內大量模型的載入和資源的加載也確定有至關棒的優點,這個爲技術亮點,能夠進行探索發掘。
我本身跑了幾個demo,效果仍是明顯的,首先是webpack層面開發環境的:
能夠看到,首次打包的效率在demo裏面表現仍是比較明顯的,webpack的明顯慢許多,vite已經作到了無感知的開發體驗。
在最終的生產環境打包方面,二者相差無幾,webpack甚至還快一點:
其中比較具備誘惑的點就是SourceMap的功能,用ESM的話會自帶這個功能,由於每一個請求的地址都是映射到真實的文件,就不須要一些臃腫的SourceMap了,能夠直接在Source裏面搜索源文件,能夠說是很是香了。圖中由於vite會作一層對應js文件再靜態資源目錄的轉譯,本質上是不變的。
由於公司級別的項目較複雜,涉及牽扯麪比較多,對於打包的遷移成本有點大,這裏咱們依照阿里內部的落地實踐來看,效果仍是明顯的:
從阿里實踐來看,在啓動單個 bundle 時,Webpack 須要 10s 左右的時間,用 Vite (ESModule規範下)只須要 1s 左右,提高 10 倍,熱更新更是到達了毫秒級的體驗,
探索的目的就是爲了明確將來的方向,能夠說ESModule的規範化和推廣度在穩固上升的場景下,利用這些特性使用在開發中是你們所須要的,從尤大每隔幾天就提交一次修改記錄能夠看到他對這個項目也很是上心。
能夠說規範化的推動有助於前端的持續發展,這次的探索成果能夠說是頗有用,想象一下,你開發的時候,不須要再過多等待編譯和打包,而是」毫秒級「的體驗,加快你的開發效率。從前,你編譯一次2分鐘,調試一次3分鐘,一天下來,浪費在這些無用的地方的時間可能就有小時級別的,那是低效率的表現。
將來的ESM打包本質就是把webpack低效率的依賴收集解析的工做交給瀏覽器去執行,加快編譯轉換,提升效率
下一期會從簡單demo完成一個打包器,把其中涉及到的知識點鞏固一遍。