之前总结的代码分割都是针对JS代码的,
如果要对CSS代码进行代码分割,要怎么办呢?
借助MiniCssExtractPlugin
插件
-
在我们没有配置这个插件的时候,
webpack
是怎么对css代码进行打包的呢?我们来试一下
- 然后运行打包命令
npm run dev-build
然后运行代码会发现,样式生效了。
由此可以得知,`webpack`在打包的时候,它会把CSS文件直接打包到JS文件里。
这也就是我们常听说的`CSS IN JS`这样一个概念
但是这并不是我们希望的,
我们希望的是,在打包生成代码的时候,
如果我们引入的是CSS文件,那么把CSS文件单独打包到`dist`目录下,生成一个CSS文件,
而不是打包到`js文件里`,
这个时候,我们就要借助`MiniCssExtractPlugin`插件了;
具体的使用步骤如下:
- 先安装
npm install --save-dev mini-css-extract-plugin
此版本官方文档显示这个插件有个缺陷,
TODO:
HMR support
也就是现在这个模块是不支持模块热更新的,
这就意味着在开发环境使用这个插件,
改变了css的样式,这个样式不会及时的更新到我们的项目中,
我们需要手动刷新页面,
开发效率低
所以我们一般在线上环境的打包过程中使用,
- 安装好以后,要配置一下webpack.prod.js
//dist目录下 webpack.prod.js配置如下
const MiniCssExtractPlugin = require('mini-css-extract-plugin'); //引入这个插件
const merge = require('webpack-merge');
const commonConfig = require('./webpack.common.js');
const prodConfig = {
mode: "production",
devtool:'cheap-module-source-map',
plugins: [ //使用这个插件,还需要对loader进行一些配置
new MiniCssExtractPlugin({
filename: '[name].css',
chunkFilename: '[id].css',
}),
}
module.exports = merge(commonConfig,prodConfig)
之前我们最终会通过style-loader把css样式挂载到页面上,
module: {
rules: [
{
test: /\.scss$/,
use: [
'style-loader',
{
loader: 'css-loader',
options: {
importLoaders: 2
}
},
'sass-loader',
'postcss-loader'
]
},{
test: /\.css$/,
use: [
'style-loader',
'css-loader',
'postcss-loader'
]
}]
},
module: {
rules: [
{
test: /\.css$/,
use: [
{
loader: MiniCssExtractPlugin.loader,
options: {
publicPath: (resourcePath, context) => {
},
},
},
'css-loader',
],
},
],
},
src目录下,webpack.common.js文件中,
rules中对应的css文件,scss文件这部分代码剪切下
const path = require('path')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const CleanWebpackPlugin = require('clean-webpack-plugin')
module.exports = {
entry: {
main: "./src/index.js"
},
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
loader: 'babel-loader'
},
{
test: /\.(jpg|png|gif)$/,
use: {
loader: 'url-loader',
options: {
name: '[name]_[hash].[ext]',
outputPath: 'images/',
limit: 10240
}
}
},
{
test: /\.(eot|ttf|svg|woff)$/,
use: {
loader: 'file-loader'
}
},
//剪切到,分别放入webpack.dev.js和webpack.config.js中
// {
// test: /\.scss$/,
// use: [
// 'style-loader',
// {
// loader: 'css-loader',
// options: {
// importLoaders: 2
// }
/ / },
// 'sass-loader',
// 'postcss-loader'
// ]
// },{
// test: /\.css$/,
// use: [
// 'style-loader',
// 'css-loader',
// 'postcss-loader'
// ]
// }]
},
plugins: [
new HtmlWebpackPlugin({
template:'./src/index.html'
}),
new CleanWebpackPlugin()
],
output: {
path:path.resolve(__dirname,'dist'),
filename: '[name].js'
}
}
webpack.dev.js
中关于css文件,scss文件如下配置:
//webpack.dev.js
const webpack = require('webpack');
const merge = require('webpack-merge');
const commonConfig = require('./webpack.common.js');
const devConfig = {
mode: "development",
devtool:'cheap-module-eval-source-map',
devServer: {
contentBase: './dist',
open: true,
port: 8080,
hot: true, //让webpack开启 Hot Module Replace 的功能
},
module: {
//在开发环境中还是使用style-loader
rules:[
{
test: /\.scss$/,
use:[
'style-loader',
{
loader: 'css-loader',
options: {
importLoaders: 2
}
},
'sass-loader',
'postcss-loader'
]
},
{
test: /\.css$/,
use: [
'style-loader',
'css-loader',
'postcss-loader'
]
}
]
},
plugins: [
new webpack.HotModuleReplacementPlugin()
],
optimization: {
usedExports: true
}
}
module.exports = merge(commonConfig,devConfig)
webpack.prod.js
还剩下如下配置
//webpack.prod.js
const merge = require('webpack-merge');
const merge = require('webpack-merge');
const commonConfig = require('./webpack.common.js');
const prodConfig = {
mode: "production",
devtool:'cheap-module-source-map',
module: {
//在线上环境中
rules:[
{
test: /\.scss$/,
use:[
MiniCssExtractPlugin.loader, //使用这个插件提供给我们的loader替换掉style-loader
{
loader: 'css-loader',
options: {
importLoaders: 2
}
},
'sass-loader',
'postcss-loader'
]
},
{
test: /\.css$/,
use: [
MiniCssExtractPlugin.loader,
'css-loader',
'postcss-loader'
]
}
]
},
plugins: [
new MiniCssExtractPlugin({})
],
}
//最终导出的是 prodConfig 和 commonConfig 结合的配置
module.exports = merge(commonConfig,prodConfig)
- 然后打包生成·线上·的代码
npm run build
,
发现仍然没于对CSS做单独的打包
-
分析下原因,可能是下边几个因素造成的,之前我们在
webpack.dev.js
里做了下边的配置- 这个参数是给
tree shaking
使用的。
在做tree shaking
的时候,webpack会对所有的模块都去tree shaking
,
但是有些模块我们不希望进行tree shaking
,
所以我们配置了usedExports: true
,
然后在package.json
里,我们就可以在sideEffects
去写一些内容来代替false
值。
- 之前
tree shaking
对我们引入的style.css
起了作用,
发现我们虽然引入了文件,但是并没于使用它,
所以直接就把style.css
给干掉了,
所以要解决这个问题,我们要对tree shaking
做一下修改。
- 还有就是,之前我们把
tree shaking
的配置写在了dev
开发环境里,
实际上我们应该写在common
这里,
因为不管是线上代码,还是本地测试代码,
我们都需要,使用这个参数来告诉我们的webpack
,
有一些css文件不要去做tree shaking
的处理,
所以,我们需要把usedExports: true
从dev
里剪切到common
里
- 然后我们再运行打包
npm run build
,发现可以单独对CSS进行打包了,
dist目录下main.css就是我们这个页面上的 css文件对应的内容,
main.css.map是一个sourceMap,里面存储了一些映射关系,
可以方便我们对代码的调试
- 这个参数是给
还可以对MiniCssExtractPlugin
插件进行更详细的配置
-
然后运行打包命令,发现打包生成的CSS文件的文件名,还是走的
filename
这个配置,
而不是chunkFilename
这个配置。
也就是说,打包生成的CSS文件,如果是直接被页面引用,
那么在使用这个插件的时候,就会走filename
这个配置。
如果是间接要被引用的CSS文件,就会走chunkFilename
这个配置 -
如果我们再增加一个CSS文件,并引入到index.js文件里,进行打包,
那么webpack
会把这两个CSS文件的内容合并到一起。
虽然我们实现了打包单独生成CSS文件,
但是我们可以看到,生成的文件代码并不是压缩状态的。
如果我们希望单独生成CSS文件是压缩状态的,可以用`optimize-css-assets-webpack-plugin这个插件
- 先安装
npm install --save-dev optimize-css-assets-webpack-plugin
- 然后引入和配置
//dist目录下的webpack.prod.js
const merge = require('webpack-merge');
const OptimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin'); //引入这个插件
const merge = require('webpack-merge');
const commonConfig = require('./webpack.common.js');
const prodConfig = {
mode: "production",
devtool:'cheap-module-source-map',
module: {
//在线上环境中
rules:[
{
test: /\.scss$/,
use:[
MiniCssExtractPlugin.loader, //使用这个插件提供给我们的loader替换掉style-loader
{
loader: 'css-loader',
options: {
importLoaders: 2
}
},
'sass-loader',
'postcss-loader'
]
},
{
test: /\.css$/,
use: [
MiniCssExtractPlugin.loader,
'css-loader',
'postcss-loader'
]
}
]
},
optimization: {
minimizer: [new OptimizeCSSAssetsPlugin({})], //创建的时候,参数为空,空对象
},
plugins: [
new MiniCssExtractPlugin({})
],
}
//最终导出的是 prodConfig 和 commonConfig 结合的配置
module.exports = merge(commonConfig,prodConfig)
然后我们再运行打包npm run build
,
发现它不单单帮我们把样式做了合并,
还把代码做了压缩显示在了一行
更高级的用法
-
之前我们是在只有一个入口文件的情况下,对CSS文件进行单独的打包和压缩。如果我们现在有多个入口文件,并且我们希望所有的入口文件引入的CSS文件都能够打包生成到一个CSS样式文件里。该怎么做呢?
-
看官方文档可以知道,我们现在使用的
MiniCssExtractPlugin
这个插件,它的底层也是借助了splitChunks
这个插件的。我们可以在cacheGroups组
里额外增加一个组叫做styles
,只要发现打包的文件是CSS为后缀的文件,那么不管它是同步加载的还是异步加载的文件,统一的都把它打包到名字叫做styles
的文件里去。
enforce:true
的意思是,忽略掉默认的一些参数,比如说minSize,maxSize
等。这些参数都不管,只要是一个CSS文件,就会做代码的拆分,把代码分割到名字叫做styles
的文件里去。