使用craco對cra專案進行構建優化
修改CRA專案的配置
使用create-react-app
建立的專案預設是無法修改其內部的webpack配置的,不像vue-cli
那樣可以通過一個配置檔案修改。 雖然有一個eject
命令可以是將配置完全暴露出來,但這是一個不可逆的操作,同時也會失去CRA
帶來的便利和後續升級。
如果想要無 eject 重寫 CRA 配置,目前成熟的是下面這幾種方式
- 通過 CRA 官方支援的
--scripts-version
引數,建立專案時使用自己重寫過的 react-scripts 包 - 使用 react-app-rewired + customize-cra 組合覆蓋配置
- 使用 craco 覆蓋配置
這裡我選擇的是craco
安裝
- 安裝依賴
yarn add @craco/craco
複製程式碼
- 修改pacage.json中的命令
{
"scripts":{
"start": "craco start",
"build": "craco build",
"test": "craco test"
}
}
複製程式碼
在根目錄建立craco.config.js配置檔案
/* craco.config.js */
module.exports = {
// ...
webpack: {},
babel: {},
}
複製程式碼
基礎的配置到此完成了,接下來是處理各種配置的覆蓋,完整的 craco.config.js 配置檔案結構,可以在 craco 官方的文件中詳細查詢:Configuration File 。
注意! 目前的craco最新版本v6.4.3僅支援cra4建立的專案
構建體積分析
首先引入了webpack-bundle-analyzer 這個外掛來分析一下構建產物的組成
/* craco.config.js */
const { BundleAnalyzerPlugin } = require('webpack-bundle-analyzer');
module.exports = {
webpack: {
plugins: [
new BundleAnalyzerPlugin({
analyzerMode: 'server',
analyzerHost: '127.0.0.1',
analyzerPort: 8888,
openAnalyzer: true, // 構建完開啟瀏覽器
reportFilename: path.resolve(__dirname, `analyzer/index.html`),
}),
],
}
}
複製程式碼
在使用yarn build
命令打包後,就可以得到一個分析圖,包含了每個chunk的組成部分。
可以看到這裡專案的包體積高達24M,有非常多的重複檔案被打包。
程式碼拆分,減少重複打包
由於使用了懶載入,每個頁面都對應一個獨立的chunk檔案。有些使用比較頻繁的庫,會被重複打包進每個chunk中,增加了很多體積。這裡使用 SplitChunksPlugin來將這些庫拆成一個單獨的chunk。
在craco
中可以通過configure
屬性拿到webpack
的配置物件,對其進行修改來配置,將重複的包拆分出去。
經過對圖的分析,發現jsoneditor
,echarts
,antv
等庫對包體積的影響比較大,所以將他們拆分出去。 除了將重複打包的內容拆分之外,我們還可以將專案的基本框架也提取到一個單獨的檔案 base.js 中,該檔案包含了所有網頁的基礎執行環境。(為了長期快取 base.js 檔案)
webpack: {
plugins: [/** */],
configure: (webpackConfig, { env: webpackEnv, paths }) => {
webpackConfig.optimization.splitChunks = {
...webpackConfig.optimization.splitChunks,
cacheGroups: {
base: {
// 基本框架
chunks: 'all',
test: /(react|react-dom|react-dom-router)/,
name: 'base',
priority: 100,
},
jsoneditor: {
test: /jsoneditor/,
name: 'jsoneditor',
priority: 100,
},
echarts: {
test: /(echarts)/,
name: 'echarts',
priority: 100,
},
g2: {
test: /@antv/,
name: 'g2',
priority: 100,
},
commons: {
chunks: 'all',
// 將兩個以上的chunk所共享的模組打包至commons組。
minChunks: 2,
name: 'commons',
priority: 80,
},
},
};
return webpackConfig;
},
}
複製程式碼
將它拆分出去後,包體積直接減少到了7.61M,提升顯著。
按需載入大體積的庫
從優化後的分析圖中我發現了一個體積很大的庫BizCharts
,而專案中這個庫實際上只使用過不多的幾個元件.
這種情況下,可以通過修改引入方式來進行按需引入。
import { Chart, Axis, Legend, Tooltip } from 'bizcharts';
// 改為手動按需引入
import Chart from 'bizcharts/lib/components/Chart'
import Axis from 'bizcharts/lib/components/Axis'
import ......
複製程式碼
手動修改所有的引入非常的麻煩,這時可以通過babel外掛來幫我們在構建時修改。
babel-plugin-import
這個外掛原本是用來給antd按需引入的,但在這裡我們也能用於其他的庫
babel: {
plugins: [
[
'import',
{ libraryName: 'bizcharts', libraryDirectory: 'lib/components' },
],
],
}
複製程式碼
構建速度優化
HardSourceWebpackPlugin
外掛可以為模組提供中間快取。首次構建時間沒有太大變化,但是第二次開始,構建時間大約可以節約 80%。
在我的專案中,一開始的構建的速度為26s,配置完外掛生成快取後為15s,節約了60%多的時間。
附上配置
// craco.config.js
const path = require('path');
const CracoLessPlugin = require('craco-less');
const { BundleAnalyzerPlugin } = require('webpack-bundle-analyzer');
const WebpackBar = require('webpackbar');
const HardSourceWebpackPlugin = require('hard-source-webpack-plugin');
const env = process.env.REACT_APP_ENV;
module.exports = {
webpack: {
plugins: [
new BundleAnalyzerPlugin({
analyzerMode: env !== 'development' ? 'server' : 'disabled',
analyzerHost: '127.0.0.1',
analyzerPort: 8888,
openAnalyzer: true,
reportFilename: path.resolve(__dirname, `analyzer/index.html`),
}),
new WebpackBar({
profile: true,
color: '#fa8c16',
}),
new HardSourceWebpackPlugin(),
],
alias: {
layouts: path.resolve(__dirname, './src/app/layouts'),
containers: path.resolve(__dirname, './src/app/containers'),
components: path.resolve(__dirname, './src/app/components'),
utils: path.resolve(__dirname, './src/utils'),
routers: path.resolve(__dirname, './src/routers'),
},
configure: (webpackConfig, { env: webpackEnv, paths }) => {
webpackConfig.externals = {
'ckeditor5-custom-build': 'ClassicEditor',
};
webpackConfig.optimization.splitChunks = {
...webpackConfig.optimization.splitChunks,
cacheGroups: {
base: {
// 基本框架
chunks: 'all',
test: /(react|react-dom|react-dom-router)/,
name: 'base',
priority: 100,
},
jsoneditor: {
test: /jsoneditor/,
name: 'jsoneditor',
priority: 100,
},
echarts: {
test: /(echarts)/,
name: 'echarts',
priority: 100,
},
g2: {
test: /@antv/,
name: 'g2',
priority: 100,
},
commons: {
chunks: 'all',
// 將兩個以上的chunk所共享的模組打包至commons組。
minChunks: 2,
name: 'commons',
priority: 80,
},
},
};
return webpackConfig;
},
},
babel: {
plugins: [
[ // antd 的按需載入用和自動引入樣式檔案
'import',
{
libraryName: 'antd',
libraryDirectory: 'es',
style: true,
},
],
// bizcharts的按需載入
['import', { libraryName: 'bizcharts', libraryDirectory: 'lib/components' }, 'biz'],
],
},
plugins: [
{ // 修改antd主題
plugin: CracoLessPlugin,
options: {
lessLoaderOptions: {
lessOptions: {
math: 'always',
modifyVars: {
'@primary-color': '#1890ff', //主題顏色
},
javascriptEnabled: true,
},
},
},
},
],
};
複製程式碼
總結
這次的優化主要是針對減小構建產物體積的,體積從24M -> 6.8M左右,提升還是非常大的。
通過了程式碼分割的方式減少庫被重複打包,以及按需載入一些很大的庫,同時通過一些快取的外掛提升了構建速度。
最後
如果你覺得此文對你有一丁點幫助,點個贊。或者可以加入我的開發交流群:1025263163相互學習,我們會有專業的技術答疑解惑
如果你覺得這篇文章對你有點用的話,麻煩請給我們的開源專案點點star:http://github.crmeb.net/u/defu不勝感激 !
PHP學習手冊:https://doc.crmeb.com
技術交流論壇:https://q.crmeb.com
- 遵循Promises/A 規範,深入分析Promise實現細節 | 通過872測試樣例
- 80 行程式碼實現簡易 RxJS
- 前後端分離專案,如何解決跨域問題?
- springboot中攔截並替換token來簡化身份驗證
- 15 行程式碼在 wangEditor v5 使用數學公式
- Java執行緒池必知必會
- EdgeDB 架構簡析
- TS 型別體操:圖解一個複雜高階型別
- 基於babel的埋點工具簡單實現及思考
- 使用craco對cra專案進行構建優化
- Netty核心概念之ChannelHandler&Pipeline&ChannelHandlerContext
- 理解python非同步程式設計與簡單實現asyncio
- Mycat 作為代理服務端的小知識點
- 一文吃透 React Expiration Time
- 前端模組化詳解
- Java必備主流技術流程圖
- 【建議使用】告別if,Java超好用引數校驗工具類
- MySQL模糊查詢再也不用like %了
- Java 8 的Stream流那麼強大,你知道它的原理嗎
- Vue SEO的四種方案