webpack在进行模块化打包的时候,会将模块中用得到的用不到的全部都打包,我们希望它只打包我们用到的,在 webpack2+ 引入了 Tree Shaking
,它可以帮我们把我们不需要的东西“从树上摇晃掉”。
注意: Tree Shaking 只支持 ES Module 的引入
在开发模式下,tree shaking 默认是关闭的,我们只需在 plugins 下方加入以下配置:
// webpack.config.js
module.exports = {
mode: 'development', // 开发环境
plugins: [...],
optimization: {
usedExports: true
},
output: {...}
}
如果某些模块你不想使用 tree shaking,可以在 package.json
中加入以下配置:
// package.json
{
"sideEffects": ["@babel/polyfill", "*.css"], // 对@babel/polyfill和所有的css文件不使用Tree Shaking
}
开发环境和生产环境的打包需求是不一样的,例如开发环境我们想要让代码不压缩,而生产环境需要减小体积而要求代码压缩。因此,我们需要将 Development 和 production 模式区分打包。因为打包需求不同,因此每次打包我们都需要手动修改配置项来配置不同的打包模式,这样未免有些过于繁琐,我们可以通过一些配置项来简化这一步操作。
// package.json
"scripts": {
"dev": "webpack-dev-server --config webpack.dev.js",
"build": "webpack --config webpack.prod.js"
}
运行不同的命令即可进行不同环境的打包。
接下来我们就要对这两个配置文件进行精简——将相同的配置合并到一个文件中。
新建一个文件 webpack.common.js
将 webpack.dev.js 和 webpack.prod.js 中公共的部分移到 webpack.common.js 中
安装 webpack-merge
npm i webpack-merge -D
在 webpack.dev.js 和 webpack.prod.js 中引入 webpack-merge、webpack.common.js
使用 webpack-merge 合并 common 配置
我们可以将这三个文件放到一个文件夹里面(需要修改出口文件夹路径和配置文件路径),下面是我的目录结构以及详细配置
webpack.dev.js:
const webpack = require('webpack');
const merge = require('webpack-merge');
const commonConfig = require('./webpack.common');
const devConfig = {
mode: 'development', // 打包模式,默认是 production
devtool: 'cheap-module-eval-source-map',
devServer: {
contentBase: './dist',
open: true,
hot: true, // 开启热模块替换
hotOnly: true // 即使热模块替换不生效,浏览器也不自动刷新
},
plugins: [
new webpack.HotModuleReplacementPlugin()
],
optimization: {
usedExports: true
}
}
module.exports = merge(commonConfig, devConfig);
webpack.prod.js:
const merge = require('webpack-merge');
const commonConfig = require('./webpack.common');
const prodConfig = {
mode: 'production', // 打包模式,默认是 production
devtool: 'cheap-module-source-map'
}
module.exports = merge(commonConfig, prodConfig);
webpack.common.js:
const path = require('path')
const HtmlWebpackPlugin = require('html-webpack-plugin');
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
module.exports = {
entry: {
main: './src/index.js', // 打包的入口文件,即打包 index.js 文件
},
module: {
rules: [{
test: /\.(png|jpg|gif)$/,
use: {
loader: 'url-loader',
options: {
// 这种配置语法叫做 placeholder, 占位符
name: '[name].[ext]', // 打包后的文件名以及后缀不变
outputPath: 'images/', // 打包后的图片文件会放到出口文件夹中的 images 文件夹下
limit: 2048 // 当图片大小大于 2048bit,即大于2Kb时,url-loader就不会将图片转成base64字符串,而是单独生成一个文件,打包到出口文件夹下指定文件夹内
}
}
}, {
test: /\.css$/,
use: [
'style-loader',
{
loader: 'css-loader',
options: {
importLoaders: 1
}
},
'postcss-loader'
]
},{
test: /\.js$/,
exclude: /node_modules/,
loader: 'babel-loader',
options: {
presets: [['@babel/preset-env', {
targets: {
edge: "17",
firefox: "60",
chrome: "67",
safari: "11.1",
},
useBuiltIns: 'usage'
}]]
}
}]
},
plugins: [
new HtmlWebpackPlugin({
template: 'src/index.html'
}),
new CleanWebpackPlugin()
],
output: {
filename: '[name].js', // 打包后的文件名
path: path.resolve(__dirname, '../dist'), // 打包后的文件放在哪个文件夹内,这里必须是绝对路径
}
}
package.json:
{
"scripts": {
"dev": "webpack-dev-server --config ./build/webpack.dev.js",
"build": "webpack --config ./build/webpack.prod.js"
}
}
在一些项目中,我们经常对项目公用部分进行拆分,这就是 代码分割,这样做可以给用户更好的使用体验。
举个手动分割的栗子:在某个项目中使用了一个大小为 1MB 的第三方库,自己的业务逻辑代码也有 1MB
webpack4 自带了一个代码分割插件,不用我们手动分割
只需在webpack的配置文件中加入一下配置项就可以最简单粗暴的代码分割了:
// webpack.config.js
module.exports = {
optimization: {
splitChunks: {
chunks: 'all'
}
}
}
split plugins 参数配置: