webpack&React 性能优化

关于 Webpack + React 的性能优化

这篇文章很早就想写了,但是由于工作太忙,一直挤不出时间。正好趁月底挤干货的时间弄出来一篇。
由于本文内容是作者自互联网收集 + 实践与发散思维得出,故可能随时会更新修改,为了方便读者追本索源,转载请保留头部,谢谢
本文链接

另: 本文不是新手教程,关于 WebPack 如何入门配置、React Jsx 的Loader 等,请移步这里: 使用Jsx 或者 优化开发-Webpack & Jsx

先看一下最基础 Webpack 配置:

module.exports = {
    entry: 'entry.jsx',
    output: {
        path: path.join(__dirname, '/dist'),
        filename: 'bundle.js'
    },
    resolve: {
        extensions: ['', '.js', '.jsx', '.scss']
    },
    module: {
        loaders: [
            {
                test: /\.jsx?$/,
                exclude: /(node_modules|bower_components)/,
                loader: 'babel',
                query: {
                    presets: ['react', 'es2015']
                }
            },
            { test: /\.css$/, 'style!css' },
            { test: /\.scss$/, 'style!css!sass?sourceMap'},
        ]
    }
}

文件结果

  • bundle.js : 852kb.

心想并没有什么复杂的代码,为什么有852kb!

目前情况: Webpack + react 文件打包出来过大,动则 几百k 上兆。
原因分析:

  • 在使用 import css 的时候,Webpack Css 直接作为模块打包到js中。
  • 所有Js 模块 + 依赖都会打包到一个文件,导致文件很大。
  • React、React-dom 文件过大

解决方案:

  1. 分离 css 文件,将css 单独打包。

     //使用 ExtractTextPlugin 插件,将css 打包进一个文件
     plugins: [
         new ExtractTextPlugin("bundle.css"),
     ],
    
     //同时需要在 loader 里加上方法,如下
     { test: /\.css$/, loader: ExtractTextPlugin.extract('style-loader', 'css-loader') },
     { test: /\.scss$/, loader: ExtractTextPlugin.extract('style-loader','css!sass?sourceMap')},
    

    此时看下文件大小,变成:

    1. bundle.css - 56kb
    2. bundle.js -796kb

    好像作用还不是很大… - -!

  2. 那么执行第二步 ,公用JavaScript 模块分离

    如果文件 file1 使用了 a 模块, 文件 file2 也使用了 a 模块,那么这个模块就可以认为是公用模块,当然这个数量也可以自己定义,可以使用 CommonsChunkPlugin 分片插件来分离。

     //同样是插件
     new webpack.optimizes.CommonsChunkPlugin('vendor',  'vendor.js')
    

    此时看下效果,文件变成:

    1. bundle.css - 56kb
    2. bundle.js -760kb
    3. vendor.js -36kb

    移出了 36kb,效果不是很明显。

    最好是把 React、React-dom 这种移到 vendor.js 中让他去缓存。

     //修改 entry 为:
     entry: {
         app: path.resolve(__dirname, 'entry.jsx'),
         vendor: ['react', 'react-dom']
     },
    

    变成:

    1. bundle.js - 16kb
    2. vendor.js - 780kb
  3. 压缩 JavaScript 代码

    通过 UglifyJsPlugin 插件

    new webpack.optimize.UglifyJsPlugin({
    output: {
    comments: false, // remove all comments
    },
    compress: {
    warnings: false
    }
    })

    压缩后,文件有明显瘦身:

    1. bundle.js -16kb
    2. vendor.js -750kb

    但是还是不太明显, 原因可能是 react、react-dom 本身就是min 状态,在压缩一遍也小不了多少。

  4. 那么就从 react 上入手,发现react 里面存在很多注释,警告等,是一个开发版本。那么如何切换成生产版本呢

    通过 webpack.DefinePlugin 的process.env 来切换成生产版本

     new webpack.DefinePlugin({
         'process.env': {
             NODE_ENV: JSON.stringify(process.env.NODE_ENV),
         },
     }),
    

    当然,这里的process.env.NODE_ENV 也可以直接换成 production,就不用在 build脚本里赋值了,如果按上面的写法,build 里需要赋值:

     "build": "set NODE_ENV=production&&webpack -p --progress --colors"
    

    注意: 这里是 windows的写法,如果是 mac、linux 需要这样写 ——

     NODE_ENV=production webpack -p --progress --colors
    

    看一眼,这个影响最大,编译完成后:

    1. bundle.js -16kb
    2. vendor.js -144kb
  5. 上面四条已经差不多解决了文件过大的问题,但是还有童鞋发现,编译速度好慢.. 为什么?

    编译速度慢是因为项目中引用了很多的模块,这些模块又互相依赖, webpack 去处理依赖关系的时候, 要去 npm中搜索, 硬盘搜索很占用资源。所以可以通过 alias 配置来解决

     var node_modules = path.resolve(__dirname, 'node_modules');
     var pathToReact = path.resolve(node_modules, 'react/dist/react.min');
    
     resolve: {
         alias: {
             'react': pathToReact
         }
     },
    

    这样等于直接为 webpack 指定了目录,上述只是配置了 react , 如果需要,可以酌情配置其他库。

注: 上述所有插件,都需要 npm install 。

写在最后

优化了这么多,还有没有优化的空间?当然有。

  • 服务端渲染
  • 首屏优化
  • 异步加载模块
  • ….
  • 还有很多

代码在这里: https://github.com/zhukejin/WebPack-Demo

公司即将倒闭,求一个工作机会。

如何联系我?点击此处发送邮件:To:[email protected]