webpack中对CSS文件的代码分割

webpackhot.jpg

写在前面

在之前的文章中,我们介绍了如何对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的代码分割做了大致的讲解和实验,当然了这个插件还会有一些很高级的用法,下面我再用文字的形式,简单的描述一下,各位读者朋友可以自行对照着官网做相应的理解

  1. 有时候,我们会对项目做多入口的配置,那么我们如何去保证多入口的文件中引入的css最终打包到一个css文件中呢?
    splitChunks: {
      cacheGroups: {
        styles: {
          name: 'styles',
          test: /\.css$/,
          chunks: 'all',
          enforce: true,
        },
      }

其实MiniCssExtractPlugin底层还是比较依赖我们的splitChunks配置的,我们可以在其中生成一个组。上面就会做匹配,只要你是css结尾的文件,不管是同步引入还是异步引入,最终都会被打包进一个叫styles.css的文件中去。其中enforce: true代表忽略默认参数,不管你splitChunks中的其他限制参数如何,都去执行这个组的规则。这样,所有的css文件,都会被打包进一个文件中去

  1. 假如我想根据打包入口的不同,将不同的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插件的应用,相信大家结合文章和官网的描述,能很快的将它应用到你的项目中。

你可能感兴趣的:(webpack中对CSS文件的代码分割)