webpack打包极限优化

webpack打包极限优化--基本介绍

1.为什么我们需要构建工具

(a)转换ES6语法

(b)转换JSX

(c)CSS前缀补全/预处理器

(d)压缩混淆

(e)图片压缩

2.初级分析-使用Webpack内置的stats

(a)stats:构建的统计信息

(b)package.json中使用status

1 "scripts": { 2 "build:stats": "webpack ---env production --json > stats.json" 3 ... 4 }

(c)Node API中使用

 1 const webpack = require('webpack');
 2 const config = require('./webpack.config.js')("production");
 3 
 4 webpack(config, (err, stats) => {
 5   if (err) {
 6     return console.error(err);
 7   }
 8   if (stats.hasErrors()) {
 9     return console.error(stats.toString("errors-only"))
10   }
11   console.log(stats);
12 })

3.速度分析-使用speed-measure-webpack-plugin

 1 const speedMeasurePlugin = require("speed-measure-webpack-plugin");
 2 const smp = new SpeedMeasurePlugin();
 3 
 4 const webpackConfig = smp.wrap({
 5   plugins: {
 6     new MyPlugin(),
 7     new MyOtherPlugin()
 8   }
 9 })
10 // 可以看到每个loader和插件执行耗时

4.体积分析-使用webpack-bundle-analyzer

1 const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
2 module.exports = {
3   plugins: {
4     new BundleAnalyzerPlugin()
5   }
6 }
7 // 构建完成后会在8888端口展示各个打包后文件的大小

webpack打包极限优化--构建速度优化

1.速度优化策略

(a)使用webpack4

(b)多进程/多实例构建

(c)分包

(d)缓存

(e)缩小构建目标

2.使用webpack4-优化原因

(a)V8带来的优化(for of替代forEach、Map和Set替代Object、includes替代indexOf)

(b)默认使用更快的md4 hash算法

(c)webpacks AST可以直接从loader传递给AST,减少解析时间

(d)使用字符串方法替代正则表达式

3.多进程/多实例-使用HappyPack解析资源

原理:每次webpack解析一个模块,HappyPack会将它及它的依赖分配给worker线程中

 1 exports.plugins = {
 2   new HappyPack({
 3     id: 'jsx',
 4     threads: 4, // 固定线程数,但是不建议
 5     loaders: ['babel-loader']
 6   }),
 7   new HappyPack({
 8     id: 'styles',
 9     threads: 2, // 固定线程数,但是不建议
10     loaders: ['style-loader', 'css-loader', 'less-loader']
11   })
12 }

4.多进程/多实例-并行压缩

方法一:使用parallel-uglify-plugin插件(webpack3使用)

 1 const ParallelUglifyPlugin = require('webpack-parallel-uglify-plugin');
 2 module.exports = {
 3   plugins: [
 4     new ParallelUglifyPlugin({
 5       uglifyJS: {
 6         output:{
 7           beautity: false,
 8           comments: false,
 9         },
10         compress: {
11           warnings: false,
12           drop_console: true,
13           collapse_vars: true,
14           reduce_vars: true
15         }
16       }
17     })
18   ]
19 }

方法二:使用uglifyjs-webpack-plugin开启parallel参数(webpack4使用)

 1 const UglifyJsPlugin = require('uglifyjs-webpack-plugin');
 2 module.exports = {
 3   plugins: [
 4     new UglifyJsPlugin({
 5       uglifyOptions: {
 6         warnings: false,
 7         parse: {},
 8         compress: {},
 9         mangle: true,
10         output: null,
11         toplevel: false,
12         nameCache: null,
13         ie8: false,
14         keep_fnames: false
15       },
16       parallel: true
17     })
18   ]
19 }

5.分包-设置Externals

思路:将react、react-dom基础包通过cdn引入,不打入bundle中

方法:使用html-webpack-externals-plugin

 1 const HtmlWebpackExternalsPlugin = require('html-webpack-externals-plugin');
 2 plugins: [
 3   new HtmlWebpackExternalsPlugin({
 4     external: [
 5       {
 6         module: 'react',
 7         entry: '........./react-with-addons.min.js?_b,
 8         global: 'React'
 9       },
10       {
11         module: 'react-dom',
12         entry: '........./react-dom.min.js?_b,
13         global: 'ReactDOM'
14       }
15     ]
16   })
17 ]

6.进一步分包-预编译资源模块

思路:将react、react-dom、redux、react-redux基础包和业务基础包打包成一个文件。

方法:使用DLLPlugin进行分包,DllReferencePlugin对manifest.json引用

1 module.exports = {
2   plugins: [
3     new webpack.DllPlugin({
4       name: '[name]',
5       path: './build/library/[name].json'
6     })
7   ]
8 }

7.缓存

目的:提升二次构建速度

方法:使用HardSourceWebpackPlugin或者cache-loader

比较推荐使用HardSourceWebpackPlugin,速度更快

8.缩小构建目标

目的:尽可能的少构建模块

比如babel-loader不解析node_modules

1 module.exports = {
2   rules: {
3     test: /\.js$/,
4     loader: 'happypack/loader',
5     exclude: 'node_modules'
6   }
7 }

webpack打包极限优化--构建体积优化

1.体积优化策略

(a)Scope Hoisting

(b)Tree-shaking

(c)公共资源分离

(d)图片压缩

(e)动态Polyfill

2.Scope Hoisting

原理:将所有模块的代码按照引用顺序放在一个函数作用域里,然后适当的重命名一些变量以防止变量名冲突

对比:通过scope hoisting可以减少函数声明代码

1 // 代码示例:
2 module.exports = {
3   plugins: [
4     new webpack.opimize.ModuleConcatenationPlugin()
5   ]
6 }
7 // 要求:必须是ES6的语法,CJS的方式不支持

3.Tree-shaking

概念:1个模块可能有多个方法,只要其中的某个方法使用到了,则整个文件都会被打到bundle里面去,Tree-shaking

就是只把用到的方法打入bundle,没用到的方法会在uglify阶段被删掉

使用:webpack默认支持,在.babelrc里设置modules:false即可

要求:必须是ES6的语法,CJS的方式不支持

4.公共资源分离

目的:提取多页面公共JS chunk代码

使用:webpack3使用CommonsChunkPlugin

webpack4使用SplitChunksPlugin

5.图片压缩

要求:基于Node库的imagemin或者tinypng API

使用:配置image-webpack-loader