Webpack的进阶概念-TreeShaking与buildMode

1. TreeShaking

tree shaking 是一个术语,通常用于描述移除 JavaScript 上下文中的未引用代码(dead-code)。它依赖于 ES2015 模块系统中的静态结构特性,例如 import 和export

1.1 问题引入

我们新增一个工具文件math.js,里面编写一个add和minus方法:

//math.js

export const add = (a,b) =>{
    console.log(a+b)
}

export const minus = (a,b) => {
    console.log(a-b)
}

然后index.js里面导入:

// index.js
import {add} from './math.js'

add(1,2)

接着我们build打包一下,发现打包后端的文件除了add的代码外还包含了没有使用的minus相关代码。

这个其实是没有必要的,会使得js文件变大,理想情况下就是引入什么真正用到了什么,你帮我打包什么。

这也就是webpack提供的tree shaking功能 — 把一个模块里面没用的部分摇掉,只留下部分需要的。

1.2 配置使用

首先需要注意tree Shaking只支持 ES Module这种模块化方式(import,export),不支持CommonJS(require(./))。

这是因为前者底层基于一种静态引入方式,而后者是动态化的,无法在打包阶段支持。

接着让我们关注一下webpack配置文件,当mode是开发模式development时是默认不开启tree shaking的,需要加上:

optimization:{
    usedExports:true
}

接着我们还需要去package.json里面再配置一下:

{
    ...
    "sideEffects":false,
    ...
}

这里关于sideEffects配置项和treeShaking的关系可以参考这篇博文

这里要补充一个概念,当你的import对象并不是要使用的时候,而是做一些额外操作的时候,例如导入polyfill,这时候tree shaking可能直接摇掉了,其实是需要的,所以这里有可能还需要这样配置:

{
    ...
    "sideEffects":["@babel/polly-fill"],
    ...
}

之前我们通过配置了useBuiltIns字段从而避免了直接import polyfill函数,所以这里改为false就行了。

此外我们还有可能import一些css文件,这时候tree shaking也可能将其干掉,所以一般在这里我们还会写一个css规则:

{
    ...
    "sideEffects":["*.css"],
    ...
}

重新打包后我们发现bundle里面仍然有minus代码,但是exports used:minus的注释没有了。

这是因为我们目前是在开发环境,需要做一些调试,如果tree shaking干掉了,那么sourcemap就会出错,无法调试了。

我们尝试把mode切换为production,注意production环境下tree shaking会自动添加,原先新增的配置可以不要。

然后重新打包后搜索发现已经找不到minus的相关代码。

2. buildMode

其实这一点之前都带着提到过,就是设置打包模式mode字段,包括development和production

之前我们在开发过程中使用了包括devServer,HMR这种技术很方便,但是一旦源代码开发完成需要上线,就需要将mode修改为production。

development下的sourceMap是很全的,而produciton则是可以生成一个map文件来进行存储。

development下的代码不会压缩,可以完全看到源代码,而produciton则是压缩过的

2.1 为不同模式分别编写配置文件

之前的方式我们如果需要改动配置,必须去webpack.config.js里面手动修改一下,显得比较繁琐(并且不同的mode可能有一些配置还不一样)。

要想解决这个问题我们可以如下解决:

  1. 首先重命名webpack.config.js -> webpack.dev.js。
  2. 然后新创建一个webpack.prod.js文件,分别对应dev和prod环境下的配置项,prod配置项文件所需要的变化主要是将之前的devServer、HMR、optiimaztion相关的配置项移除。
  3. 配置package.json文件,新增对应的script:
...
scripts:{
    "dev":"webpack-dev-server --config webpack.dev.js", //开发环境使用devServer
    "build":"webpack --config webpack.prod.js" // 线上环境直接打包就可以
}

开发时候直接npm run dev,启动一个devServer配合HMR提高开发效率。

然后开发完成上线时执行npm run build,可以在dist目录下面生成线上所使用的html和打包的js文件

2.2 配置封装

这里我们发现两个配置文件其实有很多代码都是相同的,感觉可以提取封装一下,这里我们创建一个webpack.common.js文件,把共同的代码抽出放进去,例如entry,module,output,这里plugins虽然两者value有一些不一样,但是还是可以把共同的部分提取出来:

提取之后的prod配置文件:

module.exports = {
    mode:'production',
    devtool:'cheap-module-source-map'
}

提取之后的dev配置文件:

const webpack = require('webapck')

module.exports = {
    mode:'development',
    devtool:'cheap-module-eval-source-map',
    devServer:{
        contentBase:'./dist',
        open:true,
        port:8080,
        hot:true
    },
    plugins:[
        new webpack.HotModuleReplacmentPlugin()
    ],
    optimization:{
        usedExports:true
    }
}

抽取封装的common.js:

// 内部是之前未拆分的部分,就不重复写了
const path = ...
const HtmlWebpackPlugin = ...
...

module.exports = {
    entry:...,
    module:...,
    export:...,
    ...
}

这里光这样写还不够,记得在dev.js和prod.js同common.js做一个合并,这里就需要借助一个第三方模块:webpack-merge

npm install -D webpack-merge

并地方引入webpack-merge,并引入commonConfig进行merge就可以了

// webpack.dev.js
const merge = require('webpack-merge'),
const commonConfig = require('./webpack.common.js')

const devConfig = {
    ... // 之前的dev配置对象
}

module.exports = merge(commonConfig,devConfig)

2.3 小提示

有一些框架里面会额外创建一个build文件夹,然后把webpack的3个配置文件都放到build目录里面。

这样的话记得script的路径也要修改

猜你喜欢

转载自blog.csdn.net/sdsh1880gm/article/details/108941611
今日推荐