tree-shaking只支持ES模块的引入(import方式的引入),如果使用CommonJS的引入方法,tree-shaking是不支持的。因为CommonJS底层是动态引入的方式,import底层是静态引入的方式,tree-shaking只支持静态引入的方法,所以只支持ES模块引入。
// 正确的引入方式
import { add } from './math.js';
// 错误的引入方式 (tree shaking不支持)
// const add = require('./math.js');
目录结构:
|--demo
|--node_modules
|--src
|--index.html
|--index.js
|--math.js
|--package-lock.json
|--package.json
|--webpack.config.js
index.js
// 引入math.js模块中的一个方法
import { add } from './math.js';
add(1, 2);
math.js
// 导出两个方法
export const add = (a, b) => {
console.log(a + b)
}
export const minus = (a, b) => {
console.log(a - b)
}
在开发模式下(development), 默认是没有tree-shaking这个功能的,如果想在此模式下添加tree-shaking, 需要配置optimization项: (webpack.config.js具体如下)
// 在这里做打包配置
const path = require('path'); // 引入node的path模块(loader模块)
const HtmlWebpackPlugin = require('html-webpack-plugin');
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
// Common.js语法
module.exports = {
mode: 'development', // 开发模式
devtool: 'cheap-module-eval-source-map', // 开发环境下的devtool
entry: {
main: './src/index.js'
},
devServer: {
contentBase: './dist',
open: true,
port: 8080
},
module: {
rules: [{
test: /\.js$/,
exclude: /node_modules/,
loader: "babel-loader",
options: {
presets: [["@babel/preset-env", {
targets: {
chrome: "67"
},
useBuiltIns: "usage"
}]]
}
}]
},
plugins: [
new HtmlWebpackPlugin({
template: './src/index.html'
}),
new CleanWebpackPlugin()
],
optimization: { // 在开发环境里需要使用此配置
usedExports: true // 哪些导出的模块被使用了,再做打包
},
output: {
filename: 'dist.js', // 打包之后的输出文件
path: path.resolve(__dirname, 'dist')
}
}
在package.json里做如下配置:
也可以通过数组的形式配置:
"sideEffects": false,
// "sideEffects": ["@babel/polyfill"],
// "sideEffects": ["*.css"],
sideEffects配置的含义:遇到任何的css文件和@babel/polyfill需要填充注入的特性,不使用tree-shaking。如果某些文件,不想让它做tree-shaking, 那么就可以通过数组的形式配置在sideEffects里边就可以了。若没有要配置的东西,此值就设置为false.
打包:
npx webpack
在打包后的dist.js中,可以看出,tree-shaking已经帮我们做了处理,已经区分了哪些是导出模块,哪些是导出使用了的模块。但在development环境下做打包的时候,即时用了tree-shaking, 也不会帮我们把导出没有使用的模块从打包生成的dist.js文件里去除掉,只是会在代码里给与提示。⭐️(这个问题出现的原因是:因为在开发环境中,我们可能会对代码做一定的调试,如果tree-shaking 把部分代码去除,可能在调试时,代码对应的行数都会出错,所以开发环境下,tree-shaking还会保留代码)
当我们的项目要打包上线的时候,mode的值为production的时候。此时tree-shaking就会生效了,配置如下:
// 在这里做打包配置
const path = require('path'); // 引入node的path模块(loader模块)
const HtmlWebpackPlugin = require('html-webpack-plugin');
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
// Common.js语法
module.exports = {
mode: 'production', // 生产模式
devtool: 'cheap-module-source-map', // 生产环境下的devtool
entry: {
main: './src/index.js'
},
devServer: {
contentBase: './dist',
open: true,
port: 8080
},
module: {
rules: [{
test: /\.js$/,
exclude: /node_modules/,
loader: "babel-loader",
options: {
presets: [["@babel/preset-env", {
targets: {
chrome: "67"
},
useBuiltIns: "usage"
}]]
}
}]
},
plugins: [
new HtmlWebpackPlugin({
template: './src/index.html'
}),
new CleanWebpackPlugin()
],
output: {
filename: 'dist.js', // 打包之后的输出文件
path: path.resolve(__dirname, 'dist')
}
}
由于在生产环境下,tree-shaking是默认配置好的,所以生产环境下,不需要写以下配置项:
optimization: { // 在开发环境里需要使用此配置
usedExports: true // 哪些导出的模块被使用了,再做打包
}
npx webpack
由此可以看出,在我们打包生成线上代码的时候,Tree-Shaking已经把导出未使用的模块代码剔除掉了。使项目在运行时,加载脚本体积减小,缩短了加载时间,从而提升项目性能。✨