使用 webpack 处理 CSS 文件


作者:Seiya

时间:2019年07月09日


前言


基于模块化开发的角度,我们需要每个模块都拥有自己的 CSS 样式,在进入不同的模块时,引用不同的 CSS 样式。为了达到这样的效果,我们需要 webpack 来帮助我们对 CSS 文件进行处理。



准备


如果需要使用 webpack 解析 css 文件,需要用到以下插件:

  • css-loader:用于加载 .css 文件,并且转换成 commonjs 对象;

  • style-loader:将样式通过 <style> 标签插入到 head 中;


众所周知,CSS 在 HTML 中的常用引入方法有 <link> 标签和 <style> 标签两种,所以这次就是结合 webpack 特点实现以下功能:

  • 将 css 通过 link 标签引入

  • 将 css 放在 style 标签里

  • 动态卸载和加载 css

  • 页面加载 css 前的transform


接下来,我们编写需要编译的 CSS 代码:

*,
body {
  margin: 0;
  padding: 0;
}
html {
  background: red;
}


CSS 放在 <style> 标签里


通常来说,css 代码放在 style 标签里可以减少网络请求次数,提高响应时间。需要注意的是,在老式 IE 浏览器中,对 style 标签的数量是有要求的。下面我们先编写 app.js 文件,如下所示:

import './css/base.css'

然后,我们编写 webpack 配置文件,如下所示:

const path = require('path');

module.exports = {
	mode: 'development',
	entry: {
		app: './src/app.js',
	},
	output: {
		filename: '[name].bundle.js',
		path: path.resolve(__dirname, 'dist'),
		publicPath: __dirname + "/dist/",
	},
	module: {
		rules: [
			{
				test: /\.css$/,
				use: [
					{
            loader: 'style-loader',
            options: {
              singleton: true   // 处理为单个style标签
            }
					},
					{
            loader: 'css-loader',
            options: {
              minimize: true    // css代码压缩
            }
					}
				]
			}
		]
	}
}



link 标签通过引用 css 文件,所以需要借助 file-loader 来将 css 处理为文件。

这里 app.js 文件和上面的一样,保持不变,然后,我们来修改部分 webpack 配置,如下所示:

...
module: {
    rules: [
      {
        test: /\.css$/, // 针对CSS结尾的文件设置LOADER
        use: [
          {
            loader: "style-loader/url"
          },
          {
            loader: "file-loader"
          }
        ]
      }
    ]
  }


动态卸载和加载 CSS


style-loader 为 css 对象提供了 use 和 unuse 两种方法,借助这两种方法,可以方便快捷地加载和卸载 css 样式。


首先,我们来修改 webpack 配置,如下所示:

...
module: {
  rules: [
    {
      test: /\.css$/,
      use: [
        {
          loader: "style-loader/useable" // 注意此处的style-loader后面的 useable
        },
        {
          loader: "css-loader"
        }
      ]
    }
  ]
}

然后,我们来修改 app.js 文件,如下所示:

import base from "./css/base.css";

var flag = false;
setInterval(function() {
  /* unuse 和 use 是 cssObj上的方法 */
  if (flag) {
    base.unuse();
  } else {
    base.use();
  }
  flag = !flag;
}, 500);


页面加载 css 前的 transform


对于 css 的 transform,简单来说:在加载 css 样式前,可以更改 css。这样,方便开发者根据业务需要,对 css 进行相关处理。


首先,我们来修改 webpack 配置,如下所示:

module: {
  rules: [
    {
      test: /\.css$/,
      use: [
        {
          loader: "style-loader",
          options: {
            transform: "./css.transform.js" // transform 文件
          }
        },
        {
          loader: "css-loader"
        }
      ]
    }
  ]
}

下面,我们编写css.transform.js,这个文件导出一个函数,传入的参数就是 css 字符串本身。

module.exports = function(css) {
  console.log(css); // 查看css
  return window.innerWidth < 1000 ? css.replace("red", "green") : css; // 如果屏幕宽度 < 1000, 替换背景颜色
};

注意:

transform 是在 css 引入前根据需要修改,所以之后是不会改变的。



自动补全 CSS3 前缀


自动补全除了 PostCSS 插件外,还需要使用 autoprefixer 插件配合,具体配置如下所示:

module.exports = {
  ...
  module: {
    rules: [
      test: /\.css$/,
      use: [
        'style-loader',
        'css-loader',
        {
          loader: 'postcss-loader',
          options: {
            plugins: () => {
              require('autoprefixer')({
                /*
                 * last 2 version: 表示兼容到浏览器最近的两个版本
                 * > 1% :          表示浏览器版本使用人数的比例
                 * iOS 7 :         表示兼容 iOS7 以上的版本
                 */
                browsers: ["last 2 version", ">1%", "iOS 7"]
              })
            }
          }
        }
      ]
    ]
  }
}

注意:

autoprefixer 这个插件是根据 Can I Use 的规则进行补全的 (Can I Use



移动端适配:px 自动转化成 rem


以前,我们使用媒体查询来实现响应式布局,这样做的缺陷就是需要写多套适配样式代码。我们现在可以使用 CSS3 最新的 rem 规范进行适配,相对于 px 规范所表示的绝对单位,rem 规范表示的是相对单位。为了实现转化,我们需要以下插件:

  • px2rem-loader:根据一个样式表,生成 rem 版本和 @1x,@2x 和 @3x 样式表;

  • lib-flexible:动态计算根元素 font-size 的 rem 单位;


具体配置如下:

module.exports = {
  ...
  module: {
    rules: [
      test: /\.less$/,
      use: [
        'style-loader',
        'css-loader',
        'less-loader',
        {
          loader: 'postcss-loader',
          options: {
            plugins: () => {
              require('autoprefixer')({
                browsers: ["last 2 version", ">1%", "iOS 7"]
              })
            }
          }
        },
        {
          loader: 'px2rem-loader',
          options: {
            /* 1 rem = 75 px,适合 750 的视觉稿 */
            remUnit: 75,
            /* px 转化成 rem 时,小数点后面的位数 */
            remPrecision: 8
          }
        }
      ]
    ]
  }
}

然后通过内联的方式引入 lib-flexible,具体配置如下:

	<script>${require('raw-loader!babel-loader!../node_modules/lib-flexible/flexible.js')}</script>
	```
最后更新时间: 2019-7-16 12:54:06