02-打包CSS资源

86 阅读3分钟

打包CSS资源

css-loader

前面说过,webpack只能识别js和json作为模块,如果你在代码中引入css无法识别并报错。

配置css-loader

这里介绍CSS的loader,因为最常用:

body {
  background-color: black;
}
// 下载css-loader的包
const MODULE = {
  rules: [
    {
      test: /\.css$/, // 匹配以.css结尾的文件
      use: ['css-loader'], // 使用 css-loader 处理
    }
  ]
}

打包发现,诶为啥css没有生效?

css-loader只负责识别css语法并支持模块化,import style from 'xx.css' 文件发现,style输出一个数组,css-loader确实已经帮我们完成了模块的转化!

// 第一元素是
[
  './src/assets/css/global.css', 
  'body {\n  background-color: black;\n}', 
  ''
]

哦,原来如此,css-loader只是完成了转换和识别(模块化),但是真正作用到页面需要将CSS插入到页面上,这个功能需要其它的loader帮助我们完成。

内联style插入样式

style-loader

style-loader就是专门做这件事(将css-loader打包结果插入到html)的loader

// 下载style-loader的包
const MODULE = {
  rules: [
    {
      test: /\.css$/, // 匹配以.css结尾的文件
      use: ['style-loader', 'css-loader'], // 先使用 css-loader 处理,在经过style-loader动态创建style标签插入到页面里
    }
  ]
}

打包发现,生效了,但是我们发现style这个变量的值变成了 undefined,因为style-loader最后处理完之后没有返回任何东西(它不需要对外暴露任何东西)

外联打包成单独的文件link链入样式

mini-css-extract-plugin

mini-css-extract-plugin提供了一个loader方法属性,MiniCssExtractPlugin.loader 简单的处理一下 css-loader 转换的对象

// 抽离css; extract => 提取 +++
const MiniCssExtractPlugin = require('mini-css-extract-plugin')

const MODULE = {
  rules: [
    {
      test: /\.css$/,
      use: [MiniCssExtractPlugin.loader, 'css-loader'],
    }
  ]
}

// 加入 plugins
let plugins = [
  ...plugins,
  new MiniCssExtractPlugin({
    // 传入打包的各种配置
    filename: 'style/[name][contenthash:8].css'
  }),
]

兼容低版本的浏览器 CSS前缀

github-postcsswebpack-postcss

postcss是一个css预处理器,能够增强css的功能,但是它又不像less、sass那样,而是集成在webpack中,postcss有很多功能,为了细化功能,它将一个个功能细化为plugin,因此,当我们需要一些功能的时候需要安装对应的插件列表:

  • autoprefixer 自动添加前缀
  • postcss-nested 支持css嵌套写法
// webpack.config.js
let loaderRules = [
  ...loaderRules,
  {
    test: /\.css$/, 
    use: [
      'style-loader', {
        loader: 'css-loader',
        // 假设一个css写了 @import ...,那么postcss-loader不会处理,等到了css-loader的时候,css-loader才开始识别到了 是另外的一个模块,但是 css-loader 无法为现在匹配到的  @import ... 用 postcss-loader,因此为了让 css-loader匹配到别的css模块的时候,回头n次,再顺序执行loader。这里回头一次就是 postcss-loader
        importLoaders: 1,
      }, 
      'postcss-loader'
    ], 
  }
]
/*
不过需要注意的是,options.importLoaders需要考虑是否设置对应的值 
[css-loader-importLoaders](https://github.com/webpack-contrib/css-loader#importloaders)
*/

// create postcss.config.js
module.exports = {
  // 记得 npm i -D 一下
  plugins: [
    require('autoprefixer'),
    require('postcss-nested')
  ]
}

npx webpack 打包发现确实可以支持嵌套写法的,但是autoprefixer为啥没生效?postcss-autoprefixer

我们的在package.json下面添加配置:

{
  "browserslist": [
    ">1%",
    "last 2 versions"
  ]
}
/* 如果你需要设置环境的话需要 cross-env */
// {
//   "browserslist": {
//     "production": [
//       ">0.2%",
//       "not dead",
//       "not op_mini all"
//     ],
//     "development": [
//       "last 1 chrome version",
//       "last 1 firefox version",
//       "last 1 safari version",
//       "last 1 ie version"
//     ]
//   }
// }

CSS模块化

CSS Module 由css-loader支持,配置css-loader的options的

let cssLoader = {
  loader: 'css-loader',
  options: {
    modules: true,
  }
}

其实css-loader可以对以 .module.css结尾的文件自动的开启module模块化功能。

压缩CSS资源

css-minimizer-webpack-plugin

js可以压缩,那么CSS肯定也可以,压缩都是通过插件,那么CSS的压缩插件:

// 压缩css
const CssMinimizerPlugin = require("css-minimizer-webpack-plugin");

const optimization = {
  minimize: true, // 这个必须为true,当然默认是true,可以根据不同的环境考虑是否需要压缩
  minimizer: [
    new CssMinimizerPlugin(),
  ],
}

// 别忘了修改mode为production
const mode = 'production'

CSS编译器

如果需要集成其他的css编译器,需要安装对应的编译器包和翻译官:比如less、less-loader,在loader里配置less-loader即可

let rules = [
  {
    test: /\.less$/,
    use: ['style-loader', 'css-loader', 'less-loader']
  }
]

CSS引入的其他资源怎么办

css-loader在新版本已经自动的帮你处理好了,在之前需要url-loader和file-loader帮你做文件模块化,现在不需要了。当然这也带来个问题css-loader只是帮你打包了引用的资源,但是并未帮你模块化,如何解决?

  • file-loader出场,但是css-loader和file-loader功能冲突,会打包出两张图片,需要配置css-loader的options的url为false(具体参照css-loader的最新文档)

  • webpack5的asset资源模块(具体如何下节分析)

总结

本次代码参照 code-example / 02-example

需要注意的是,这里所有的loader都说的很简略,其实当真正用的时候才发现,每个loader都十分强大,有各种配置可以供你选择(比如less-loader可以替换解析的内容,css-loader的module有多种类型),如果遇到复杂的场景,需要我们自己去 查文档