上面我们使用了 webpack 中的代码分割。我们知道webpack 代码分割,底层使用了 SplitChunksPlugin 插件。那么下面,我们来写写这个插件可以进行配置的一些参数。
我们上篇的代码如下。index.js
function getComponent () {
return import('lodash').then(
({default: _}) => {
var element = document.createElement('div');
element.innerHTML = _.join(['h','e'], '**');
return element;
}
)
}
getComponent().then(element => {
document.body.appendChild(element);
})
我们异步加载了 lodash 代码。webpack 会将lodash 中的代码单独打包生成一个文件,自动做代码分割。
我们运行打包命令,会发现,在项目 build 中会有下面的文件。
0.js 就是lodash 代码。我们想把0.js 改名。0 实际上是代码分割产生的id 的值。
在异步加载组件的代码中,我们有一种语法叫 Magic Comment。
我们在import 函数参数前面加上注释,如下。
function getComponent () {
return import(/* webpackChunkName:"lodash" */ 'lodash').then(
({default: _}) => {
var element = document.createElement('div');
element.innerHTML = _.join(['h','e'], '**');
return element;
}
)
}
getComponent().then(element => {
document.body.appendChild(element);
})
上面代码的意思是,打包时代码分割,chunk 的名字为lodash.
运行打包命令,发现并未命令成功。
这是因为我们之前使用的动态import 插件,不是官方的插件,它不支持 magic comment 语法。
下面,我们先去package.json 中删除这个插件. 同时找一下 babel dynamic import 官方插件
https://babeljs.io/docs/en/babel-plugin-syntax-dynamic-import/
npm 下载安装
npm install --save-dev @babel/plugin-syntax-dynamic-import
然后在 babelrc 中配置上plugins
{
"presets": [
["@babel/preset-env",{
useBuiltIns: 'usage'
}],
"@babel/preset-react"
],
"plugins": ["@babel/plugin-syntax-dynamic-import"]
}
然后,我们打包即会生成下面的文件
这里,lodash 代码就会打包在vendors~lodash.js 中。但是,如果不想要前缀,就想它的名字叫lodash,需要再去配置,如下。
我们打开webpack.config.js 其中的optimization 配置项,如下是之前我们的配置。
optimization: {
splitChunks: {
chunks: 'all'
}
},
其实,这个配置项可以配置很多东东。我们打开webpack 官网 document > plugin > SplitChunksPlugin
https://webpack.js.org/plugins/split-chunks-plugin/
如下,我们将cacheGroups 配置项拷贝到我们的项目配置中,并做以下修改。
optimization: {
splitChunks: {
chunks: 'all',
cacheGroups: {
vendors: false,
default: false
}
}
},
然后运行打包代码,发现完美!
注:
如果我们将webpack.config.js 中splitChunks 中的内容清空,如下
optimization: {
splitChunks: {
}
},
发现,还是可以正常的进行代码分割打包,只不过名字是默认的而已。这是因为,刚刚我们找到的webpack SplitChunksPlugin 网页上说的这段话:(如果splitChunks 配置项的默认值是下面的这个,如果splitChunks 中配置项没有配那么会使用默认值)
下面我们继续尝试。把我们项目中的optimization.splitChunks 换成默认的配置。
splitChunks.chunks 可以是函数也可以是string , 当它是‘async’ 时,表示只对异步引入代码分割,当它是'all' 时,表示同步引入 异步引入的代码都可以分割。
我们将chunks 改为 ‘all’,并将index 中import 改为同步, 如下。
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const CleanWebpackPlugin = require('clean-webpack-plugin');
module.exports = {
mode: 'development',
devtool: "cheap-module-source-map",
devServer: {
contentBase: './bundle',
open: true
},
entry: {
main: './src/index.js'
},
module: {
rules: [{
test: /\.(png|jpg|gif)$/,
use: {
loader: 'url-loader',
options: {
name: '[name].[ext]',
outputPath: 'imgs/',
limit: 20480
}
}
}, {
test: /\.scss$/,
use: ['style-loader', {
loader: 'css-loader',
options: {
importLoaders: 2,
// modules: true
}
},
'sass-loader',
'postcss-loader']
}, {
test: /\.(eot|ttf|svg)$/,
use: {
loader: 'file-loader'
}
}, {
test: /\.js$/,
exclude: /node_modules/,
loader: 'babel-loader'
}]
},
output: {
filename: '[name].js',
path: path.resolve(__dirname, 'bundle')
},
optimization: {
splitChunks: {
chunks: 'all',
minSize: 30000,
maxSize: 0,
minChunks: 1,
maxAsyncRequests: 5,
maxInitialRequests: 3,
automaticNameDelimiter: '~',
name: true,
cacheGroups: {
vendors: false,
default: false
}
}
},
plugins: [new HtmlWebpackPlugin({
template: 'src/index.html'
}),new CleanWebpackPlugin()]
}
import _ from 'lodash'
var element = document.createElement('div');
element.innerHTML = _.join(['h','e'], '**');
document.body.appendChild(element);
运行打包命令,会发现,并没有进行代码分割,如下。
这是为什么呢。当同步代码引入的时候,不仅是看到splitChunks 为 ‘all’ 就可以了。它还会继续往下看配置 cacheGroups . 我们要在cacheGroups 中做一些配置,才能实现同步的代码分割。我们把官网上的cacheGroups.vendors 配置拷贝过来,如下。
cacheGroups: {
vendors: {
test: /[\\/]node_modules[\\/]/,
priority: -10
},
default: false
}
lodash 是从mode_modules 中引入的,因此test是ok 的。
这样lodash 就会打包到 vendors 组里。运行打包代码,如下。就可以分割同步引入代码了。
我们可以看到分割后的代码文件名为vendors~main.js 它的意思上,我的代码,是属于vendors 组,入口文件是main(webpack 中配置的entry)。如果我们不想要这个名字,也可以给它配置一个自定义名。把所有分割文件打包叫vendors.js, 如下。
cacheGroups: {
vendors: {
test: /[\\/]node_modules[\\/]/,
priority: -10,
filename: "vendors.js"
},
default: false
}
打包后,分割代码放在vendors.js 中,就不截图了。
接下来是splitChunks.minSize。当我们把它设置为很大时 (比如)1000000000 。 会发现webpack 不会进行代码分割了。这个因为,这个minSize 表示,当引入的文件 小于它的值(单位字节)时,就不进行代码分割了。