將 React 應用遷移至 Vite
前言
當下,在項目開發的過程中,對於大多數人來說,會使用 create react app 來創建 react 應用,它開箱即用,零配置,但隨着項目中代碼量的增加,你的項目構建時間也會隨之增加,開發服務啓動時間變得緩慢,代碼更改後熱更新也會變慢,可能會需要 2-5s 纔會在頁面上體現,那麼能否提高構建速度,減少開發者等待的時間呢?
如何提升構建速度?
我們可以將構建工具遷移到 Vite[1]。
Vite 是下一代前端構建工具,可以更快地構建應用程序。
Vite 的亮點
-
極速的服務啓動,使用原生 ESM 文件,無需打包!
-
輕量快速的熱重載,無論應用程序大小如何,都始終極快的模塊熱重載(HMR)
-
開箱即用,對 TypeScript、JSX、CSS 等支持開箱即用。
-
Rollup 構建,可選 “多頁應用” 或 “庫” 模式的預配置
-
通用的插件,在開發和構建之間共享 Rollup-superset 插件接口。
-
靈活的 API 和完整的 TypeScript 類型。
-
支持 React, Vue, Preact, Svelte.
創建 vite 新項目
使用以下命令創建全新的 react 應用程序。
yarn create vite my-react-app --template react
CRA 爲什麼慢?
Create react app 使用 wabpack 來打包。
webpack 打包圖如上圖所示,它將整個項目的代碼打包在一起,然後才能啓動服務。
Vite 爲什麼快?
Vite 將會使用 esbuild[2] 預構建依賴 [3]。esbuild 使用 Go 編寫,並且相比 JavaScript 編寫的 babel 打包器預構建依賴快 10-100 倍。
依賴預構建
當你首次啓動 vite
時,你可能會注意到打印出了以下信息:
Pre-bundling dependencies: (正在預構建依賴:)
react,
react-dom
(this will be run only when your dependencies or config have changed)(這將只會在你的依賴或配置發生變化時執行)
依賴預構建的目的:
-
Vite 必須先將作爲 CommonJS 或 UMD 發佈的依賴項轉換爲 ESM。
-
性能: Vite 將有許多內部模塊的 ESM 依賴關係轉換爲單個模塊,例如,
lodash-es
有超過 600 個內置模塊!通過預構建lodash-es
成爲一個模塊,我們就只需要一個 HTTP 請求了!
按需加載
Vite 通過在一開始將應用中代碼區分爲 依賴 和 源碼 兩類,改進了開發服務器啓動時間。
-
依賴 一般是那種在開發中不會改變的 JavaScript,比如組件庫,或者一些較大的依賴(可能有上百個模塊的庫),這一部分使用 esbuild 來進行預構建依賴
-
源碼 是我們開發的 JSX,CSS 或者 Vue/Svelte 組件,需要編譯後纔可以執行。同時,並不是所有的源碼都需要同時被加載(例如基於路由拆分的代碼模塊)。
vite 打包圖
如上圖所示,當瀏覽器請求時,Vite 只需要按需編譯當前屏幕使用的代碼。
緩存優化
Vite 是直接把轉換後的 ES module 的 JavaScript 代碼,給支持 ES module 的瀏覽器,讓瀏覽器自己去加載依賴,也就是把壓力丟給了瀏覽器,從而達到了項目啓動速度快的效果。在我們修改其中一個代碼模塊的時候,Vite 熱更新非常快,源碼中模塊的請求會根據 304 Not Modified
進行協商緩存,而依賴模塊請求則會通過 Cache-Control: max-age=31536000,immutable
進行強緩存,因此一旦被緩存它們將不需要再次請求。
時間對比
我拿一個 create react app 項目, 該項目包含 3 個路由頁面,14 個組件,遷移到 vite,也就是大家常說的 cra 來測試過,我們一起來對比下時間:
開發模式 CRA 12 s,vite 298 ms。Vite 開發環境是懶編譯模式, 298ms 只是啓動 devServer 的時間,不包含資源編譯,只有你用瀏覽器去請求頁面了,它纔會進行編譯,但是 CRA 是一次性把所有資源都編譯、打包了。
打包模式 CRA 15.66 s,vite 9.11 s
從 CRA 遷移到 Vite
那麼我是如何從老項目遷移到 vite 的呢?
-
首先從 package.json 刪除依賴
react-scripts
. -
在
dependencies
安裝以下依賴
"devDependencies": {
"@vitejs/plugin-react": "1.1.1",
"vite": "2.7.0"
},
- 修改 package.json 中 scripts 命令
"scripts": {
// 開發階段啓動 Vite Dev Server
"dev": "vite",
// 生產環境打包
"build": "tsc && vite build",
// 生產環境打包完預覽產物
"preview": "vite preview"
},
- 創建一個 vite.config.js 輸入以下代碼
import { defineConfig } from "vite";
import react from "@vitejs/plugin-react";
export default ({ mode }) => {
return defineConfig({
plugins: [react()],
define: {
"process.env.NODE_ENV": `"${mode}"`,
}
})
}
可以看到配置文件中默認在 plugins 數組中配置了官方的 react 插件,來提供 React 項目編譯和熱更新的功能。
-
配置別名
如果你的項目中使用到了別名,則需要做出相應修改。
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
const { resolve } = require('path')
// https://vitejs.dev/config/
export default defineConfig({
base: './',
resolve: {
alias: {
'@components': resolve(__dirname, 'src', 'components'),
'@utils': resolve(__dirname, 'src', 'utils'),
'@config': resolve(__dirname, 'src', 'config'),
},
},
plugins: [react()]
})
-
將 index.html 移動到 public 文件夾外面
-
在 index.html 刪除
%PUBLIC_URL%
//修改前
<link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
//修改後
<link rel="icon" href="/favicon.ico" />
- 在 index.html 引入入口 js 腳本
<div></div>
<script type="module" src="/src/index.jsx"></script>
- 修改 REACT_APP 開頭的 env 環境變量
REACT_APP_XXX
的環境變量,則切換爲 VITE_XXX
,假如有一個 .env
文件:
// 修改前
REACT_APP_ENV = local
// 修改後
VITE_ENV = local
- SASS
如果項目使用了 sass,則需要執行命令進行安裝:
$ yarn add -D sass
如果 scss 文件裏面引入了一些 node_modules 的 css 是使用 ~
符號的,可以做出調整:
@import '~antd/dist/antd.css';
調整爲
@import 'antd/dist/antd.css';
可以參考 issue - Cannot import CSS from node_modules using "~" pattern[4]
-
重新執行 yarn 命令,安裝依賴
-
執行
yarn start
啓動
若能夠成功啓動,那麼恭喜你,項目遷移成功了,若不能啓動,我們可以根據命令行中的提示,參照 Vite 文檔修改。
遇到問題
decorators not support
項目代碼中如果使用了裝飾器,比如 redux 提供的 connect 來綁定狀態,形如:
@connect(state => state.foo)
class Foo extends React.PureComponent {
....
}
但是 decorators 語法居然不被 vite 支持,關於這個問題,也有一個 issus,目前沒有一個好的解決辦法,只好去掉 decorators,改用常規的函數綁定了。
無法按需加載樣式文件
如果項目組使用了 antd 組件庫,本來會使用 babel-plugin-import 來自動導入組件和樣式, vite 對 babel-plugin-import 支持不那麼好,那麼就要手動修改代碼。
// 修改前
import { Button } from 'antd';
// 修改後
import Button from 'antd/lib/button';
import 'antd/lib/button/style/index.css';
也可以使用 vite-plugin-imp
'default' is not exported
有時候三方依賴項加載會出錯,例如'default' is not exported 等,這裏可以參考 issues
在實際遷移過程中,還是難免遇到一些奇怪的問題,這都是嚐鮮的代價。
小結
Vite 充分利用了瀏覽器的加載機制和緩存機制等,大大提示了研發效率,vite 雖然快,但不是所有的項目 react 項目都可以遷移成功,若有些項目的中的 npm 包並不遵循 CommonJS 的規範,那就可能遷移失敗,或者需要寫一些自定義插件來適配,所以筆者認爲不要激進地直接重構一些已有的大型項目,打包不是目的,運行纔是,若有些項目 webpack 配置特別複雜,那麼我們可以升級到 webpack5,或者開啓 webpack5 懶編譯模式 [5] 等, 這樣既能提升部分構建效率,也可以保證項目能夠穩定運行。
以上就是本文全部內容,希望這篇文章對大家有所幫助,也可以參考我往期的文章或者在評論區交流你的想法和心得,歡迎一起探索前端。
[1]Vite: https://vitejs.dev/
[2]esbuild: https://esbuild.github.io/
[3] 預構建依賴: https://cn.vitejs.dev/guide/dep-pre-bundling.html
[4]Cannot import CSS from node_modules using '~' pattern: https://github.com/vitejs/vite/issues/382
[5] 開啓 webpack5 懶編譯模式: https://juejin.cn/post/7090372816784064526
本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源:https://mp.weixin.qq.com/s/J0HO2PP8eaxTnoxx601dIA