优化篇|博客系列
# 一、删除未引用代码
在实际开发中, 我们无意间可能会产生很多未使用的代码, 但是你又因为业务的原因不想把它删除, 同时又不希望在打包的时候将这些无用的代码包含进去.
# 1.2 一个小案例
让我们先来看一个案例, 以确保让你能够完全了解tree shaking.
- 在
src文件夹下新建一个math.js并导出两个方法:
export function square(x) {
return x * x;
}
export function cube(x) {
return x * x * x;
}
- 在
src/index.js中使用cube()方法:
import './style.css'
+ import { cube } from './math'
function component() {
var element = document.createElement('div');
element.innerHTML = '孔子曰:中午不睡,下午崩溃!孟子曰:孔子说的对!';
element.classList.add('color_red')
+ console.log(cube(3)) // 使用了cube
return element;
}
document.body.appendChild(component());
- 修改
webpack.config.js中的mode:
const path = require('path')
const HtmlWebpackPlugin = require('html-webpack-plugin')
module.exports = {
+ mode: 'development',
entry: [
'./src/index.js'
],
output: {
filename: '[name].bundle.js',
path: path.resolve(__dirname, 'dist')
},
plugins: [
new HtmlWebpackPlugin({
title: 'html-webpack',
})
],
module: {
rules: [{
test: /\.css$/,
use: [
"style-loader",
"css-loader"
]
}
]
}
}
完成上述的三个步骤之后, 执行npm run build指令, 来进行打包.
可以看到生成的dist文件夹目录长这样:
/dist
|- index.html
|- main.bundle.js
让我们打开main.bundle.js看看里面的内容, 使用Ctrl + F查找square, 发现它竟然还是能够搜索的到.
这就是我想要表达的:
明明square方法没有在代码使用, 但是它还是会被包含在构建完之后的bundle中.
# 1.3 找出未引用代码
通过上面👆这个案例, 我想你大概已经明白未引用代码的意思了吧.
现在让我们来看看如何在打包的时候找出这些未引用的代码.
说是找出这些未引用的代码, 但其实这种说法是不太全面的.
而是要找出并删除这些无副作用的代码.
「副作用」的定义是,在导入时会执行特殊行为的代码,而不是仅仅暴露一个 export 或多个 export。
有些代码是有副作用的, 但是你也不能把它删除.
比如polyfill, 它会影响全局作用域, 但是它通常不会提供export.
而将文件标记为无副作用(也就是纯粹部分), 是通过在package.json设置sideEffects属性来实现的:
{
"name": "your-project",
"sideEffects": false
}
若是将sideEffects设置成了false则表示所有文件都是无副作用的, 来告知webpack你可以大胆放心的删除未用到的export导出.
如果你的代码中确实又一些副作用, 那么可以改为提供一个数组:
{
"name": "your-project",
"sideEffects": [
"./src/some-side-effectful-file.js",
"*.css"
]
}
# 1.4 压缩输出
我们已经明白了什么是未使用的代码, 也知道了利用sideEffects找到这些未使用的代码.
其实如果你没有在package.json中设置sideEffects也没事, 它默认会认为所有的文件都是无副作用可供webpack删除的.
所以接下来就是要在构建的时候将它们从bundle中删除.
像这种删除未使用代码并进行代码压缩就被称为压缩输出, 非常好记.
而实现压缩输出的方式, 是要启用webpack内部的uglifyjs插件.
它主要有以下几种方式启用:
webpack4直接通过mode配置成production就可以了webpack4如果没有配置mode的话它默认也会启用- 通过在命令行中添加
--optimize-minimize, 比如"build": "webpack --optimize-minimize"
通过压缩输出, 我们此时再看看npm run build之后的效果:
-
main.bundle.js里的代码被压缩成了我们看不懂的代码… -
同时也查找不到
square函数了.
# 二、代码分离
代码分离的特性主要是: 能够把代码分离到不同的bundle中, 然后按需加载或并行加载这些模块.
常用的代码分离方法:
- 多个入口起点, 通过配置entry
- 防止重复, 使用
webpack.optimize.CommonsChunkPlugin插件去重和分离chunk (但是在webpack4中已废弃) - 动态导入: 通过模块的内联函数调用来分离代码。
# 2.1 多个入口起点
通过在webpack.config.js设置entry就可以了:
const path = require('path');
const HTMLWebpackPlugin = require('html-webpack-plugin');
module.exports = {
entry: {
index: './src/index.js',
another: './src/another-module.js'
},
plugins: [
new HTMLWebpackPlugin({
title: 'Webpack Code Splitting'
})
],
output: {
filename: '[name].bundle.js',
path: path.resolve(__dirname, 'dist')
}
};
# 2.2 防止重复(CommonsChunkPlugin废弃)
在学习官网给出的文档《 webpack文档-代码分离-防止重复》这一章节的时候, 发现使用webpack.optimize.CommonsChunkPlugin之后, 在构建的过程中会报错.
后来了解到这个插件在webpack4中已经被废弃了, webpack4中已经默认做了这方面的优化了.
这里我就简单介绍一下CommonsChunkPlugin这个功能就是了, 如果你对此不感兴趣可以跳过这块内容阅读下一节.
案例🌰:
此案例基于webpack3, GitHub案例地址: LinDaiDai/webpack3-demo
假设我们有这样一个场景:
lodash这个依赖在不同的js文件中被使用, 例如在index.js和another-module.js中都被使用了:
(lodash是一个工具库里面提供了很多实用的方法,可以使用npm i lodash安装)
// src/index.js
import _ from 'lodash'
// src/another-module.js
import _ from 'lodash'
然后在webpack.config.js中配置两个入口:
const path = require('path');
const HTMLWebpackPlugin = require('html-webpack-plugin');
module.exports = {
entry: {
index: './src/index.js',
another: './src/another-module.js'
},
plugins: [
new HTMLWebpackPlugin({
title: 'Webpack Code Splitting'
})
],
output: {
filename: '[name].bundle.js',
path: path.resolve(__dirname, 'dist')
}
};
此时如果你执行npm run build进行打包, 会看到:
lindaidai@LinDaiDaideMacBook-Pro webpack3-demo % npm run build
> webpack3-demo@1.0.0 build /Users/lindaidai/codes/webpack/webpack3-demo
> webpack
Hash: 273be9a48e0799049788
Version: webpack 3.12.0
Time: 422ms
Asset Size Chunks Chunk Names
+ index.bundle.js 546 kB 0, 1 [emitted] [big] index
+ another.bundle.js 545 kB 1 [emitted] [big] another
index.html 249 bytes [emitted]
[1] (webpack)/buildin/global.js 509 bytes {0} {1} [built]
[2] (webpack)/buildin/module.js 517 bytes {0} {1} [built]
[3] ./src/another-module.js 122 bytes {0} {1} [built]
[4] ./src/index.js 274 bytes {0} [built]
+ 1 hidden module
Child html-webpack-plugin for "index.html":
1 asset
[2] (webpack)/buildin/global.js 509 bytes {0} [built]
[3] (webpack)/buildin/module.js 517 bytes {0} [built]
+ 2 hidden modules
生成的index.bundle.js和another.bundle.js中都有lodash依赖, 导致依赖重复, 生成的bundle很大.
dist文件目录为:
