# style

> 在打包器，比如 webpack 中，需要借用 loader 将非 JS 资源转化成可识别为 Javascript 的 module。 在 webpack 中，处理 css 稍微比较费劲，需要借用两个 loader 来做成这件事情: 1. $1: 处理 CSS 中的 url 与 @import ，并将其作为模块引入 1. $1: 将样式注入

- 发布于: 2019-04-14
- 更新于: 2026-09-30
- 原文: https://shanyue.tech/posts/frontend-engineering/style/
- 标签: frontend-engineering
- 专栏: 前端工程化

---

在打包器，比如 webpack 中，需要借用 `loader` 将非 JS 资源转化成可识别为 Javascript 的 module。

在 webpack 中，处理 css 稍微比较费劲，需要借用两个 loader 来做成这件事情:

```js
module.exports = {
  module: {
    rules: [
      {
        test: /\.css$/,
        use: ["style-loader", "css-loader"],
      },
    ],
  },
};
```

1. [css-loader](https://github.com/webpack-contrib/css-loader): 处理 CSS 中的 `url` 与 `@import`，并将其作为模块引入
1. [style-loader](https://github.com/webpack-contrib/style-loader): 将样式注入到 DOM 中

```css
@import url(./basic.css);

.bg {
  background: url(./shanyue.png);
}
```

如果说现代前端中 Javascript 与 CSS 是其中最重要的两种资源，那么 `Babel` 与 `PostCSS` 就是前端工程化中最有影响力的两个编译器。

`css-loader` 的原理就是 postcss，借用 `postcss-value-parser` 解析 CSS 为 AST，并将 CSS 中的 `url()` 与 `@import` 解析为模块。

`style-loader` 用以将 CSS 注入到 DOM 中，原理为使用 DOM API 手动构建 `style` 标签，并将 CSS 内容注入到 `style` 中。

在其源码实现中，借用了许多运行时代码 [style loader runtime](https://github.com/webpack-contrib/style-loader/tree/master/src/runtime)，而最简单的实现仅仅需要几行代码:

```js
module.exports = function (source) {
  return `
function injectCss(css) {
  const style = document.createElement('style')
  style.appendChild(document.createTextNode(css))
  document.head.appendChild(style)
}

injectCss(\`${source}\`)
  `;
};
```

使用 DOM API 加载 CSS 资源，由于 CSS 需要在 JS 资源加载完后通过 DOM API 控制加载，容易出现页面抖动，在线上低效且性能低下。且对于 SSR 极度不友好。

由于性能需要，在线上通常需要单独加载 CSS 资源，这要求打包器能够将 CSS 打包，此时需要借助于 [mini-css-extract-plugin](https://github.com/webpack-contrib/mini-css-extract-plugin) 将 CSS 单独抽离出来。

深入 webpack 中如何抽离 CSS 的源码有助于加深对 webpack 的理解。
