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插件的应用,相信大家结合文章和官网的描述,能很快的将它应用到你的项目中。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,456评论 5 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,370评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,337评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,583评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,596评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,572评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,936评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,595评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,850评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,601评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,685评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,371评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,951评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,934评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,167评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,636评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,411评论 2 342