webpack五探-tree shaking、模式、代码分割

Tree Shaking:
当我们写了好几个方法,但是实际上只用到了一个,那么我们需要在打包的时候剔除没有用到的代码,这就是tree shaking的作用,tree shaking只支持ES module的语法,即import、export这种,而不支持require这种commonJS的语法。
在webpack.config.js中与entry、plugins等同级:

optimization:{
    usedExports:true
}

以上配置在开发环境下需要配置,在生产环境下默认已经存在,不需要配置。
package.json增加配置:意思是对所有模块都进行tree shaking

"sideEffects":false

但是有时候我们引入了一些类似css文件,如:
import './style.css';
虽然它没有导出任何内容,但是我们也不希望被剔除,所以需要排除:

"sideEffects":["*.css"]

development和production模式:
在开发环境中sourceMap是非常全的,代码不需要压缩
我们可以分成两个文件:webpack.dev.jswebpack.prod.js,分别指代开发模式和生产模式,在生产模式下需要修改配置:

mode:'production',
devtool: 'cheap-module-source-map'

删除:

new webpack.HotModuleReplacementPlugin(),
optimization:{
    usedExports:true
},
devServer: {
    contentBase: './dist',
    open: true,
    hot: true,
    hotOnly: true
}

这个时候两个文件会存在很多相同的内容,所以我们可以在创建一个webpack.common.js放置相同代码。
拆分以后需要在两个文件中引入webpack.common.js才能正常使用,需要安装:
npm install webpack-merge -D
在两个文件中引入:

const merge=require('webpack-merge');
const commonConfig=require('./webpack.common');

最后导出:

module.exports=merge(commonConfig,devConfig);

生产环境同理

Code Splitting(代码分割):
假设我们要引入lodash:
npm install lodash --save
当我们直接在业务中引入loadash时(import _ from 'lodash');会打包在同一个js中,假设loadsh大小为1M,我们的业务代码也是1M,那么我们打包生成的代码就是2M,而当我们修改代码时又会重新生成2M的js文件
// 旧
// 首次访问页面需要加载main.js(2M)
// 修改业务代码又要加载main.js(2M)

import _ from 'lodash';
console.log(_.join(['a','b','c']));

// 新
// 增加一个入口文件,将公共组件lodash.js(1M)分割出来,
// 当业务代码发生改变时,只需要重新加载main.js(1M)即可
lodash.js:

import _ from 'lodash';
window._=_;

webpack.common.js:

entry: {
    lodash:'./src/lodash.js',
    main: './src/index.js'
},

以上的代码分割是人为的,不够智能,webpack中有一些配置、插件可以让代码分割变得更加简单

optimization:{
    splitChunks:{
        chunks:'all'
    }
},

// 以上为同步代码分割
// 下面是异步代码分割:
安装:
npm install babel-plugin-dynamic-import-webpack -D
在.babelrc中:

"plugins":["dynamic-import-webpack"]

就可以以异步形式引入:

import('lodash').then(({default:_})=>{})

// 总结:代码分割与webpack无关,webpack中实现代码分割有2中方式
// 1.同步分割:只需要在webpack.common.js中做optimization配置即可
// 2.异步分割(import):无需要任何配置,会自动进行代码分割

摘要:以上 babel-plugin-dynamic-import-webpack 这个插件不是官方提供的插件,官方提供有一个代码分割的插件

需要删除:
.babelrc中:"plugins":["dynamic-import-webpack"]
package.json中:"babel-plugin-dynamic-import-webpack": "^1.1.0",
安装:
npm install --save-dev @babel/plugin-syntax-dynamic-import
在.babelrc中使用该插件:"plugins": ["@babel/plugin-syntax-dynamic-import"]
重新打包会发现生成0.js,那么我们要如何使文件名为指定名字呢?以lodash为例:
import(/* webpackChunkName:"lodash" */'lodash').then(({default:_})=>{});
只需在前面加上注释即可,会生成名为vendors~lodash.js的文件,而不是原来的0.js

如果想要生成lodash.js,需要修改webpack.common.js:

optimization:{
    splitChunks:{
        chunks:'all',
        cacheGroups: {
            vendors: false,
            default: false
        }
    }
},

重新打包就会看到生成的事lodash.js。
由此可以得出:无论是同步还是异步的代码分割,都需要使用SplitChunksPlugin这个插件

讲解splitChunks,默认为:

splitChunks: {
    chunks: "async", // 只适用于异步,如果只对同步的也进行分割,需要设置为"initial",若需要对两者都进行分割,需要设置为'all'
    minSize: 30000, // 如果代码大于30000B(30KB)才做代码分割,小于此则不做代码分割
    // maxSize:0,  // 一般不配置,假如设置成50000(50kb),而引入的库为1MB,则会尝试分成20个,一般也不会成功,所以不配置
    minChunks: 1,   // 被引用多少次的时候才进行分割
    maxAsyncRequests: 5,    // 默认就好
    maxInitialRequests: 3,  // 默认就好
    automaticNameDelimiter: '~',    // 文件生成连接符
    name: true,
    cacheGroups: {  // 缓存组-同步会走到这里,假设我们同时引入lodash和jquery,则会先缓存,然后打包到一起
        vendors: {
            test: /[\/]node_modules[\/]/, // 如果是node_modules下面的库,则统一分割到vendors.js
            priority: -10,  // 优先级,值越大,优先级越高
            filename:'vendors.js'
        },
    default: {
            minChunks: 2,
            priority: -20,
            reuseExistingChunk: true    // 如果一个模块已经被打包过了,再次发现需要打包的时候就会忽略这个模块
        }
    }
}
原文地址:https://www.cnblogs.com/jingouli/p/12255825.html