这是我参与更文挑战的第6天,活动详情查看:更文挑战
对CSS文件进行代码分割
场景
使用style-loader
打包后会自动帮我们在html文件中加入<style>
并将CSS往里填充,当CSS代码成千上万时,将会产生庞大的html。我们能不能在打包时将css分离出来,然后使用link
标签进行引入呢?
在webpack中如何进行css的代码分割?
这块我们要借助webpack官网提供的一个插件,mini-css-extract-plugin
这个插件就可以帮助我们对webpack中引入的css文件进行代码分割,不过这个插件有一个缺陷就是不支持模块热更新,这就意味着,如果我们在开发环境中使用这个插件,改变了css的样式,此时视图不会自动更新,我们需要手动刷新页面,如果在开发环境使用此插件的话效率就不是很高了,对于这个插件的使用我们在打包线上环境时使用即可;
配置
安装
npm add mini-css-extract-plugin
引入
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
module.exports = {
module: {
rules: [
{
test: /\.css$/,
use: [
MiniCssExtractPlugin.loader,
{
loader: 'css-loader',
options: {
importLoaders: 2
}
},
'css-loader',
'postcss-loader'
]
}
]
},
plugins: [
new MiniCssExtractPlugin({
filename: '[name].css'
})
]
}
- 将原本的
style-loader
替换成MiniCssExtractPlugin.loader
- 配置了
plugins
后就能对css进行抽离,filename
是对打包后的css进行命名
按上述这样配置就能实现css代码分离了,但是分离出来的css代码是还没有进行压缩过的,我们希望分离出来的css还要进行压缩,应该怎么处理呢?
optimize-css-assets-webpack-plugin
这个插件可以帮助我们压缩css,配置如下:
const OptimizeCSSAssetsPlugin = require("optimize-css-assets-webpack-plugin");
module.exports = {
optimization: {
minimizer: [new OptimizeCSSAssetsPlugin({})]
}
}
减少loader的执行频率
rules: [{
test: /\.js$/,
exclude: /node_modules/,
loader: 'babel-loader',
}]
如果遇到的是JS模块,上述配置写了exclude:/node_modules/
也就是,不是node_modules里面的JS模块才会去使用babel loader,如果外面不写exclude的话,遇到JS模块时会将node_modules里的代码也进行一次编译,这就会降低打包的速度,其实这种引入的第三方库已经是编译好了的,我们完全没有必要在对它进行一次编译,在这里加入exlcude就可以很好的提高JS的打包速度;
使用DllReferencePlugin插件进一步提高打包速度
场景
现在我们已经做了代码分割的配置,第三方引入的模块会被打包到vendors
中,以下是我们使用的代码:
import React, { Component } from 'react';
import ReactDom from 'react-dom';
class App extends Component {
render() {
return (
<div>
<div>To see you in my dreams</div>
</div>
)
}
}
ReactDom.render(<App />, document.getElementById('root'));
我对此代码进行打包,结果如下:
耗时是1089ms,
vendors
的体积分别是131kib以及137kib,接下来我改动上述代码在引入一个第三方模块进行打包:
import React, { Component } from 'react';
import ReactDom from 'react-dom';
import _ from 'lodash';
class App extends Component {
render() {
return (
<div>
<div>{_.join(['To see yo', 'in my dream'], ' ')}</div>
</div>
)
}
}
ReactDom.render(<App />, document.getElementById('root'));
耗时是1235ms,
vendors
的体积分别是664kib以及771kib,我再次进行打包耗时为1198ms,我刚才已经打包过一次为什么再次打包耗时还是接近1200ms呢?
这是因为我们代码里引入了第三方模块,每一次重新打包的时候,它都要重新去分析我们引入的第三方库,最终把它们打包到我们的项目之中。那其实我们知道像这种第三方模块,它实际上代码是不会变的。所以我们可以把它单独打包,生成一个文件,然后只在第一次打包的时候,去分析这里面的代码,之后再去做打包的时候,我们直接用上一次分析好的结果就可以了,这样就可以提高打包速度;
配置
首先我们新建一个webpack.dll.js
的文件,里面专门用于打包第三方库,配置如下:
const path = require('path');
const webpack = require('webpack');
module.exports = {
mode: 'production',
entry: {
vendors: ['lodash','react', 'react-dom','jquery']
},
output: {
filename: '[name].dll.js',
path: path.resolve(__dirname, '../dll'),
library: '[name]'
},
plugins: [
new webpack.DllPlugin({
name: '[name]',
path: path.resolve(__dirname, '../dll/[name].manifest.json'),
})
]
}
entry
和output
就是入口和出口这个就不多说了,library
就是往window添加一个全局变量vendors
new webpack.DllPlugin
就是生成下面的文件,作用是把所有的第三方库依赖打包到一个的dll文件里面就是vendors.dll.js
,还会生成一个名为 manifest.json文件。该manifest.json的作用是用来让DllReferencePlugin 映射到相关的依赖上去的。
vendors.dll.js
vendors.manifest.json
接着再来配置webpack.config.js
:
const path = require('path');
const fs = require('fs');
const AddAssetHtmlWebpackPlugin = require('add-asset-html-webpack-plugin');
const webpack = require('webpack');
const plugins = [
new HtmlWebpackPlugin({
template: 'src/index.html'
}),
new CleanWebpackPlugin(['dist'], {
root: path.resolve(__dirname, '../')
})
];
const files = fs.readdirSync(path.resolve(__dirname, '../dll'));
files.forEach(file => {
if (/.*\.dll.js/.test(file)) {
plugins.push(new AddAssetHtmlWebpackPlugin({
filepath: path.resolve(__dirname, '../dll', file)
}))
}
if (/.*\.manifest.json/.test(file)) {
plugins.push(new webpack.DllReferencePlugin({
manifest: path.resolve(__dirname, '../dll', file)
}))
}
})
module.exports = {
plugins
}
- fs引进dll文件下的内容,就是引入
vendors.dll.js
,vendors.manifest.json
- 接着遍历dll文件下的内容,匹配后缀为
dll.js
,使用AddAssetHtmlWebpackPlugin
将vendors.dll.js
以script的形式插入html中; new webpack.DllReferencePlugin
的作用是什么呢?- 它的意思是,在我们进行打包的时候,发现了我们引入了第三方模块的时候,这个插件就会到
vendors.manifest.json
里面去帮我们找映射关系;
- 它的意思是,在我们进行打包的时候,发现了我们引入了第三方模块的时候,这个插件就会到
按照上述配置后,打包出的两次结果:
两次打包vendors.dll.js
的体积都是一样的,由于我们做了配置打包时就不会去分析第三方的模块了,而是直接引用我们第一次打包的vendors.dll.js
打包速度也明显提示了;
总结
webpack的配置很多,详细配置还请翻阅文档进行学习;