Skip to content

webpack 处理 css 资源

我们可以将css文件也看成是一个模块,我们是通过import来加载这个模块的,在加载这个模块时,webpack其实并不知道如何对其进行加载,我们必须制定对应的 loader 来完成这个功能。

css-loader

css-loader 就是用来解析 css 文件的,该 loader 会将 css 等价翻译为 module.exports = "${css}" 的js代码

案例:编写 component.js,在页面上添加有颜色的文字

js
import "./assets/css/index.css";

function component() {
  const element = document.createElement("div");

  element.innerHTML = ["Hello", "Webpack"].join(" ");

  element.classList.add("content");

  return element;
}

document.body.appendChild(component());
css
.content {
  color: red;
  font-size: 20px;
}

将 component.js 写入到配置的入口中

js
entry: {
    main: './src/index.js',
    component: './src/component.js'
},

打包会发现,webpack 解析模块失败了

image-20240821142501195

我们需要引入 css-loader 对 css 模块进行解析

bash
npm i css-loader -D

添加配置

js
module: {
    rules: [{
        test: /\.css$/i,
        use: ['css-loader']
    }]
}

重新打包即可完成打包。编译完成后的css 会是一段 js字符串

js
var ___CSS_LOADER_EXPORT___ = _node_modules_css_loader_dist_runtime_api_js__WEBPACK_IMPORTED_MODULE_1___default()((_node_modules_css_loader_dist_runtime_noSourceMaps_js__WEBPACK_IMPORTED_MODULE_0___default()));
// Module
___CSS_LOADER_EXPORT___.push([module.id, `.content {
  color: red;
  font-size: 20px;
}
`, ""]);
// Exports
/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (___CSS_LOADER_EXPORT___);

得到js代码后,还是预览不到效果,需要将代码注入到他们的 style 标签中,便会使样式生效,这就需要使用 style-loader 来实现

style-loader

style-loader 大多都用于开发环境

安装

bash
npm install style-loader -D

在配置的时候需要注意的是,loader 是有顺序的,是从右到左(换行的话可以说是从上到下),相当于链式调用 style-loader(css-loader(css))

js
module: {
    rules: [{
        test: /\.css$/i,
        // 先解析css,再插入到页面
        use: ['style-loader', 'css-loader']
    }]
}

image-20240821153020342

这种将 JS、CSS 代码合并进同一个产物文件的方式有几个问题:

  • JS、CSS 资源无法并行加载,从而降低页面性能;
  • 资源缓存粒度变大,JS、CSS 任意一种变更都会致使缓存失效。

所以 style-loader 在生产环境中不使用,使用 mini-css-extract-plugin 插件代替 style-loader,将样式代码抽离成单独的css 文件。

mini-css-extract-plugin

用于抽离 css

安装

bash
npm i mini-css-extract-plugin -D

配置:在开发环境使用 style-loader,在生产环境使用 mini-css-extract-plugin 插件

js
const { resolve } = require('path')
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
const HtmlWebpackPlugin = require('html-webpack-plugin')

module.exports = () => ({
  mode: 'none',
  entry: {
    main: './src/index.js',
    component: './src/component.js'
  },
  output: {
    filename: '[name].js',
    path: resolve(__dirname, './dist')
  },
  module: {
    rules: [{
      test: /\.css$/i,
      use: [
        // 根据运行环境判断使用那个 loader
        (process.env.NODE_ENV === 'development' ?
          'style-loader' :
          MiniCssExtractPlugin.loader),
        'css-loader'
      ]
    }]
  },
  plugins: [
    new MiniCssExtractPlugin(),
    new HtmlWebpackPlugin()
  ]
})

打包后的css就是抽离出来了的

image-20240821154856127

需要注意的是:

  • mini-css-extract-plugin 库同时提供 Loader、Plugin 组件,需要同时使用
  • mini-css-extract-plugin 不能与 style-loader 混用,否则报错
  • mini-css-extract-plugin 需要与 html-webpack-plugin 同时使用,才能将产物路径以 link 标签方式插入到 html 中

image-20240821155046155

预处理器 less、sass、stylus

在项目开发的时候,经常会使用到一些预处理器,可以借助相应的 loader 将它们先转成 css

以 less 为例:

less
@color: blue;
@fontSize: 24px;

.content {
    color: @color;
    font-size: @fontSize;
}

安装 less 和 less-loader

bash
npm i less less-loader -D

配置

js
module.exports = {
  module: {
    rules: [{
      test: /\.less$/i,
      use: [
        // 根据运行环境判断使用那个 loader
        (process.env.NODE_ENV === 'development' ?
          'style-loader' :
          MiniCssExtractPlugin.loader),
        'css-loader',
        'less-loader'
      ]
    }]
  },
}

其他预处理器

sass

bash
npm i -D sass sass-loader
js
module.exports = {
    module: {
        rules: [{
          test: /\.s(ac)ss$/i,
          use: [
            'style-loader',
            'css-loader',
        	'sass-loader'
          ]
        }]
    }
}

stylus

bash
npm i -D stylus stylus-loader
js
module.exports = {
    module: {
        rules: [{
          test: /\.styl$/i,
          use: [
            'style-loader',
            'css-loader',
        	'stylus-loader'
          ]
        }]
    }
}

PostCSS

PostCSS 并没有定义一门新的语言,只是实现了一套将 CSS 源码解析为 AST 结构,并传入 PostCSS 插件做处理的流程框架,具体功能都是由插件实现。这个工具可以帮助我们进行一些CSS的转换和适配,比如自动添加浏览器前缀、css样式的重置。

预处理器之于 CSS,就像 TypeScript 与 JavaScript 的关系;而 PostCSS 之于 CSS,则更像 Babel 与 JavaScript。

自动添加浏览器前缀案例:

bash
npm i postcss postcss-loader autoprefixer -D

通过 webpack.config.js 来配置

js
module: {
    rules: [{
      test: /\.css$/i,
      use: [
        // 根据运行环境判断使用那个 loader
        (process.env.NODE_ENV === 'development' ?
          'style-loader' :
          MiniCssExtractPlugin.loader),
        'css-loader',
        {
          loader: "postcss-loader",
          options: {
            postcssOptions: {
              // 添加 autoprefixer 插件
              plugins: [require("autoprefixer")],
            },
          },
        }
      ]
    }]
}

也可以抽离出来,通过 postcss.config.js 配置文件来进行配置

js
module.exports = {
  plugins: [
    require('autoprefixer')
  ]
}

也可以通过 postcss.json 配置文件来进行配置

json
{
    "plugins":["autoprefixer"]
}

user-select: none; 来举例

css
.content {
  color: blue;
  font-size: 24px;
  user-select: none;
}

经过插件处理后自动加上了浏览器前缀

css
.content {
  color: blue;
  font-size: 24px;
  -webkit-user-select: none;
     -moz-user-select: none;
          user-select: none;
}

PostCSS 最大的优势在于其简单、易用、丰富的插件生态,基本上已经能够覆盖样式开发的方方面面。实践中,经常使用的插件有:

  • autoprefixer:基于 Can I Use 网站上的数据,自动添加浏览器前缀
  • postcss-preset-env:一款将最新 CSS 语言特性转译为兼容性更佳的低版本代码的插件,比如他会将8位数的颜色格式转为RGBA格式的颜色,并且它内置了 autoprefixer 功能。
  • postcss-less:兼容 Less 语法的 PostCSS 插件,类似的还有:postcss-sasspoststylus
  • stylelint:一个现代 CSS 代码风格检查器,能够帮助识别样式代码中的异常或风格问题

Released under the MIT License.