webpack高级概念-TreeShaking,CodeSplitting,Shimming

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',
    })
]

Demo地址

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值