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.js和webpack.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 // 如果一个模块已经被打包过了,再次发现需要打包的时候就会忽略这个模块 } } }