美文网首页
webpack中对CSS文件的代码分割

webpack中对CSS文件的代码分割

作者: 喜剧之王爱创作 | 来源:发表于2020-08-24 18:26 被阅读0次
    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文件的代码分割

          本文链接:https://www.haomeiwen.com/subject/yzhnjktx.html