編譯速度一直是困擾開發者的頭等問題,現階段大型 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 推出了更清晰的參與機制和榮譽激勵機制,歡迎更多的同學參與進來~