写在前面
在之前的文章中,我们介绍了如何对JS文件进行代码分割,这节我们将介绍,如何对css文件做代码。
在讲解今天的知识点前,我们先来介绍一个小知识点chunkFilename
,我们将配置项改成这样
module.exports = {
output: {
filename: '[name].js',
chunkFilename: '[name].chunk.js',
path: path.resolve(__dirname, '../dist')
}
}
对我们的项目进行打包,发现打包生成了下面这样的目录结构
|--dist
|--index.html
|--main.js
|--vendors~lodash.chunk.js
也就是说,在output中,chunkFilename是对简介引入模块的打包,而filename是对入口文件中的文件的打包。或者说,在index.html中,直接引入的文件,是来自filename的,而没有在里面被直接引入的将被打包进chunkFilename。这样我们就可以对代码分割后的chunk做统一的命名了。
CSS代码分割
我们做CSS代码分割的时候,会借助一个Webpack官方的插件MiniCssExtractPlugin。 下面我们先写一个demo看看打包效果,我们在src下新建一个style.css文件,再将index.js改成下面的样子。
import './style.css'
console.log('css 代码分割示例')
body {
background: #090;
}
这次我们执行打包,生成的文件目录如下
|--dist
|--index.html
|--main.js
我们发现打包出的文件,并没有出现在打包结果的目录里,但是运行index.html会发现,样式已经出来的,这是因为webapck在执行打包的时候,把css文件打包进了js中。也就是“css in js” 的概念。
那我们期望的是,对于引入的css文件,在打包目录中也是会打包出来一个css文件的,这时候就需要用到我们上面的插件了
MiniCssExtractPlugin
我们按照官方文档里的步骤操作一下
npm install --save-dev mini-css-extract-plugin
我们在使用他的时候,一般会配置再线上模式的打包配置文件中,因为有的版本的插件,是不支持HMR的,也就是说,在本地开发模式下,我们将不能使用热替换,这就可能会降低我们的开发效率,所以我我们一般将其配置再线上模式的打包配置文件中
webpack.prod.js
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
module.exports = {
plugins: [
new MiniCssExtractPlugin({})
]
}
看官网,还需要我们对loader做相应的更改
rules: [
{
test: /\.css$/i,
use: [MiniCssExtractPlugin.loader, 'css-loader'],
},
],
其实是通过MiniCssExtractPlugin
提供的loader代替了我们之前的style-loader
,所以在这里我们还需要对loader做一下更改,我们将webpack.common.js中的关于样式的loader都提出来,在dev模式下还用之前的,在线上模式下我们用插件提供给我们的配置方式,下面我只把线上模式下的代码贴出来
module.exports = {
plugins: [
new MiniCssExtractPlugin({})
],
module: {
rules: [
{
test: /\.scss$/,
use: [
MiniCssExtractPlugin.loader,
{
loader: 'css-loader',
options: {
importLoaders: 2,
}
},
'sass-loader',
'postcss-loader'
],
},{
test: /\.css$/,
use: [
MiniCssExtractPlugin.loader,
'css-loader',
'postcss-loader'
],
},
]
}
}
配置完成后,这里还需要提一点,因为我们之前在配置中开启了tree shaking,而css代码,又不符合tree shaking的逻辑,所以我们要对其做一个过滤,在package.json中将sideEffects
项改成"sideEffects": ["*.css"]
。
配置完成后,我们执行一下线上模式下的打包,这时候文件目录变成这样了
|--dist
|--index.html
|--main.js
|--main.css
|-main.css.map
|--main.js.map
可以看到哈,通过使用MiniCssExtractPlugin
插件,我们可以将CSS代码做分割了。
MiniCssExtractPlugin参数
上面的示例中,我们没有给插件传参,但是这个插件也是有一些参数可以配置的,我们按照官网的示例对其进行一下配置
new MiniCssExtractPlugin({
filename: '[name].css',
chunkFilename: '[name].chunk.css'
})
执行打包后,我们发现,打包出来的css文件叫main.css
也就是说,我们现在项目中的css走的是filname
配置项,那这是为什么呢?我们打开生成的index.html就会发现,main.css是直接被引入到index.html中的,如果是间接引入的话,才会走chunkFilename
。
同时大家还会发现,当页面中这样引入样式的时候,最终会打包到一个文件中,这也是这个插件的功能
import './style.css'
import './style1.css'
console.log('css 代码分割示例')
通过上面的示例,我们已经实现了CSS代码的分割,但是,对于CSS来说,还是未被压缩的,我们可以再次借助插件对CSS代码进行压缩
optimize-css-assets-webpack-plugin
我们按照官网对他进行配置
optimization: {
minimizer: [new OptimizeCSSAssetsPlugin({})],
}
打包后发现,在main.css中的代码已经是压缩过的了,并且还对类做了合并
其他配置
通过上面的讲解,我们已经对CSS的代码分割做了大致的讲解和实验,当然了这个插件还会有一些很高级的用法,下面我再用文字的形式,简单的描述一下,各位读者朋友可以自行对照着官网做相应的理解
- 有时候,我们会对项目做多入口的配置,那么我们如何去保证多入口的文件中引入的css最终打包到一个css文件中呢?
splitChunks: {
cacheGroups: {
styles: {
name: 'styles',
test: /\.css$/,
chunks: 'all',
enforce: true,
},
}
其实MiniCssExtractPlugin
底层还是比较依赖我们的splitChunks
配置的,我们可以在其中生成一个组。上面就会做匹配,只要你是css结尾的文件,不管是同步引入还是异步引入,最终都会被打包进一个叫styles.css的文件中去。其中enforce: true
代表忽略默认参数,不管你splitChunks中的其他限制参数如何,都去执行这个组的规则。这样,所有的css文件,都会被打包进一个文件中去
- 假如我想根据打包入口的不同,将不同的css文件打包到不同的文件里面去呢?
cacheGroups: {
fooStyles: {
name: 'foo',
test: (m, c, entry = 'foo') =>
m.constructor.name === 'CssModule' && recursiveIssuer(m) === entry,
chunks: 'all',
enforce: true,
},
barStyles: {
name: 'bar',
test: (m, c, entry = 'bar') =>
m.constructor.name === 'CssModule' && recursiveIssuer(m) === entry,
chunks: 'all',
enforce: true,
},
},
},
和上面的一样,也是新创建了一个组,只不过是,在判定规则的时候做了一个判断,这里只是照搬官网的内容,主要是为了让大家熟悉有这样的东西,如果在打包的过程中存在这样的样式文件的打包需要,就可以到对应的地方去找文档了
写在最后
到此,我们关于css的代码分割就讲解完了,其实主要是对MiniCssExtractPlugin
插件的应用,相信大家结合文章和官网的描述,能很快的将它应用到你的项目中。