San CLI 4.0 升级指南
San CLI 歷經多個版本迭代,目前已經進入 4.0 版本,增加 webpack5 支持、優化配置機制等,本文會對升級經驗做出總結,期望給讀者帶來一些啟發。
前言
San CLI 更新到 3.0 版本時,已從最初的簡單腳手架功能逐步增加了構建命令、插件化、圖形化的能力,其功能已經可以滿足大部分的業務需求。但在一些特殊場景,其表現仍有待提升,例如配置的修改:San CLI 默認對 CSR 的工程支持較好,但在業務中遇到 SSR 架構的工程時,則需要在 San CLI 默認配置的基礎上增加較多配置,3.0 提供的配置修改能力需要對默認規則逐一進行覆蓋,對于業務來說還是比較繁瑣且不夠靈活的。在實際的使用過程中,我們也發現對于一些內置的命令,如 command、 plugin 等命令,使用頻率較低,無法達到按需安裝,同時新增命令時,使用方式略顯復雜。隨著社區工具的升級,San CLI 內部也需要不斷的更新升級,基于此我們在 4.0 版本對 San CLI 進行了整體功能架構的調整,主要的目標就是提升工具的靈活性及構建性能。
關于 San CLI 的功能介紹可以參考以往公眾號文章
San CLI 4.0 升級
San CLI 4.0 的主要升級包括兩部分,第一個就是提升靈活性,為此對整體架構進行調整,以實現命令的按需安裝,更靈活的配置,提升整體的擴展性;第二個則是針對構建性能的優化,提升用戶的使用體驗。接下來將詳細介紹這兩點。
1 架構變化
San CLI 的構建能力主要基于對 webpack 的封裝,我們知道,大型項目的 webpack 的配置通常是比較復雜的,集齊一些優化方案也比較耗費時間,而 San CLI 內置了 webpack 常用的配置及優化方案,可以大大簡化用戶的使用,并在此基礎上提供了 init(項目創建)、build(生產環境構建)、 serve(本地調試)三個核心命令,除此之外,內置的 command 、plugin 、inspect 命令可以提供自由擴展命令、插件及查看配置能力,用戶可以定制屬于自己的前端開發的工具集,San CLI 3.0 的架構如下圖所示:
San CLI 4.0 升級后的架構,如下圖所示:
為提升工具的靈活性,架構的調整主要包括以下幾點:
- 精簡命令,按需安裝 所有功能及插件都以獨立 npm 包存在;內置命令及擴展命令都是按照統一命名規范加載,并從 之前的san-cli-service 包解耦,可以實現獨立安裝升級,內置命令由之前的 7 個精簡為 3 個主要命令,其余命令可通過安裝擴展。
- 配置解耦,獨立升級 內置的構建配置由 san-cli-config-webpack生成,統一通過插件生成和擴展,外部可以通過加載插件或配置包的形式擴展配置,并且將 webpack 啟動包基于事件機制進行重構,提升復用性。
- 統一擴展方式 San CLI 配置都是通過插件進行修改,內外邏輯統一;規定三種類型的擴展:san-cli-xxx自定義命令,san-cli-plugin-xxx 用于修改 San CLI 自身配置, san-cli-ui-xx 增加 San CL UI 可視化界面插件
1.1 命令 / 插件擴展
San CLI 有三種插件擴展的方式:
- 第一種是命令的擴展。新增的自定義命令,只需符合包及 yargs 的命令規范,即可集成到 SanCLI,安裝即可使用,無需采用之前的命令式安裝。自定義命令包導出的變量格式如下所示:
- 第二種是可修改 webapck 配置的 service 插件。同樣需要符合包命名規范,并導出統一字段:插件 id 和實際執行函數,通過webpack-chain 的語法修改默認配置。在 4.0 中增加了插件的配置映射 pickConfig, 將插件的配置項與 SanCLI 配置文件中的配置項隔離,使得插件的使用更純粹。插件包導出的變量格式如下所示:
- 第三種則是用于 San CLI UI 可視化界面的插件,在符合包命名規范的基礎上可根據提供的 api 創建不同類型的可視化部件.
1.2 配置機制
San CLI 3.0 內默認支持 CSR 工程的打包,webpack 相關的 loader 及 rules 等均在 san-cli-service 包內置,在執行 san serve/build 命令構建時,統一通過 service 生成,整個流程對用戶是透明的,用戶可以快速開啟一個 San 的工程,但整個配置的生成是在 Service 內部流轉,對開發者來說只能通過 提供的 webpack-chain 覆蓋修改,如果遇到需要對構建流程有較大改動時,配置較多且繁瑣,因此需要更加靈活的控制內置配置的生成,下圖是配置升級前模塊調用關系圖:
如上圖所示,配置升級前所有的 loader、 rules 等 webpack 配置都在 service 內部調用,開發者可以通過增加 San CLI 的 plugin 進行修改,或者在配置文件中通過函數對最終生成的 webpack 配置的 JSON 對象進行修改。內置的 san-cli-config-webpack 的配置是完全執行完畢,即使自定義的構建配置可能并不需要,甚至在最后需要手動覆蓋。整個配置的生成流程:
- getWebpackConfig 調用 getWebpackChainConfig 生成 chainConfig ,同時得到san-cli-config-webapck 內置的配置
- getWebpackChainConfig 內依賴san-cli-config-webapck 內的函數 createChainConfig 創建 chainConfig ,加載san-cli-config-webapck 內置的配置
- 執行 webpackChainFns 內的所有函數,應用 plugin的插件擴展修改配置
- 回到 getWebpackConfig 繼續執行 webpackRawConfigFns 內一些對 config直接修改的方法
- 調用 san-cli-config-webapck 內的函數 createDevServerConfig,合并傳入的devServer 配置和默認配置
在配置升級后,所有的內置的 webpack 相關配置都是以 plugin 方式存在,統一了內外部配置的修改方式;并且插件以資源類型進行拆分,加載配置時提供了每個插件的開關,用戶可以通過傳入插件的配置來關閉對應的插件;與此同時為提升同一類型配置的復用性,在 San CLI 的配置文件內增加了 extends 關鍵字,可以批量增加配置包或者配置插件,更多細節可查看 san-cli-config-webpack 配置包,升級后的模塊調用關系如下如所示:
配置拆分后,移除了對 san-cli-config-webapck 創建 webpackChain 的依賴,san-cli-config-webapck 僅作為配置包加載,不參與 service 流程的執行。調用 api.getWebpackConfig 生成 webpack 配置流程:
- getWebpackConfig 調用 getWebpackChainConfig 生成 chainConfig
- 在getWebpackChainConfig 內通過 new Config 生成 webapckChain 的實例。
- 執行webpackChainFns 內的所有函數,應用 plugin 的插件擴展修改
- 回到 getWebpackConfig 繼續執行 webpackRawConfigFns 內一些對 config 直接修改的方法
- 取得 san-cli-config-webapck內的函數 devServerOptions,在 service 內部做合并
2 性能提升
San CLI 4.0 升級的第二個部分就是對構建性能的優化,將內置的 webpack 版本由 4 升級到 5。Webpack5 甩掉了一些歷史包袱,并做了一些優化,進一步提升了 San CLI 的構建體驗。關于 webpack5 升級的文章有很多,這里我們僅介紹升級后為 San CLI 增加的一些新特性。
2.1 新特性與效果
Webpack5 升級官方有一些關于構建性能的指導,比如 loader 設置 exclude 去掉不包含的模塊,精簡 loader/plugin 的數量、應用緩存等,升級的過程就是不斷的修改、調試、運行的過程,不再詳述,我們簡要總結下在 San CLI 內部經驗證保留的功能:
首先是 San CLI 4.0 內默認開啟的能力(以下效果數據均基于 San CLI 創建的默認 demo 測試產生):
- Pollyfill 按需加載:Webpack5 移除了 node 相關的依賴,結合我們實現的 pollyfill 按需加載方案,其vendor 的體積減少 5.3%(19.62kb)
- Cache:Webpack5 的構建緩存能力,在生產環境關閉,開發環境開啟且默認使用memory 緩存,在 San CLI 中指定了緩存到文件系統(filesystem),開發環境非首次啟動可以減少78.14%,增量構建減少 7.66%
- Asset module:Webpack5 的資源處理模塊,可以替換 url-loader、file-loader,以減少 loader 的數量,demo 對比來看沒有明顯的提升(demo 工程較小),但loader 的數據量的減少對一些大型工程打包的速度會有一定的影響
以上都是在 San CLI 內默認開啟的功能,接下來介紹下選擇開啟的功能:
- Esbuild-loader:開啟后,在開發環境替換 babel-loader,首次減少 22.25%;增量構建減少31.17%;生產環境替換 terser 對 js 進行壓縮 ,構建速度有所提升(減少 34%),但是會導致包大小略有增加
- Thread-loader:多進程打包,只應用在生產環境,開啟也消耗時間(600ms)因此推薦只在大型項目時開啟,默認關閉
- RuntimeChunk:Webpack5 支持拆分運行時 chunk,推薦多入口情況下選擇開啟,開啟后體積略有降低,配合splitChunks 進一步可以降低入口 bundle 的大小
- Dlls 分包預編譯:引入后對構建流程有所改造,通過 demo的測試,僅在開發環境增量構建速度有所降低,相較于對產出的影響,在 San CLI 內部默認不應用
- optimization.moduleIds:Webapck5 新增的文件生成的優化,San CLI 內默認設置為deterministic 以減少文件的 hash 修改頻次,有利于緩存
2.2 升級問題總結
在升級的過程中,我們遇到的問題主要有以下兩類:
持久化緩存
webpack5 可指定緩存到文件系統,這在本地開發環境下,可以極大提升構建速度。
{
cache: {
type: ‘filesystem’
}
}
精簡 plugin
webpack5 提供了一些配置和功能,可以替代一些 loader/plugin 的使用,我們知道 loader/plugin 的數量在一定程度上會影響構建的速度,例如:使用 Asset module 替換 url-loader、file-loader;使用 lint 工具替換 CaseSensitivePathsPlugin 插件;使用 output.clean 的配置項替換 CleanWebpackPlugin 插件等。
按需關閉配置項
webpack5 內部新增了一些默認開啟的計算策略,但在構建時也會影響到構建的速度,可在使用時按需關閉,例如:可通過指定 module.unsafeCache = true 來關閉 webpack5 的安全緩存策略,可減少約 800ms 左右的時間;生產環境下指定 output.pathinfo=false 禁用模塊的注釋信息,僅在開發環境下啟用;注意簡化 stats 狀態信息,stats.toJSON 轉換全部信息也需要耗費一定的時間,因此在使用時推薦傳入配置 {all: false},僅提取需要的部分。寫法上注意檢查避免 export * 的寫法。
關于 esModule 的支持:webpack5 已全面擁抱 ES Module,相關的插件如:html-loader、san-loader、css-loader 等均支持 esModule 配置項,以便開啟 ES Module 的語法支持。為此,在 San CLI 內部新增了 esModule 配置項,用于一鍵開啟內置 loader 的相關配置(該配置項是在 .san 單文件構建且啟用 css modules 的必要選項)。
關于 tree shaking 失效的問題:在 webpack5 升級之前,為保證構建的一致性,在 babel 使用時引入了 @babel/plugin-transform-modules-commonjs 插件,將代碼轉換為 commonjs 后再進行處理,我們知道,webpack 的 tree shaking 是基于 ES module 的語法實現,因此在 San CLI 的默認 babel 配置中移除了該插件,推薦工程內部采用 ES module 的語法,以便更好的利用 tree shaking 減小產出體積。
San CLI 內暫緩升級的部分:盡管 webpack5 更新已有很長時間了,但其周邊的相關插件并沒有完全適配,San CLI 在升級時也遇到了相關的情況,例如依賴的 webpack-chain 包,由于其未能支持一些 webpack5 新增的 api,導致在 San CLI 內部使用時仍需要單獨處理此類配置,此類工具需要靜待社區的更新;另外,webpack-dev-server 的 4.x 版本有較多不兼容改變,為保證 San CLI 用戶的平滑升級,我們內置的 webpack-dev-server 仍考慮采用 3.x 的版本。
2.3 對業務構建性能的提升
San CLI 4.0 發布后,我們將其應用到了不同的類型的業務,性能有不同程度的提升。整體包體積均有所減小,構建速度有所提升,在不同的應用架構下趨勢相同:
- C 端的多頁應用(代碼行數約 11710)構建包體積減少約 2.7%,生產環境下構建速度提升約13.2%,開發環境尤其是非首次啟動時速度提升較明顯(約 86%)
- B 端單頁應用(代碼行數約 70582)構建包體積減少約 0.9%,生產及開發環境下構建速度均有所提升
3 功能增強
除以上提到的架構升級和內置配置的修改外,在 San CLI 4.0 上增加了以下功能。
3.1 typescript 構建支持
在 San CLI 3.0 及之前版本,默認創建 js 類型的工程。使用 San CLI 4.0 創建項目時,支持選擇 typescript 作為工程的語言類型。
在實現上主要基于 babel 的預設 @babel/preset-typescript 來支持 ts 文件的語法轉換,而語法檢測的工作默認采用 @typescript-eslint 來實現,項目創建時已默認配置,用戶也可自行配置,利用 tsc 命令或配合 vscode 插件等實現。
3.2 san 單文件構建體驗提升
在 San CLI 4.0 我們進一步優化了單文件的構建體驗,在全局安裝 san-cli 之后,只需以下兩步,即可調試一個單文件組件:
同樣的,執行 san build index.san 即可得到構建產出。
3.3 esm 構建支持
San CLI 4.0 還有一個新增的構建選項 —— 基于 esm 的本地構建。在本地調試場景下,我們更在意的是功能的快速查看和驗證,特別是在一些大型的項目中,如果本地一個小的修改需要等待幾秒鐘完成構建,這個開發體驗是很令人崩潰的,也就是說構建的速度很重要。而實際情況中,我們通常使用的本地瀏覽器的版本較新,能夠很好的支持 js 的 esnext 版本,并不需要構建中通過 babel 等工具做代碼的 es5 轉換,因此在本地構建場景下,只需要實現基于 esm 的構建即可滿足需求。
從構建工具的角度來看,隨著社區構建工具的不斷更新,出現了一些類似 esbuild 的構建工具,從上圖數據來看,esbuild 構建速度遠遠大于 Webpack。esbuild 更適合處理 js 和 ts (對比 babel )來做代碼轉換,而在本地構架的場景下,恰好可以滿足只構建 es6 以上版本,因此我們在 San CLI 內利用 esbuild-loader 來實現基于 esm 的構建功能,通過 san serve --esm 命令即可啟動,通過 demo 數據的對比來看,本地調試的啟動時間可降低 32.7%。
最后
社區的工具不斷推陳出新,我們也在持續跟進,不斷優化 San CLI 的功能,豐富 San CLI 的使用場景,以期給用戶帶來更好的使用體驗,如果有任何疑問或想法,歡迎提出 issue 或 pr 。
點擊進入獲得更多技術信息~~
與50位技術專家面對面20年技術見證,附贈技術全景圖總結
以上是生活随笔為你收集整理的San CLI 4.0 升级指南的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 基于互联网生态积累,百度Apollo智舱
- 下一篇: 双项通过|百度点石通过信通院「可信数据流