Tree Shaking
只支持ES module的引入,即import引入方法,作用是把不需要的代码“摇晃”掉,减少打包体积。比如
// math.js
export const add = (a, b) => {
return a + b;
}
export const minus = (a, b) => {
return a - b;
}
// index.js
import {add} from './math.js'
.....
打包之后可以看到
add和minus都一起打包进去了,但是我们只用到了add函数,所以我们希望打包应该只需要add函数。
webpack.config.js
....
optimization: {
usedExports: true,
},
.....
package.json
...
"sideEffects": false,
....
意思是tree shaking正常对所有模块进行操作,没有需要特殊处理。如果需要处理的,如设置css文件不进行tree shaking,
...
"sideEffects": ["*.css"],
...
现在打包,可以看到
虽然minus函数依旧存在,但是多了一行/* unused harmony export minus */, webpack知道minus是没有使用到的函数,这是因为我们在开发环境下,webpack使用到了sourcemap,如果代码删除,可能导致对应行数出现问题,当切换 mode: "production",可以查询到add函数,但是minus函数就没有被打包进去。
Develoment 和 Production 模式的区分打包
npm install webpack-merge -D
// webpack.common.js
module.exports = {...}
// webpack.dev.js
const commonConfig = require('./webpack.common.js')
const {merge} = require('webpack-merge')
const devConfig = {...}
module.exports = merge(commonConfig, devConfig)
// webpack.prod.js
const commonConfig = require('./webpack.common.js')
const {merge} = require('webpack-merge')
const prodConfig = {...}
module.exports = merge(commonConfig, prodConfig)
package.json
"scripts": {
"dev": "webpack --config webpack.dev.js",
"build": "webpack --config webpack.prod.js",
"start": "webpack serve --hot --config webpack.dev.js"
},
Code Splitting
以lodash为例,假设lodash大小为1MB,业务代码为1MB,考虑不做任何压缩,打包之后的index.js文件大小为2MB,这样导致文件过大,加载时间过长,当再次访问页面的时候,又要重新加载2MB的内容,但是loash这样的三方库,一般是不会有变化的。有没有办法解决这个问题呢?
我们借助webpack实现code splitting
第一种:同步代码实现方式:
// webpack.config.js
...
optimization: {
splitChunks: {
chunks: 'all'
}
}
...
第二种:异步代码(import)实现方式:
无需任何配置,会自动实现代码分割;
// index.js
function getComponent() {
// webpackChunkName 打包之后的文件名
return import(/* webpackChunkName: "lodash" */'lodash').then(({default: _}) => {
var element = document.createElement('div');
element.innerHTML = _.join(['Hello', 'World'], '~');
return element;
})
}
getComponent().then(element => {
document.body.appendChild(element);
})
使用官方插件支持dynamic-import
npm install --save-dev @babel/plugin-syntax-dynamic-import
babel.config.json
{
"presets": [
["@babel/preset-env",
{
"useBuiltIns": "usage"
}
],
"@babel/preset-react"
],
"plugins": ["@babel/plugin-syntax-dynamic-import"]
}
重新打包,没有问题的话可以看到有一个入口main.js和lodash.js文件。
Split Chunks详细配置
splitChunks: {
chunks: "async", // 共有3个值"initial","async"和"all"。配置后,优化仅选择初始块,按需块或所有块。
minSize: 30000,
minChunks: 1, // 至少引用次数1次才代码分割
maxAsyncRequests: 5, // (默认为5)按需加载时并行请求的最大数量
maxInitialRequests: 3, // (默认值为3)入口点的最大并行请求数
automaticNameDelimiter: '~', // 自动生成的文件名里面的分隔符
name: true,
cacheGroups: {
vendors: {
test: /[\\/]node_modules[\\/]/, // node_modules中的才代码分割
priority: -10,
filename: 'vender.js',
},
default: { // 不在node_modules中的模块进入default
minChunks: 2,
priority: -20,
reuseExistingChunk: true, // 允许重用现有的块,而不是在模块完全匹配时创建新的块
filename: 'common.js'
}
}
}
Shimming
例如使用jquery, 我们需要改为一个全局变量依赖。要实现这些,我们需要使用 ProvidePlugin
插件。
使用 ProvidePlugin
后,能够在 webpack 编译的每个模块中,通过访问一个变量来获取一个 package。如果 webpack 看到模块中用到这个变量,它将在最终 bundle 中引入给定的 package。
plugins:[
...
new webpack.ProvidePlugin({
$: 'jquery',
})
]