02月08, 2018

webpack 处理 css module的一种方式

在实际项目开发中,会经常遇到引入第三方库和开发者自己书写的css处理问题。首先我采用了postcss的语法,借助postcss的语法可以实现定义变量、全局css、自动添加浏览器内核的前缀等等,除此之外,借助css-loader,采用cssmodule的实现方式在react中定义className,并且为了防止重复的css代码,采用了`[name][local]-[hash:base64:5]`的命名方式。

场景

所有的css都通过style标签的方式注入到html文档中,并没有通过extract-text-webpack-plugin来处理成css文件

疑问

在该定义场景下,这里主要谈两个问题

  1. 一个是如何在webpack中分别处理vendor样式和开发者自己书写的样式
  2. 另一个是如何压缩vendor样式和自己书写的样式

处理方式

我采用了postcss的两个plugin来处理自己的css

// postcss.config.js
module.exports = {
  plugins: [
    require('autoprefixer'),
    require('cssnano')({
      preset: 'default',
    }),
  ],
};

autoprefixer 顾名思义,是添加浏览器内核前缀使用,主要处理兼容性问题,另外,cssnano主要来处理postcssminify。并且用css-loader来处理变量的命名和导入方式,

{
    test: /\.css$/,
    exclude: /node_modules/,
    use: [
        'style-loader',
        {
            loader: 'css-loader',
            options: {
                modules: true,
                localIdentName: '[name]_[local]-[hash:base64:5]',
            },
        },
        {
            loader: 'postcss-loader',
        },
    ],
}

下图是最终的css。

在未使用cssnano处理之前的css

在处理完自身css的时候会出现一个问题,也就是当引用vendor的css时,并不希望用postcss来处理前缀等问题(因为vendor的css已经拥有了这些),甚至处理了会导致样式的错乱,即相当于手动修改了vendor的css,导致组件class与样式匹配不上的问题。

解决方式

其实,在webpack处理loader的时候,是会根据开发者的入口文件递归遍历,在使用loader时,同一个loader可以针对不同文件使用多次。loader的配置中可以通过这样的方式来区分不同文件

{ exclude: /node_modules/ }

通过这样的方式,排除了node_modules下的css,另一个问题又出现了,排除了node_modules中的css样式之后,此时引入的css还想进行压缩或者vendor的样式库并不支持css_module时该如何处理?

可以通过如下方式进行处理,排除掉源代码中的css,并且采用css-loader的options来定义它的处理。

{
    test: /\.css$/,
    exclude: [/src/],
    use: [
        'style-loader',
        {
            loader: 'css-loader',
            options: {
                minimize: true,
                importLoaders: 0,
            },
        },
    ],
},

GitHub - postcss/postcss-loader: PostCSS loader for webpack的文档中解释了这里的内容

This loader cannot be used with CSS Modules out of the box due to the way css-loader processes file imports. To make them work properly, either add the css-loader’s importLoaders option.

css-loader中也有相同的解释

{
  test: /\.css$/,
  use: [
    'style-loader',
    {
      loader: 'css-loader',
      options: {
        importLoaders: 2 // 0 => no loaders (default); 1 => postcss-loader; 2 => postcss-loader, sass-loader
      }
    },
    'postcss-loader',
    'sass-loader'
  ]
}

loader不能够用css_module的方式处理的时候,需要借助css-loaderimportLoaders选项来进行处理。

这样,webpack的build速度也会提升,我这里从12s提升到了10s,最终vendor的css如下

总结

开发过程中总有一些外部资源不是那么尽如人意,我们需要去尽量的解耦并且做到0冲突,对于不同的位置的资源进行不同的方式的处理,但他们最终的效果应该是相同的。殊途同归,弯路再多,也只是在过程上的不同。

本文链接:https://beacelee.com/post/webpack-css-module-postcss-css-loader.html

-- EOF --

Comments

评论加载中...

注:如果长时间无法加载,请针对 disq.us | disquscdn.com | disqus.com 启用代理。