日本综合一区二区|亚洲中文天堂综合|日韩欧美自拍一区|男女精品天堂一区|欧美自拍第6页亚洲成人精品一区|亚洲黄色天堂一区二区成人|超碰91偷拍第一页|日韩av夜夜嗨中文字幕|久久蜜综合视频官网|精美人妻一区二区三区

RELATEED CONSULTING
相關咨詢
選擇下列產(chǎn)品馬上在線溝通
服務時間:8:30-17:00
你可能遇到了下面的問題
關閉右側(cè)工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營銷解決方案
Webpack 打包太慢?來試試 Bundleless

 ????一 引言

成都創(chuàng)新互聯(lián)專業(yè)為企業(yè)提供天元網(wǎng)站建設、天元做網(wǎng)站、天元網(wǎng)站設計、天元網(wǎng)站制作等企業(yè)網(wǎng)站建設、網(wǎng)頁設計與制作、天元企業(yè)網(wǎng)站模板建站服務,10年天元做網(wǎng)站經(jīng)驗,不只是建網(wǎng)站,更提供有價值的思路和整體網(wǎng)絡服務。

Webpack 最初是為了解決前端模塊化以及使用 Node.Js 生態(tài)的問題而出現(xiàn),在過去的 8 年時間里,Webpack 的能力越來越強大。

??

??

但因為多了打包構建這一層,隨著項目的增長,打包構建速度越來越慢,每次啟動都要等待幾十秒甚至幾分鐘,然后啟動一輪構建優(yōu)化,隨著項目的進一步增大,構建速度又會降低,陷入不斷優(yōu)化的循環(huán)。

??

??

在項目達到一定的規(guī)模時,基于 Bundle 的構建優(yōu)化的收益變得越來越有限,無法實現(xiàn)質(zhì)的提升。我們從另一個角度思考,webpack 之所以慢,主要的原因還是在于他將各個資源打包整合在一起形成 bundle,如果我們不需要 bundle 打包的過程,直接讓瀏覽器去加載對應的資源,我們將有可能可以跳出這個循環(huán),實現(xiàn)質(zhì)的提升。

??

??

在 Bundleless 的架構下,我們不再需要構建一個完整的 bundle,同時在修改文件時,瀏覽器也只需要重新加載單個文件即可。由于沒有了構建這一層我們將能夠?qū)崿F(xiàn)以下的目標:

  • 極快的本地啟動速度,只需要啟動本地服務。
  • 極快的代碼編譯速度,每次只需要處理單個文件。
  • 項目開發(fā)構建的時間復雜度始終為 O(1),使得項目能夠持續(xù)保持高效的構建。
  • 更加簡單的調(diào)試體驗,不再強依賴 sourcemaps 即可實現(xiàn)穩(wěn)定的單文件的 debug。

基于以上的可能性 Bundleless 將重新定義前端的本地開發(fā),讓我們重新找回前端在 10 年前修改單個文件之后,只需要刷新即可即時生效的體驗,同時疊加上前端的 HotModuleReplace 相關技術,我們可以把刷新也省去,最終實現(xiàn)保存即生效。

實現(xiàn) Bundleless 一個很重要的基礎能力是模塊的動態(tài)加載能力,這一主要的思路會有兩個:

  • System.js 之類的 ES 模塊加載器,好處是具有較高的兼容性。
  • 直接利用 Web 標準的 ESModule,面向未來,同時整體架構也更加簡單。

在本地開發(fā)過程中兼容性的影響不是特別大,同時 ESModule 已經(jīng)覆蓋了超過 90% 的瀏覽器,我們完全可以利用 ESModule 的能力讓瀏覽器自主加載需要的模塊,從而更加低成本同時面向未來實現(xiàn) Bundleless。

社區(qū)中在近一兩年也出現(xiàn)了很多基于 ESModule 的開發(fā)工具,如 Vite、Snowpack、es-dev-server 等。本文將主要分享基于瀏覽器的 ESModule 能力實現(xiàn) Bundless 本地開發(fā)的相關思路、核心技術點以及 Vite 的相關實現(xiàn)和在供應鏈 POS 場景下的落地實踐。

二 從資源加載看 Bundle 和 Bundleless 的不同

下面以大家最熟悉的 create-react-app 默認項目為例,從實際的頁面渲染資源的加載過程對比 Bundle 和 Bundleless 的區(qū)別。

??

??

基于 Webpack 的 bundle 開發(fā)模式

??

??

上面的圖具體的模塊加載機制可以簡化為下圖:

??

??

在項目啟動和有文件變化時重新進行打包,這使得項目的啟動和二次構建都需要做較多的事情,相應的耗時也會增長。

基于 ESModule Bundleless 模式

??

??

從上圖可以看到,已經(jīng)不再有一個構建好的 bundle、chunk 之類的文件,而是直接加載本地對應的文件。

??

??

從上圖可以看到,在 Bundleless 的機制下,項目的啟動只需要啟動一個服務器承接瀏覽器的請求即可,同時在文件變更時,也只需要額外處理變更的文件即可,其他文件可直接在緩存中讀取。

對比總結(jié)

??

??

Bundleless 模式可以充分利用瀏覽器自主加載的特性,跳過打包的過程,使得我們能在項目啟動時獲取到極快的啟動速度,在本地更新時只需要重新編譯單個文件。下面將分享如何基于瀏覽器 ESModule 的能力實現(xiàn) Bundleless 的開發(fā)。

三 如何實現(xiàn) Bundleless

如何使用 ESModule 模塊加載

實現(xiàn) Bundleless 的第一步是要讓瀏覽器自主加載對應的模塊。

使用 type="module" 開啟 ESModule


利用 import-maps 支持 bare import

分享一個在 chrome 中已經(jīng)實現(xiàn)了的 import-maps 的標準 ,可以讓我們直接用 import React from 'react' 這樣的寫法,未來我們可以利用此能力實現(xiàn)線上的 Bundleless 部署。




以上我們介紹了瀏覽器中原生的 ESModule 是如何使用的。面向本地開發(fā)的場景,我們只需要啟動一個本地的 devServer 承載瀏覽器的請求映射到對應的本地文件,同時動態(tài)地將項目中 import 的資源路徑指向我們的本地地址,即可讓瀏覽器直接加載本地的文件,比如可以使用下面的寫法,將入口 JS 文件直接指向本地的路徑,然后 devServer 再攔截相應的請求返回對應的文件。



如何加載非 JS 的文件資源

通過 ESModule 我們借助瀏覽器的能力實現(xiàn)了 JS 的自主加載,但實際的項目代碼中我們不僅僅會 import JS 文件,也會有下面的寫法:

// main.jsx 
import React from 'react'
import ReactDOM from 'react-dom'
import './index.css' // import css 文件
import App from './App' // import jsx 文件

// 使用 JSX 語法
ReactDOM.render(, document.getElementById('root'))

而瀏覽器在處理文件時是依據(jù) Content-Type 的,不關心具體的文件類型,所以我們需要在瀏覽器發(fā)起請求時,將對應的資源轉(zhuǎn)化為 ESModule 格式,同時設置對應的 Content-Type 為 JS,返回給瀏覽器執(zhí)行,瀏覽器就會按照 JS 的語法進行解析處理,整體的流程可見下圖:

??

??

以下是 Vite 的相關實現(xiàn),在請求返回的過程中,對不同的文件進行動態(tài)處理:

??

??

如何實現(xiàn) HotModuleReplace

HotModuleReplace 能夠在我們修改代碼后,不需要刷新頁面,直接在當前場景下生效,結(jié)合 Bundleless 極快的生效速度,我們能夠?qū)崿F(xiàn)幾乎沒有延遲的保存即生效的體驗。對于 React,在 Webpack 場景下目前只能通過使用 react-hot-loader 來實現(xiàn),但這一塊受限于具體的實現(xiàn),有一些場景會存在 bug,作者也建議遷移到 React 團隊實現(xiàn)的 react-refresh,而這一塊在 Webpack 中還沒有相應的實現(xiàn)。在 Bundleless 場景下,因為我們的每個組件都是獨立加載的,所以要集成 react-refresh,我們只需要在瀏覽器請求返回時在文件的頂部和底部加上相應的腳本即可完成集成。

??

??

要完整的實現(xiàn) HotModuleReplace 會比上面畫得更加復雜,還需要有一套依賴分析機制來判斷當一個文件發(fā)生變更之后要替換哪些文件以及是否需要 reload。在 Bundleless 的場景下,因為不再需要打包為一個完整的 bundle,同時我們也能更加靈活地對單個文件進行修改,這一塊相關的實現(xiàn)會更加容易。

以下是在 Vite 中的相關實現(xiàn):

??

??

如何優(yōu)化大量請求導致頁面加載慢

Bundleless 的模式不再打包,提升了啟動的速度,但對于一些有較多外部依賴或者自身文件數(shù)量較多的模塊,需要發(fā)起大量請求才能獲取到全部的資源,這個會降低開發(fā)過程中頁面加載的時間。比如下面是直接在瀏覽器中 import lodash-es 會并發(fā)出大量的請求:

??

??

在這一塊上我們可以做相應的優(yōu)化,將外部的依賴提前打包成單個文件來減少在開發(fā)過程中由于外部依賴過多而發(fā)起過多的網(wǎng)絡請求。

在 Vite 的啟動流程中有一個 vite optimize 的過程會自動將 package.json 中的 depenencies 借助 Rollup 打包成 ES6 Module。

??

??

提前打包帶來的好處除了能夠提升頁面的加載速度,借助 @rollup/plugin-commonjs 我們能夠?qū)?commonjs 的外部依賴打包為 ESModule 的形式引入,進一步擴大 Bundleless 的適用范圍。

四 在供應鏈 POS 場景下落地實踐

我們團隊負責的供應鏈 POS 業(yè)務主要可分為面向建材家居的家裝行業(yè)和線下小店的零售行業(yè),在技術架構上采用了各個域 bundle 獨立開發(fā),然后最終借助底層的 sdk 合并為一個大的 SPA 的形式。由于項目的復雜性,在日常開發(fā)過程中,有以下的一些痛點:

  • 項目的啟動和耗時相對較長。
  • 改動后二次編譯時間長。
  • 缺少穩(wěn)定的 HMR 能力,開發(fā)過程中需要重復造場景。
  • debug 依賴 sourcemaps 能力,有時會出現(xiàn)不穩(wěn)定的情況。

基于以上的問題,借助 Vite 的相關實現(xiàn),我們對本地開發(fā)環(huán)境進行了 Bundleless 的嘗試和落地,在實驗的一些項目中對于本地的開發(fā)體驗有了很大的提升。

在啟動以及修改生效的速度上帶來極大的提升

目前已實現(xiàn)單 bundle 維度的開發(fā),打包構建速度:

??

??

Webpack

??

??

Vite Bundleless

從上面的可以看出,在啟動單個 bundle 時,Webpack 需要 10s 左右的時間,而基于 Bundleless 的 Vite 只需要 1s 左右,提升 10 倍。

??

??

整體的頁面加載時間在 4s 左右,仍然比 Webpack 的打包構建時間要短,同時從上面的視頻中也可以看到 HMR 的速度達到了毫秒級的響應,實現(xiàn)了基本無感的保存即生效。

不依賴 sourcemap 調(diào)試單個文件

??

??

落地過程中遇到的問題和解決

在實際落地過程中,遇到的問題主要是相關模塊不符合 ESModule 規(guī)范以及一些寫法上的標準化:

  • 部分模塊沒有 ESModule 的打包。
  • less 依賴 node_modules 的寫法的規(guī)范。
  • jsx 文件后綴規(guī)范。
  • babel-runtime 的處理。

部分模塊沒有 ESModule 的打包

對于沒有 ESModule 打包輸出或者輸出的錯誤的包,根據(jù)不同的類型使用不同的策略:

  • 內(nèi)部的包:通過升級腳手架,發(fā)布帶有 ESModule 的包的新版本。
  • 外部依賴:通過 issue、pull request 等形式,推動了 number-precision 等模塊的升級。
  • 同時有一些由于歷史原因無法打出 ESModule 的包可以借助 @rollup/plugin-commonjs 打包為 ESModule。

less 依賴 node_modules 的寫法的規(guī)范

@import '~@ali/pos-style-mixin/style/lst.less';  
// ~ 只在 webpack 中 less-loader 的支持,在原生的 less 中不支持

// 統(tǒng)一遷移為下面的模式
@import '@ali/pos-style-mixin/style/lst.less';

// 同時在原先的 webpack 構建中的 less-laoder 中配置 lessOptions,用于最后的打包
/*
{
loader: 'less-loader',
options: {
lessOptions: {
javascriptEnabled: true,
paths: [path.resolve(cwd, 'node_modules')],
}
}
}
*/

JSX 文件后綴規(guī)范

Vite 在運行的過程中會依據(jù)文件不同的后綴名進行對應的編譯處理,而在 Webpack 模式下我們通常會將 JSX、JS 等文件都丟給 babel-loader 進行處理,這使得有一些原本是 JSX 的文件沒有寫JSX 后綴。Vite 只會對 /\.(tsx?|jsx)$/ 的文件進行 esbuild 編譯,對于純 JS 會直接跳過 esbuild 的過程。對于這種情況我們是逐步將錯誤的原先沒有寫 JSX 的文件遷移為 JSX 文件。

babel-runtime 的處理

在使用了 babel-plugin-transform-runtime 之后,打包的輸出結(jié)果會是下面這樣:

??

??

上面所引用的 @babel/runtime/helpers/extends 是 commonjs 的格式無法直接使用,針對這個情況,有兩種解法:

1)針對內(nèi)部自己打包的模塊,可以在進行 es6 打包時添加 useModules 配置,這樣打包出來的代碼就會是直接引用@babel/runtime/helpers/esm/extends

??

??

2)針對重新打包成本較高的模塊,可以通過 Vite 的插件機制進行轉(zhuǎn)換,將 @babel/runtime/helpers 在運行時替換為 @babel/runtime/helpers/esm 可以通過 alias 配置實現(xiàn):

??

??

以上是在 Vite 開發(fā)環(huán)境的遷移過程中遇到的一些問題和處理的分享,這一塊的更大范圍的落地還在進行中。Bundleless 的落地不僅僅是為了適配 Vite 的開發(fā)模式,同時也是面向未來規(guī)范各個模塊代碼的過程,將我們的模塊進行標準的 ESModule 化,在有新的工具和思想出現(xiàn)時可以用更低成本進行落地。

五 直接使用 Bundleless 進行部署的可行性

受限于網(wǎng)絡請求和瀏覽器的解析速度,對于較大型的應用,bundle 在加載速度上還是能夠帶來較大的收益。V8 在 2018 年也給出了相關性能上的建議:在本地開發(fā)和小型的 Web 應用中使用。在今天的場景下,隨著瀏覽器和網(wǎng)絡性能的不斷提升,結(jié)合 ServiceWorker 之類的緩存能力,網(wǎng)絡加載的影響和越來越小,對于一些不需要考慮兼容性問題的場景可以進行內(nèi)部的嘗試,直接部署通過 ESModule 加載的代碼。

六 總結(jié)

本文主要分享了 Bundleless 架構下,如何提升前端的研發(fā)效率、實現(xiàn)思路以及在具體業(yè)務場景下落地實踐。Bundleless 本質(zhì)上是將原先 Webpack 中模塊依賴解析的工作交給瀏覽器去執(zhí)行,使得在開發(fā)過程中代碼的轉(zhuǎn)換變少,極大地提升了開發(fā)過程中的構建速度,同時也可以更好地利用瀏覽器的相關開發(fā)工具。

站在當前的背景下,Web 各個領域 JavaScript/CSS/HTML 相關的標準都已成熟,同時瀏覽器內(nèi)核也趨于統(tǒng)一,前端工程化的核心重點已逐步遷移到研發(fā)提效上,而 Bundleless 的模式能夠帶來長效的啟動和 HMR 的速度,是未來的一大發(fā)展趨勢。隨著瀏覽器內(nèi)核和 Web 標準的不斷統(tǒng)一,前端的代碼可以不再打包直接運行將成為可能,這將進一步提高整體的研發(fā)效率。

最后非常感謝 ESModule、Vite、Snowpack 等標準和工具的出現(xiàn),讓前端的開發(fā)體驗往前跨了一大步。


網(wǎng)站欄目:Webpack 打包太慢?來試試 Bundleless
網(wǎng)頁網(wǎng)址:http://www.dlmjj.cn/article/dpodjpg.html