性能問題歸根到底就是項目愈來愈大,文件愈來愈複雜,致使webpack打包的bundle.js的包愈來愈大,頁面加載也就變的愈來愈慢。html
使用chrome 的 performance分析代碼,能夠很明顯的看到,主要的時間都花在了Evaluate script上面,但這部分我目前沒有找到解決方案,因此只能從因此js包的體積入手。react
1.UglifyJsPlugin 壓縮代碼的插件(這個能夠很顯著的縮小包的體積)webpack
new webpack.optimize.UglifyJsPlugin({ compress: { warnings: false } }),
web
2.CommonsChunkPlugin (合併代碼)chrome
兩個用法:一個是抽取公共的包,另外一個則是把多個保重的公共依賴抽取出來npm
抽取公共包能夠優化總體包的體積,通常用在開發環境,能夠加快rebuild的速度segmentfault
抽取公共依賴能夠優化總體包的體積,便可以一次下載屢次使用,後面的包由於公共依賴的被提取,包的體積減少,能夠加快運行速度。性能優化
抽出公共代碼(能夠抽出一些公用模塊,下降整個項目但也僅僅只能減小js下載的時間,並不能減小Evaluate script的時間,而且這還會使得兩個包的整體積變大),dom
new webpack.optimize.CommonsChunkPlugin({ names: ['vendor'], filename: '[name].js', minChunks: Infinity })
Defineplugin工具
這個插件用來定義全局變量,在webpack打包的時候會對這些變量作替換。這裏替換成了production,
react代碼中有不少的NODE_ENV變量判斷
new webpack.DefinePlugin({ // <-- 減小 React 大小的關鍵 'process.env': { NODE_ENV: JSON.stringify('production') } })
1.首先你應該要知道code splitting這個東西,這個是代碼層面優化的根基。
code splitting,就是代碼分割,簡而言之就是代碼分割成一個個小塊,每次頁面加載時,我只須要加載那些我須要的部分(加載包的體積變小了),這樣可讓頁面加載的更快。
那麼如何實現呢?
route層面入手
route2-3中有一個叫作getComponent的方法,能夠配置按需加載route,即原來A,B,C三個界面生成一個bundle.js的包,使用了按需加載以後,會變爲一個bundle.js包加上3個chunk包,這個時候bundle.js包加上三個chunk包的總大小會比原來的bundle.js包稍微大一點,可是我想進入A界面,我只須要加載bundle.js包和A的chunk包,那麼個人A頁面加載速度便會變得快許多。
實際代碼入手
1.先學會分析代碼,分析代碼結構,分析你的包中究竟是什麼東西如此之大。
藉助工具:
npm install webpack-visualizer-plugin webpack-stats-plugin --save-dev
配置:
import: const StatsWriterPlugin = require('webpack-stats-plugin').StatsWriterPlugin; const Visualizer = require('webpack-visualizer-plugin'); plugin: new StatsWriterPlugin({ fields: null, stats: { chunkModules: true } }), new Visualizer({ filename: './statistics.html' })
正常的webpack run 以後,會在你的output的地方出現statistics.html這個文件,直接用網頁打開就能夠了
這樣就能夠分析出你究竟是什麼致使你bundle.js報如此之大了,但有一些包咱們是沒法縮減的,例如react-dom,react,可是絕大部分的包都是能夠進行縮減的.
那麼如何縮減呢?
加入你這個界面中用到了一個三方的圖形控件,例如你用了Echart,那麼這個包老是很大的,即便是最小的也有300k左右,其實你其餘的代碼可能都不到100k,那麼這300k將會很是影響你這個界面的加載速度,因此須要給這個控件作一個按需加載,這樣能夠先展現其他的這100k所展現的界面,等待其他的300k下載好了再把Echart給補上。
代碼實現:
1.npm install bundle-loader --save-dev
2.須要些這樣一個 Bundle.js,沒法點擊則代碼在最底部
3.
import EchartContainer from 'bundle-loader?lazy!echart'; import { bundle } from '../../../components/Bundle'; constructor(props) { super(props); this.Echart = bundle(EchartContainer); } render() { return ( <div> <this.Echart /> { (this.props.history.isFetching || this.props.monthly.isFetching) && <div className="spinner"> <Spinner /> </div> } </div>); }
import React from 'react'; import PropTypes from 'prop-types'; class Bundle extends React.Component { state = { // short for "module" but that's a keyword in js, so "mod" mod: null } componentWillMount() { // 加載初始狀態 this.load(this.props); } componentWillReceiveProps(nextProps) { if (nextProps.load !== this.props.load) { this.load(nextProps); } } load(props) { // 重置狀態 this.setState({ mod: null }); // 傳入組件的組件 props.load((mod) => { this.setState({ // handle both es imports and cjs mod: mod.default ? mod.default : mod }); }); } render() { // if state mode not undefined,The container will render children return this.state.mod ? this.props.children(this.state.mod) : null; } } Bundle.propTypes = { load: PropTypes.func, children: PropTypes.func }; export default Bundle; export function bundle(item) { return props => <Bundle load={item}> {Component => <Component {...props} />} </Bundle>; }