我作 react 開發時一般是直接用的 create-react-app。最近想分析一下一個用 create-react-app 開發的項目的打包結果,看看有沒有什麼能夠優化的地方。html
執行 npm run eject
導出配置(單向操做,不可逆)。
項目中使用的一些庫:react
"dependencies": { "antd": "^3.9.2", "axios": "^0.18.0", "echarts": "^3.8.5", "less": "^3.0.1", "moment": "^2.21.0", "react": "^16.4.2", "react-dom": "^16.2.0", "react-router-dom": "^4.2.2", }, "devDependencies": { "babel-loader": "7.1.2", "babel-plugin-import": "^1.6.5", "webpack": "3.8.1", "webpack-bundle-analyzer": "3.0.2", }
按照官網配置,使用 babel-plugin-import,在 package.json 中配置:webpack
"babel": { "plugins": [ [ "import", { "libraryName": "antd", "style": true } ] ] }
項目中直接使用:ios
import { Button } from 'antd';
create-react-app 的 webpack 已經作好配置了:git
plugins: [ ... // Moment.js is an extremely popular library that bundles large locale files // by default due to how Webpack interprets its code. This is a practical // solution that requires the user to opt into importing specific locales. // https://github.com/jmblog/how-to-optimize-momentjs-with-webpack // You can remove this if you don't use Moment.js: new webpack.IgnorePlugin(/^\.\/locale$/, /moment$/), ... ]
import React from 'react'; export default class Bundle extends React.Component { state = { mod: null } componentWillMount() { this.load(this.props); } componentWillReceiveProps(nextProps) { if (nextProps.load !== this.props.load) { this.load(nextProps); } } async load(props) { this.setState({ mod: null }); /* 使用 props.load() 返回的是一個 promise */ const mod = await props.load(); this.setState({ mod: mod.default ? mod.default : mod }); } render() { return this.state.mod ? this.props.children(this.state.mod) : null; } }
const lazyLoad = loadComponent => props => ( <Bundle load={loadComponent}> {Comp => (Comp ? <Comp {...props} /> : <Loading/>)} </Bundle> );
使用:github
// dynamic import const Demo = lazyLoad(() => import('../components/demo')); // react-router <Route path="/demo" component={Demo} />
使用工具webpack-bundle-analyzer,將打包內容轉換成可縮放的樹狀圖。web
// 安裝 yarn add -D webpack-bundle-analyzer
在 config/webpack.config.dev.js
或 config/webpack.config.prod.js
中添加:npm
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin; ... plugins: [ ... new BundleAnalyzerPlugin(), ... ] ...
默認在 127.0.0.1:8888
頁面顯示。
添加在 config/webpack.config.dev.js
後,每次 npm start
時都會彈出分析頁面。
添加在 config/webpack.config.prod.js
後,每次 npm build
時都會彈出分析頁面。
項目分析結果:
json
發現問題:axios
因爲我對 webpack 不算太熟,知道 webpack 3 中能夠用 plugin CommonsChunkPlugin
抽取公共代碼,但具體用法不甚明瞭,折騰了好久都沒有做用,終於在 antd github 的 issues 中找到答案:
plugins: [ ... new webpack.optimize.CommonsChunkPlugin({ minChunks: 2, minSize: 0, children: true, deepChildren: true, async: true }), ... ]
彷佛去掉 name
就能夠了?這一點我還沒搞清楚是爲何。
import echarts from 'echarts/lib/echarts'; import 'echarts/lib/chart/map'; import 'echarts/lib/chart/pie'; import 'echarts/lib/chart/scatter'; import 'echarts/lib/chart/effectScatter'; import 'echarts/lib/component/geo'; import 'echarts/lib/component/tooltip'; import chinaJson from 'echarts/map/json/china.json'; ... echarts.registerMap('china', chinaJson); ...
須要注意,能夠按需引入的模塊列表見 https://github.com/ecomfe/ech...