編譯速度一直是困擾開發者的頭等問題,現階段大型 Taro 項目即使在增加了 cache-loader
、thread-loader
等優化手段後,編譯耗時仍高居不下。因此在 v3.5 版本中 Taro 重點對編譯系統進行了重構,引入對 Webpack5 的支持,改善小程序 & H5 編譯時的性能與體驗。(除此之外,Taro 也正在落地對於 Vite 的支持,屆時開發者將可以自由地選擇編譯工具。)
同時,Taro v3.5 還帶來了兼容 React 18、H5 MPA 等新特性,歡迎各位同學升級試用~
一、編譯提速
爲了改善編譯性能,Taro 主要做了以下事情:
- 支持 Webpack5
- 基於模塊聯邦的依賴預編譯
- 支持使用
esbuild
壓縮 JS,使用esbuild
或@parcel/css
壓縮 CSS - 使用
@swc/register
代替@babel/register
接下來將簡單聊聊 Webpack5 與依賴預編譯,關於編譯提速的完整實現細節請參閱 RFC 文檔。
1. Webpack5
Webpack5 發佈已有兩年時間,功能足夠穩定,同時其持久化緩存、模塊聯綁、更優的 Tree Shaking 等特性都爲項目的編譯流程提供了更好的解決方案。
其中的持久化緩存功能是最重要的特性之一,能極大提升再次編譯時的速度。但同時也引入瞭如何使緩存失效的問題。
Taro 遵循 Webpack “編譯安全比編譯速度重要” 的理念,默認不開啓持久化緩存。當開發者設計好緩存策略後,強烈建議開啓持久化緩存。詳細配置請參考 mini.cache。
2. 依賴預編譯
Webpack5 另一個重要的特性要數模塊聯邦(Module Federation)。受 UmiJS mfsu 特性的啓發,可以預先把項目的 node_modules 依賴打包爲一個模塊聯邦 remote 應用,再次編譯時 Webpack 則無需再對依賴進行編譯,從而提升編譯速度。
依賴預編譯可以分爲三步:
- 收集依賴
- 打包依賴
- 打包 Module Federation Remote 應用
Taro 參考 Vite 使用了 esbuild 收集用戶使用到的第三方依賴,並分別進行打包。打包後的模塊會作爲 Webpack 的 entry,最終打包爲模塊聯邦 Remote 應用,供主應用(Host)消費。實現細節請參考 RFC 文檔。
Taro 會在小程序環境的 dev 模式下默認開啓依賴預編譯功能。首次編譯時,因爲使用了 esbuild 打包第三方依賴,所以會比普通編譯稍快。二次編譯時,Taro 能直接複用 Remote App,Webpack 只需編譯業務代碼,因此根據不同項目會有不同的編譯提速效果。
依賴預編譯的流程圖:
3. 提速效果
以 NutUI 組件示例庫爲例,分別測試 dev 與 prod 環境下編譯微信小程序的編譯提速效果:
可以看出:
- 在 dev 環境下因爲 Taro 默認開啓了依賴預編譯,因此 Webpack5 首次編譯速度比 Webpack4 稍快。而 prod 環境沒有默認開啓依賴預編譯,因此兩者速度相當(而且 Webpack5 需要寫入緩存,可能會比 Webpack4 稍慢)。
- 無論是 dev 還是 prod 環境,在完全命中緩存的最優情況下,Webpack5 的編譯速度都能得到極大提升。即使是修改源碼導致了部分緩存失效時,編譯速度仍然比首次編譯快得多。
4. 使用
舊項目升級後需要安裝 Webpack5 的相關依賴才能正常編譯,詳情請參考下文的【升級指南】部分。
簡單修改 Taro 的編譯配置即可開啓 Webpack5、持久化緩存、依賴預編譯等功能:
/** config/index.js */
const config = {
// 自定義編譯工具,可選 'Webpack4' 或 'Webpack5'
compiler: {
type: 'webpack5',
// 依賴預編譯配置
prebundle: {
enable: true
}
},
// 持久化緩存配置
cache: {
enable: true
}
}
二、兼容 React18
React 官方正式發佈了 react v18版本,帶來了 Automatic Batching、Transitions 和 Concurrent 等諸多新特性,提升了React性能。Taro 也在第一時間完成了對 React18 的兼容。
React目前存在兩種工作模式:legacy
和 concurrent
。在 concurrent 模式下,會使用 New Client API 來渲染組件。
默認情況下,Taro react 仍會在 legacy
模式下運行。簡單修改 @tarojs/plugin-framework-react
插件的配置即可啓用 concurrent
模式:
/** config/index.js */
const config = {
plugins: [
['@tarojs/plugin-framework-react', { reactMode: 'concurrent' }]
]
}
不要忘記將項目的 react 版本升級到 v18 哦
詳細內容請參考 discussions
三、支持服務端渲染(SSR)
1. 動機
與 SPA(單頁應用程序,Single-Page Application)相比,服務器端渲染(SSR)能帶來帶來更快的首屏渲染速度和更好的 SEO,因此 SSR 功能是大家期望 Taro 支持的特性之一。
2. 實現原理
Taro 在 3.1 版本提出了開放式架構的思想,讓開發者可以通過編寫插件來讓 Taro 支持一個新的平臺。
通過 Taro 插件,將 React 生態中知名的 Next.js 框架作爲 Taro 的一個新的目標平臺,以此讓 Taro 能夠支持服務端渲染(SSR)。
目前這個插件項目的地址位於:SyMind/tarojs-plugin-platform-nextjs
⚠️ 插件目前處於早期建設中,不建議用於生產環境!
3. 安裝與使用
安裝插件和 Next.js 框架。
# 使用 npm 安裝插件與 next.js
npm install tarojs-plugin-platform-nextjs next
# 使用 pnpm 安裝插件與 next.js
pnpm install tarojs-plugin-platform-nextjs next
在 Taro 項目的編譯配置中添加本插件。
const config = {
plugins: [
'tarojs-plugin-platform-nextjs'
]
}
開始嘗試它吧!
npx taro build --type nextjs --watch
四、支持多頁應用(MPA)
很多同學通過閱讀 Taro 的源碼發現,Taro 曾在 1.x 支持過多頁面應用,通過配置 multi
模式就可以開啓該特性,但是由於並沒有很好支持,也沒有相應的業務場景測試,最終並沒有在文檔中呈現。
在 2.x 發佈時,由於各種原因我們回滾了該特性,儘管開發者們依舊可以通過插件或者在項目內自定義 webpack 配置實現類似的需求,不過這依舊會在一些細節上難以處理得盡善盡美。比如需要額外配置文件拆分規則避免冗餘的代碼,對於 MPA 也並不需要taro-router
提供對於路由相關的事件方法的支持……
MPA 是不少社區開發者所追求的重要特性之一,爲此我們改寫了 taro-loader
和 taro-router
以適應該模式的個性化需求,應用該模式也只需要如下配置:
module.exports = {
// ...
h5: {
// ...
router: {
mode: 'multi'
}
}
}
需要注意的是,有很多小程序事件和方法都是基於 SPA 模式設計使用的,在 MPA 模式並不適用,所以會存在一些問題,比如由於多頁面導致 TabBar 會重複加載,App 級的生命週期會重複觸發,不支持路由動畫,生產環也需要額外配置路由映射等等,開啓該模式前需要認真考量適用場景。
五、RN 相關依賴庫由 unimodules 升級至 expo
Expo 是 React Native 生態中的重要角色,提供了非常多優秀的模塊,在 Taro 中有較爲廣泛的使用,如 expo-av、expo-camera 等,將來我們還會持續接入新的模塊。Expo 的模塊系統,由 unimodules 變更爲 expo 已有一段時日,其架構變更原因可參考文章: What’s new in Expo modules infrastructure。
Taro v3.5 及以後將使用新的模塊系統,可以通過 taro init 選擇 react-native 模板體驗。如果你使用的是 Taro 殼工程,可切換到 0.67.0-expo 分支體驗。
新老版本的 Taro 及殼工程之間混用的話,將存在不兼容情況,主要原因是存在多個版本原生依賴導致,可通過 resolution 進行版本鎖定解決,相應版本參考此處。
後續殼的工程將不再包含 unimodules 版本。舊版本升級可參考此PR。
注意:升級爲 expo 將不再支持 iOS 11,詳細內容請參考 discussions。
六、升級指南
1. 安裝 v3.5.0-beta 的 CLI 工具:
npm i -g @tarojs/cli@beta
2. 更新項目依賴
如果安裝失敗或打開項目失敗,可以刪除 node_modules、yarn.lock、package-lock.json 後重新安裝依賴再嘗試。
2.1 把 package.json 文件中 Taro 相關依賴的版本修改爲 3.5.0@beta
2.2 Breakings
-
Vue2 項目需要添加 devDenpendencies:
"@vue/babel-preset-jsx": "^1.2.4”
-
Vue3 項目需要添加 devDenpendencies:
"@vue/babel-plugin-jsx": "^1.0.6"
-
React 項目需要添加 devDenpendencies:
"@pmmmwh/react-refresh-webpack-plugin": "0.5.4", "react-refresh": "0.11.0"
-
PReact 項目需要添加 devDenpendencies:
"@prefresh/webpack": "^3.2.3", "@prefresh/babel-plugin": "^0.4.1"
2.3 重新安裝依賴
3. 使用 Webpack5
新項目在創建項目時,選擇編譯工具爲 "webpack5"
即可。
舊項目升級後需要更新依賴:
- 建議首先刪除
node_modules
、yarn.lock
、package-lock.json
。 package.json
中刪除@tarojs/mini-runner
和@tarojs/webpack-runner
依賴,添加@tarojs/webpack5-runner
依賴。- 重新安裝依賴。
- Taro 編譯配置添加
compiler: 'webpack5'
,最後開啓編譯。
最後
接下來我們會繼續對 v3.5
版本進行迭代,包括實現 H5 的依賴預編譯等。而在 v3.6
版本則會落地對 Vite 的支持,同時優化運行時的性能。
最後的最後,衷心各位感謝參與 Taro 開源共建的同學!爲了建立更加完善、更加可持續的 Taro 開源生態,突出貢獻者價值,Taro 推出了更清晰的參與機制和榮譽激勵機制,歡迎更多的同學參與進來~