加载样式

因为不能在Webpack之外处理样式,因此你不得不用loaders和plugins加载样式文件。在这一章,你将在项目中配置css,看看它如何在浏览器中自动刷新。当你改变css时,不用强制刷新全部。此外,实现css的自动补全。

加载 CSS

为了加载css文件,你需要用 css-loaderstyle-loadercss-loader 遍历查找所有的 @import and url() 引入的文件,对待他们就像 ES2015 import 一样。如果有 @import 引入项目外部的资源, css-loader 将跳过它,因为webpack只能处理项目内部资源。

style-loader 将文件中的样式注入到 style 元素内。这种实现方式可以被自定义,它实现的 Hot Module Replacement 接口,提供了一个令人愉快的开发体验。

匹配的文件也可以被 file-loaderurl-loader 处理, 这些内容将在书中的 Loading Assets 部分讲解。

由于内联css(将css样式打包到于js文件中),在生产中不是一个好的想法,而用 MiniCssExtractPlugin 插件将所有的样式打包到一个独立的css文件中是很有意义的。这将在下一章中实现。

首先,引入相关依赖

npm install css-loader style-loader --save-dev

现在让我们来确定webpack已经知道了他们的存在。在末尾部分定义如下一个新函数:

webpack.parts.js

exports.loadCSS = ({ include, exclude } = {}) => ({
  module: {
    rules: [
      {
        test: /\.css$/,
        include,
        exclude,

        use: ["style-loader", "css-loader"],
      },
    ],
  },
});

你也需要链接初始的配置片段:

webpack.config.js

const commonConfig = merge([
  ...
  parts.loadCSS(),
]);

添加的配置的意思是,以 .css 结尾的文件应该调用给定的loaders。test 匹配一个js风格的正则表达式。

Loaders是一个转换器,它将源文件转换成新的源文件,这些新的源文件像一条链子一样被穿了起来,就像Unix中的管道一样。它们被评估(验证)的方向是自右向左,这意味着 loaders: ["style-loader", "css-loader"] 读起来可能是 styleLoader(cssLoader(input)) 的样子。

如果你不想处理 url ,可以在 css-loader 设置配置为 url: false,同理你也可以设置 @import 的。你不想处理标准的 ES6 的 import ,你可以设置loader的配置项t import: false

如果你不需要 HMR 功能,同时需要ie支持source-maps,你可以考虑用 micro-style-loader 代替 style-loader.

添加初始化的CSS

定义一个 src/main.css 文件,代码如下:

body {
  background: cornsilk;
}

在入口文件 src/index.js 中,引入 src/main.css 文件:

import "./main.css";
...

执行 npm start ,然后在浏览器地址栏中输入 http://localhost:8080 ,然后按下回车键,紧接着打开 main.css 并改变背景颜色值为任意值,如:lime (background: lime)。

到这里,你学习了样式相关的技术,下一章将紧接这里来讲。

Hello cornsilk world

附录中的 CSS Modules 部分介绍了一种允许你处理本地文件的默认方法。它避免了css作用于的问题。

加载 Less

Less

Less 是一个充满函数化特性的 CSS 处理器。webpack 不用花费大量精力处理less, 这个繁重的任务由 less-loader 完成。你应该安装 lessless-loader (注意:与webpack同系列的版本)。

配置修改如下:

{
  test: /\.less$/,
  use: ["style-loader", "css-loader", "less-loader"],
},

less-loader 支持 Less 插件,source-map等等。具体使用可阅读less

加载 Sass

Sass

Sass 是一款被广泛使用的 CSS 预处理器。你可以用 sass-loader 处理它。记住安装它同系列的 node-sass 依赖。

配置修改如下:

{
  test: /\.scss$/,
  use: ["style-loader", "css-loader", "sass-loader"],
},

如果你有一个更高的性能需求,你可以尝试 fast-sass-loader.

加载 Stylus 和 Yeticss

Stylus

Stylus 也是一款 CSS 处理器。你可以用 stylus-loader 处理它。 yeticss 以库的形式被使用。

配置修改如下:

{
  ...
  module: {
    rules: [
      {
        test: /\.styl$/,
        use: [
          "style-loader",
          "css-loader",
          {
            loader: "stylus-loader",
            options: {
              use: [require("yeticss")],
            },
          },
        ],
      },
    ],
  },
},

在Stylus中使用Yeticss,你一定要在你的 .styl 文件中引入它:

@import "yeticss"
//or
@import "yeticss/components/type"

PostCSS

PostCSS

PostCSS 转换到 CSS 通过js插件。你甚至可以找到类Sass风格的插件。PostCSS 就是样式界里的 Babel。你可以在webpack中使用 postcss-loader

下面的例子讲述了css-rule自动补充前缀的实现,它使用PostCss来实现配置。同时它配置了一个 precss 插件,该插件允许你写类Sass风格的样式。你也可以使用其他loader实现自动补全前缀,然后结合PostCss一起来使用。

{
  test: /\.css$/,
  use: [
    "style-loader",
    "css-loader",
    {
      loader: "postcss-loader",
      options: {
        plugins: () => ([
          require("autoprefixer"),
          require("precss"),
        ]),
      },
    },
  ],
},

在这之前,你应该先引入 autoprefixerprecss 这两个依赖。这个技术将在 Autoprefixing 这一章详细介绍。

PostCSS 支持 postcss.config.js 这样的配置形式。它的内部依赖 cosmiconfig 来支持其他格式。

cssnext

cssnext 是一个 PostCSS 插件,它实现在一定限制下体验未来的css。你可以使用它,通过引入 postcss-cssnext 依赖并启动它,配置如下:

{
  use: {
    loader: "postcss-loader",
    options: {
      plugins: () => [require("postcss-cssnext")()],
    },
  },
},

参考 cssnext 官方文档,了解好用的配置项。

cssnext 包含 autoprefixer 功能! 所以你使用它的时候不用,额外的添加autoprefixer实现。

理解查找机制(Understanding Lookups)

为了充分的历用 css-loader,你应该了解它的查找机制是如何执行的。虽然在默认情况下css-loader 执行相对导入,但是它也不会影响绝对导入("url('/static/img/demo.png')")。如果依赖于这种导入方式(绝对导入),你将需要复制一份文件到项目中。

copy-webpack-plugin 工作为这种情况,同样你也可以赋值webpack之外的文件。前一种方法的好处是webpack-dev-server 可以从中获益。

resolve-url-loader在你使用Sass或Less的时候会派上用场。它为环境添加了对相对导入的支持。

css-loader 定制化处理导入(Processing css-loader Imports)

如果你想 css-loader 按照指定的方式处理引入的文件,你应该对配置项的 importLoaders 进行设置,选项值为一个数字,这个数字代表 css-loader 在处理引入的文件之前有几个loader已经执行。 如果你从源文件(css类型)中,使用 @import 语法引入了不同类型的css文件,并且你想制定的loader处理制定的css文件的话,那么你需要使用这个技术。

接上面的配置,在 ./main.css 中引入一个sass文件:

@import "./variables.sass";

添加处理sass文件的配置:

{
  test: /\.css$/,
  use: [
    "style-loader",
    {
      loader: "css-loader",
      options: {
        importLoaders: 1,
      },
    },
    "sass-loader",
  ],
},

如果你想添加更多的loader,如:postcss-loader,你需要根据需求来调整 importLoaders

node_modules 目录中加载

你也可以直接从 node_modules 目录中加载。以 Bootstrap 为例:

@import "~bootstrap/less/bootstrap";

这个波浪号 (~) 告诉webpack这不是默认的相对引入。如果添加了这个波浪号,webpack的查找目标就是 node_modules (这是一个默认设置),但你可以通过 resolve.modules 来修该指代的目录。

W> 如果你使用 postcss-loader ,你可以跳过使用 ~ ,具体原因可阅读 postcss-loader issue trackerpostcss-loader 解析了引入路径中的波浪号。

开启 Source-Maps

如果你想要CSS使用source-map,你需要配置 css-loadersourceMap 选项来开启这个功能,并 设置 output.publicPath 的路径为你的开发服务器路径。如果你链式的使用多个loader,你需要为所有的loader开启 sourceMapcss-loader 这个问题 issue 29 的深度讨论。

转化 CSS 为 Strings

Angular 2 就是这样实现的,这样做是因为,你可以方便的操作哪些被传入组件中的字符串形式的css。css-to-string-loader 实现这个功能。

使用 Bootstrap

Webpack 有多种方法使用 Bootstrap。其中一种选择是 npm version 然后执行上面配置的loader。

Sass version 是其他一种选择。使用这种方式,你需要设置 sass-loaderprecision 选项,它的值至少为8。有一个 常见问题bootstrap-sass 官方给出了解释。

第三种选择使用 bootstrap-loader。它提供了很多功能,同时也支持自定义。

结论

Webpack可以加载多种格式的文件。以上讲的方法,在默认情况下将样式打包到Javascript包中。

回顾:

  • css-loader 评估(验证是否存在) @importurl() 声明的样式文件。style-loader 转换并注入到js文件中,提供webpack可使用的 Hot Module Replacement 热交换接口。
  • Webpack 支持使用不同的loader来转换不同类型的样式文件到css。包含 Sass, Less, 和 Stylus类型。
  • PostCSS 允许你在 CSS 中注入函数,同它的插件生态系统来完成转换。cssnext 是一个支持未来css样式的插件集合,PostCSS可以引用它。
  • css-loader 默认情况下不影响绝对引用。你可以通过 importLoaders 选项来自定义引入。你可以通过向路径开始注入波浪号(~)来引入 node_modules 目录的文件。
  • 要使用 source-map,你必须设置 sourceMap 的配置为 true,如果你也使用了其它的样式loader,你也需要开启它们的 sourceMap 的配置。此外,你还需要设置 output.publicPath 的为开发服务起的绝对路径地址。
  • 在webpack中使用 Bootstrap,你需要特别小心。你既可以使用普通的loader,也可以使用 bootstrap-loader

虽然这里讲了足够多的用于开发模式的加载方案,但是用于生产模式并不理想。你将在下一章学习如何实现从源文件中分割CSS。