React + webpack 之性能優化

React + webpack 之性能優化

一句很經典的話:沒到性能瓶頸的時候,最好不要隨意的優化。

1.性能問題

性能問題歸根到底就是項目愈來愈大,文件愈來愈複雜,致使webpack打包的bundle.js的包愈來愈大,頁面加載也就變的愈來愈慢。html

clipboard.png
clipboard.png

使用chrome 的 performance分析代碼,能夠很明顯的看到,主要的時間都花在了Evaluate script上面,但這部分我目前沒有找到解決方案,因此只能從因此js包的體積入手。react

2.基本的解決方案

1. 從webpack入手,webpack自己會有一些插件的優化方法。

1.UglifyJsPlugin 壓縮代碼的插件(這個能夠很顯著的縮小包的體積)webpack

new webpack.optimize.UglifyJsPlugin({ compress: { warnings: false } }),web

2.CommonsChunkPlugin (合併代碼)chrome

兩個用法:一個是抽取公共的包,另外一個則是把多個保重的公共依賴抽取出來npm

  1. 抽取公共包能夠優化總體包的體積,通常用在開發環境,能夠加快rebuild的速度segmentfault

  2. 抽取公共依賴能夠優化總體包的體積,便可以一次下載屢次使用,後面的包由於公共依賴的被提取,包的體積減少,能夠加快運行速度。性能優化

抽出公共代碼(能夠抽出一些公用模塊,下降整個項目但也僅僅只能減小js下載的時間,並不能減小Evaluate script的時間,而且這還會使得兩個包的整體積變大),dom

new webpack.optimize.CommonsChunkPlugin({
      names: ['vendor'],
      filename: '[name].js',
      minChunks: Infinity
    })
  1. Defineplugin工具

這個插件用來定義全局變量,在webpack打包的時候會對這些變量作替換。這裏替換成了production,
react代碼中有不少的NODE_ENV變量判斷

new webpack.DefinePlugin({ // <-- 減小 React 大小的關鍵
      'process.env': {
        NODE_ENV: JSON.stringify('production')
      }
    })

2. 從代碼層面入手

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頁面加載速度便會變得快許多。

    能夠參考另外一篇文章React-router 4 按需加載的實現方式及原理(Code Splitting)

  • 實際代碼入手
    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這個文件,直接用網頁打開就能夠了

clipboard.png

這樣就能夠分析出你究竟是什麼致使你bundle.js報如此之大了,但有一些包咱們是沒法縮減的,例如react-dom,react,可是絕大部分的包都是能夠進行縮減的.

那麼如何縮減呢?

加入你這個界面中用到了一個三方的圖形控件,例如你用了Echart,那麼這個包老是很大的,即便是最小的也有300k左右,其實你其餘的代碼可能都不到100k,那麼這300k將會很是影響你這個界面的加載速度,因此須要給這個控件作一個按需加載,這樣能夠先展現其他的這100k所展現的界面,等待其他的300k下載好了再把Echart給補上。
clipboard.png

代碼實現:

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>);
      }

3 代碼 Bundle.js

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>;
}
相關文章
相關標籤/搜索