style-loader

免责声明 style-loader是一个由社区成员维护的第三方包,它可能不具备与 webpack 相同的支持、安全策略或许可证,并且不受 webpack 维护。

npm node tests coverage discussion size

将 CSS 注入到 DOM 中。

入门

首先,你需要安装 style-loader

npm install --save-dev style-loader

yarn add -D style-loader

pnpm add -D style-loader

建议将 style-loadercss-loader 结合使用

然后将加载器添加到你的 webpack 配置中。例如:

style.css

body {
  background: green;
}

component.js

import "./style.css";

webpack.config.js

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

安全警告

此加载器主要用于开发。默认设置不适用于生产环境。有关详细信息,请参阅推荐的示例配置和关于nonce的部分。

选项

injectType

类型

type injectType =
  | "styleTag"
  | "singletonStyleTag"
  | "autoStyleTag"
  | "lazyStyleTag"
  | "lazySingletonStyleTag"
  | "lazyAutoStyleTag"
  | "linkTag";

默认值:styleTag

允许你设置样式如何注入到 DOM 中。

可能的值

styleTag

使用多个 <style></style> 标签自动将样式注入到 DOM 中。这是**默认**行为。

component.js

import "./styles.css";

使用 Locals (CSS Modules) 的示例

component-with-css-modules.js

import * as styles from "./styles.css";

const divElement = document.createElement("div");
divElement.className = styles["my-class"];

所有局部变量(类名)都作为命名导出。要实现此行为,你还必须为 css-loader 设置 modules 选项。有关更多信息,请查阅 css-loader 文档

webpack.config.js

module.exports = {
  module: {
    rules: [
      {
        test: /\.css$/i,
        use: [
          // The `injectType`  option can be avoided because it is default behaviour
          { loader: "style-loader", options: { injectType: "styleTag" } },
          {
            loader: "css-loader",
            // Uncomment it if you want to use CSS modules
            // options: { modules: true }
          },
        ],
      },
    ],
  },
};

该加载器注入的样式如下

<style>
  .foo {
    color: red;
  }
</style>
<style>
  .bar {
    color: blue;
  }
</style>

singletonStyleTag

使用单个 <style></style> 标签自动将样式注入到 DOM 中。

[!警告]

源映射不起作用。

component.js

import "./styles.css";

component-with-css-modules.js

import * as styles from "./styles.css";

const divElement = document.createElement("div");
divElement.className = styles["my-class"];

所有局部变量(类名)都作为命名导出。要实现此行为,你还必须为 css-loader 设置 modules 选项。有关更多信息,请查阅 css-loader 文档

webpack.config.js

module.exports = {
  module: {
    rules: [
      {
        test: /\.css$/i,
        use: [
          {
            loader: "style-loader",
            options: { injectType: "singletonStyleTag" },
          },
          {
            loader: "css-loader",
            // Uncomment it if you want to use CSS modules
            // options: { modules: true }
          },
        ],
      },
    ],
  },
};

该加载器注入的样式如下

<style>
  .foo {
    color: red;
  }
  .bar {
    color: blue;
  }
</style>

autoStyleTag

styleTag 的工作方式相同,但如果代码在 IE6-9 中执行,则会开启 singletonStyleTag 模式。

lazyStyleTag

按需使用多个 <style></style> 标签将样式注入到 DOM 中。

我们建议对按需加载的样式遵循 .lazy.css 命名约定,对于 style-loader 的基本用法遵循 .css (类似于其他文件类型,例如 .lazy.less.less)。

当你使用 lazyStyleTag 值时,style-loader 会按需惰性注入样式,使其可以通过 style.use() / style.unuse() 按需使用。

⚠️ 当 unuse 的调用次数多于 use 时,行为是未定义的。请勿这样做。

component.js

import styles from "./styles.lazy.css";

styles.use();
// For removing styles you can use
// styles.unuse();

component-with-css-modules.js

import styles, { "my-class" as myClass } from "./styles.lazy.css";

styles.use();

const divElement = document.createElement("div");
divElement.className = myClass;

所有局部变量(类名)都作为命名导出。要实现此行为,你还必须为 css-loader 设置 modules 选项。有关更多信息,请查阅 css-loader 文档

webpack.config.js

module.exports = {
  module: {
    rules: [
      {
        test: /\.css$/i,
        exclude: /\.lazy\.css$/i,
        use: ["style-loader", "css-loader"],
      },
      {
        test: /\.lazy\.css$/i,
        use: [
          { loader: "style-loader", options: { injectType: "lazyStyleTag" } },
          {
            loader: "css-loader",
            // Uncomment it if you want to use CSS modules
            // options: { modules: true }
          },
        ],
      },
    ],
  },
};

该加载器注入的样式如下

<style>
  .foo {
    color: red;
  }
</style>
<style>
  .bar {
    color: blue;
  }
</style>

lazySingletonStyleTag

按需使用单个 <style></style> 标签将样式注入到 DOM 中。

我们建议对按需加载的样式遵循 .lazy.css 命名约定,对于 style-loader 的基本用法遵循 .css (类似于其他文件类型,例如 .lazy.less.less)。

当你使用 lazySingletonStyleTag 值时,style-loader 会按需惰性注入样式,使其可以通过 style.use() / style.unuse() 按需使用。

⚠️ 源映射不起作用。

⚠️ 当 unuse 的调用次数多于 use 时,行为是未定义的。请勿这样做。

component.js

import styles from "./styles.css";

styles.use();
// For removing styles you can use
// styles.unuse();

component-with-css-modules.js

import styles, { "my-class" as myClass } from "./styles.lazy.css";

styles.use();

const divElement = document.createElement("div");
divElement.className = myClass;

所有局部变量(类名)都作为命名导出。要实现此行为,你还必须为 css-loader 设置 modules 选项。有关更多信息,请查阅 css-loader 文档

webpack.config.js

module.exports = {
  module: {
    rules: [
      {
        test: /\.css$/i,
        exclude: /\.lazy\.css$/i,
        use: ["style-loader", "css-loader"],
      },
      {
        test: /\.lazy\.css$/i,
        use: [
          {
            loader: "style-loader",
            options: { injectType: "lazySingletonStyleTag" },
          },
          {
            loader: "css-loader",
            // Uncomment it if you want to use CSS modules
            // options: { modules: true }
          },
        ],
      },
    ],
  },
};

该加载器生成如下

<style>
  .foo {
    color: red;
  }
  .bar {
    color: blue;
  }
</style>

lazyAutoStyleTag

lazyStyleTag 的工作方式相同,但如果代码在 IE6-9 中执行,则会开启 lazySingletonStyleTag 模式。

linkTag

使用多个 <link rel="stylesheet" href="path/to/file.css"> 标签将样式注入到 DOM 中。

ℹ️ 该加载器将在运行时通过 JavaScript 动态插入 <link href="path/to/file.css" rel="stylesheet"> 标签。如果你想包含一个静态的 <link href="path/to/file.css" rel="stylesheet">,你应该使用 MiniCssExtractPlugin

import "./styles.css";
import "./other-styles.css";

webpack.config.js

module.exports = {
  module: {
    rules: [
      {
        test: /\.link\.css$/i,
        use: [
          { loader: "style-loader", options: { injectType: "linkTag" } },
          { loader: "file-loader" },
        ],
      },
    ],
  },
};

该加载器生成如下

<link rel="stylesheet" href="path/to/style.css" />
<link rel="stylesheet" href="path/to/other-styles.css" />

attributes

类型

type attributes = HTMLAttributes;

默认值:{}

如果定义,style-loader 会将给定的属性及其值附加到 <style> / <link> 元素上。

component.js

import "./file.css";

webpack.config.js

module.exports = {
  module: {
    rules: [
      {
        test: /\.css$/i,
        use: [
          { loader: "style-loader", options: { attributes: { id: "id" } } },
          { loader: "css-loader" },
        ],
      },
    ],
  },
};
<style id="id"></style>

insert

类型

type insert = string;

默认值:head

默认情况下,style-loader 会将 <style>/<link> 元素附加到样式目标的末尾,即页面的 <head> 标签,除非由 insert 指定。

这将导致由加载器创建的 CSS 优先于目标中已存在的 CSS。

如果标准行为不适合你,可以使用其他值,但我们不建议这样做。

如果你指定目标为 iframe,请确保你有足够的访问权限;样式将被注入到内容文档的头部。

Selector

允许你设置自定义的 查询选择器,以确定样式注入到 DOM 的位置。

webpack.config.js

module.exports = {
  module: {
    rules: [
      {
        test: /\.css$/i,
        use: [
          {
            loader: "style-loader",
            options: {
              insert: "body",
            },
          },
          "css-loader",
        ],
      },
    ],
  },
};

函数的绝对路径

允许你设置自定义函数的绝对路径,该函数可以覆盖默认行为并在任何位置插入样式。

[!警告]

请记住,此代码将在浏览器中使用,并非所有浏览器都支持最新的 ECMA 特性,例如 letconstarrow function expression 等。我们建议使用 babel-loader 来支持最新的 ECMA 特性。

[!警告]

请记住,某些 DOM 方法可能在旧版浏览器中不可用。我们建议只使用 DOM 核心级别 2 属性,但这取决于你希望支持哪些浏览器。

webpack.config.js

module.exports = {
  module: {
    rules: [
      {
        test: /\.css$/i,
        use: [
          {
            loader: "style-loader",
            options: {
              insert: require.resolve("./path-to-insert-module"),
            },
          },
          "css-loader",
        ],
      },
    ],
  },
};

新的 <style>/<link> 元素将被插入到 body 标签的底部。

示例

head 标签顶部插入样式

insert-function.js

function insertAtTop(element) {
  var parent = document.querySelector("head");
  // eslint-disable-next-line no-underscore-dangle
  var lastInsertedElement = window._lastElementInsertedByStyleLoader;

  if (!lastInsertedElement) {
    parent.insertBefore(element, parent.firstChild);
  } else if (lastInsertedElement.nextSibling) {
    parent.insertBefore(element, lastInsertedElement.nextSibling);
  } else {
    parent.appendChild(element);
  }

  // eslint-disable-next-line no-underscore-dangle
  window._lastElementInsertedByStyleLoader = element;
}

module.exports = insertAtTop;

webpack.config.js

module.exports = {
  module: {
    rules: [
      {
        test: /\.css$/i,
        use: [
          {
            loader: "style-loader",
            options: {
              insert: require.resolve("./insert-function"),
            },
          },
          "css-loader",
        ],
      },
    ],
  },
};

你可以将任何参数传递给 style.use(options),这个值将被传递给 insertstyleTagTransform 函数。

insert-function.js

function insertIntoTarget(element, options) {
  var parent = options.target || document.head;

  parent.appendChild(element);
}

module.exports = insertIntoTarget;

webpack.config.js

module.exports = {
  module: {
    rules: [
      {
        test: /\.css$/i,
        use: [
          {
            loader: "style-loader",
            options: {
              injectType: "lazyStyleTag",
              // Do not forget that this code will be used in the browser and
              // not all browsers support latest ECMA features like `let`, `const`, `arrow function expression` and etc,
              // we recommend use only ECMA 5 features,
              // but it depends what browsers you want to support
              insert: require.resolve("./insert-function.js"),
            },
          },
          "css-loader",
        ],
      },
    ],
  },
};

将样式插入到提供的元素中,如果未提供目标,则插入到 head 标签中。现在你可以将样式注入到 Shadow DOM(或任何其他元素)中。

custom-square.css

div {
  width: 50px;
  height: 50px;
  background-color: red;
}

custom-square.js

import customSquareStyles from "./custom-square.css";

class CustomSquare extends HTMLElement {
  constructor() {
    super();

    this.attachShadow({ mode: "open" });

    const divElement = document.createElement("div");

    divElement.textContent = "Text content.";

    this.shadowRoot.appendChild(divElement);

    customSquareStyles.use({ target: this.shadowRoot });

    // You can override injected styles
    const bgPurple = new CSSStyleSheet();
    const width = this.getAttribute("w");
    const height = this.getAttribute("h");

    bgPurple.replace(`div { width: ${width}px; height: ${height}px; }`);

    this.shadowRoot.adoptedStyleSheets = [bgPurple];

    // `divElement` will have `100px` width, `100px` height and `red` background color
  }
}

customElements.define("custom-square", CustomSquare);

export default CustomSquare;

styleTagTransform

类型

type styleTagTransform = string;

默认值:undefined

字符串

允许你设置自定义函数的绝对路径,该函数可以覆盖默认的 styleTagTransform 行为。

[!警告]

请记住,此代码将在浏览器中使用,并非所有浏览器都支持最新的 ECMA 特性,例如 letconstarrow function expression 等。我们建议只使用 ECMA 5 特性,但这取决于你希望支持哪些浏览器。

[!警告]

请记住,某些 DOM 方法可能在旧版浏览器中不可用。我们建议只使用 DOM 核心级别 2 属性,但这取决于你希望支持哪些浏览器。

webpack.config.js

module.exports = {
  module: {
    rules: [
      {
        test: /\.css$/i,
        use: [
          {
            loader: "style-loader",
            options: {
              injectType: "styleTag",
              styleTagTransform: require.resolve("style-tag-transform-code"),
            },
          },
          "css-loader",
        ],
      },
    ],
  },
};

base

type base = number;

此设置主要用作在使用一个或多个 DllPlugin 时解决 CSS 冲突的变通方法。base 允许你通过指定一个大于 DllPlugin1 使用范围的 CSS 模块 ID 基准,来防止应用的 CSS(或 DllPlugin2 的 CSS)覆盖 DllPlugin1 的 CSS,例如:

webpack.dll1.config.js

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

webpack.dll2.config.js

module.exports = {
  module: {
    rules: [
      {
        test: /\.css$/i,
        use: [
          { loader: "style-loader", options: { base: 1000 } },
          "css-loader",
        ],
      },
    ],
  },
};

webpack.app.config.js

module.exports = {
  module: {
    rules: [
      {
        test: /\.css$/i,
        use: [
          { loader: "style-loader", options: { base: 2000 } },
          "css-loader",
        ],
      },
    ],
  },
};

esModule

类型

type esModule = boolean;

默认值:true

默认情况下,style-loader 生成使用 ES 模块语法的 JS 模块。

在某些情况下,使用 ES 模块是有益的,例如模块串联摇树优化

你可以使用以下方式启用 CommonJS 模块语法

webpack.config.js

module.exports = {
  module: {
    rules: [
      {
        test: /\.css$/i,
        loader: "style-loader",
        options: {
          esModule: false,
        },
      },
    ],
  },
};

示例

推荐

对于 production 构建,建议从你的 bundle 中提取 CSS,以便稍后并行加载 CSS/JS 资源。这可以通过使用 mini-css-extract-plugin 实现,因为它会创建单独的 CSS 文件。对于 development 模式(包括 webpack-dev-server),你可以使用 style-loader,因为它使用多个 <style></style> 标签将 CSS 注入到 DOM 中,并且工作速度更快。

[!警告]

不要同时使用 style-loadermini-css-extract-plugin

webpack.config.js

const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const devMode = process.env.NODE_ENV !== "production";

module.exports = {
  module: {
    rules: [
      {
        test: /\.(sa|sc|c)ss$/,
        use: [
          devMode ? "style-loader" : MiniCssExtractPlugin.loader,
          "css-loader",
          "postcss-loader",
          "sass-loader",
        ],
      },
    ],
  },
  plugins: [].concat(devMode ? [] : [new MiniCssExtractPlugin()]),
};

CSS 模块的命名导出

[!警告]

不允许在 CSS 类名中使用 JavaScript 保留字。

[!警告]

css-loader 中的 esModulemodules.namedExport 选项应启用(css-loader@7 默认启用)。

styles.css

.fooBaz {
  color: red;
}
.bar {
  color: blue;
}
.my-class {
  color: green;
}

index.js

import { fooBaz, bar, "my-class" as myClass } from "./styles.css";

console.log(fooBaz, bar, myClass);

或者

index.js

import * as styles from "./styles.css";

console.log(styles.fooBaz, styles.bar, styles["my-class"]);

你可以使用以下方式启用 ES 模块命名导出

webpack.config.js

module.exports = {
  module: {
    rules: [
      {
        test: /\.css$/,
        use: [
          {
            loader: "style-loader",
          },
          {
            loader: "css-loader",
            options: {
              modules: {
                namedExport: true,
              },
            },
          },
        ],
      },
    ],
  },
};

源映射

当前一个加载器发出源映射时,此加载器会自动注入它们。

因此,要生成源映射,请将前一个加载器的 sourceMap 选项设置为 true

webpack.config.js

module.exports = {
  module: {
    rules: [
      {
        test: /\.css$/i,
        use: [
          "style-loader",
          { loader: "css-loader", options: { sourceMap: true } },
        ],
      },
    ],
  },
};

Nonce

如果你正在使用 内容安全策略 (CSP),注入的代码通常会被阻止。一种变通方法是使用 nonce。但请注意,使用 nonce 会显著降低 CSP 提供的保护。你可以在规范中阅读更多关于安全影响的信息。更好的解决方案是在生产环境中不使用此加载器。

有两种方式可以与 nonce 配合使用

  • 使用 attributes 选项
  • 使用 __webpack_nonce__ 变量

[!警告]

attributes 选项优先于 __webpack_nonce__ 变量

attributes

component.js

import "./style.css";

webpack.config.js

module.exports = {
  module: {
    rules: [
      {
        test: /\.css$/i,
        use: [
          {
            loader: "style-loader",
            options: {
              attributes: {
                nonce: "12345678",
              },
            },
          },
          "css-loader",
        ],
      },
    ],
  },
};

该加载器生成如下

<style nonce="12345678">
  .foo {
    color: red;
  }
</style>

__webpack_nonce__

create-nonce.js

__webpack_nonce__ = "12345678";

component.js

import "./create-nonce.js";
import "./style.css";

require 的替代示例

component.js

__webpack_nonce__ = "12345678";

require("./style.css");

webpack.config.js

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

该加载器生成如下

<style nonce="12345678">
  .foo {
    color: red;
  }
</style>

在顶部插入样式

head 标签顶部插入样式。

insert-function.js

function insertAtTop(element) {
  var parent = document.querySelector("head");
  var lastInsertedElement = window._lastElementInsertedByStyleLoader;

  if (!lastInsertedElement) {
    parent.insertBefore(element, parent.firstChild);
  } else if (lastInsertedElement.nextSibling) {
    parent.insertBefore(element, lastInsertedElement.nextSibling);
  } else {
    parent.appendChild(element);
  }

  window._lastElementInsertedByStyleLoader = element;
}

module.exports = insertAtTop;

webpack.config.js

module.exports = {
  module: {
    rules: [
      {
        test: /\.css$/i,
        use: [
          {
            loader: "style-loader",
            options: {
              insert: require.resolve("./insert-function.js"),
            },
          },
          "css-loader",
        ],
      },
    ],
  },
};

在目标元素之前插入样式

#id 元素之前插入样式。

insert-function.js

function insertBeforeAt(element) {
  const parent = document.querySelector("head");
  const target = document.querySelector("#id");

  const lastInsertedElement = window._lastElementInsertedByStyleLoader;

  if (!lastInsertedElement) {
    parent.insertBefore(element, target);
  } else if (lastInsertedElement.nextSibling) {
    parent.insertBefore(element, lastInsertedElement.nextSibling);
  } else {
    parent.appendChild(element);
  }

  window._lastElementInsertedByStyleLoader = element;
}

module.exports = insertBeforeAt;

webpack.config.js

module.exports = {
  module: {
    rules: [
      {
        test: /\.css$/i,
        use: [
          {
            loader: "style-loader",
            options: {
              insert: require.resolve("./insert-function.js"),
            },
          },
          "css-loader",
        ],
      },
    ],
  },
};

自定义元素 (Shadow DOM)

当你使用 lazyStyleTag 类型时,可以为样式定义自定义目标。

insert-function.js

function insertIntoTarget(element, options) {
  var parent = options.target || document.head;

  parent.appendChild(element);
}

module.exports = insertIntoTarget;

webpack.config.js

module.exports = {
  module: {
    rules: [
      {
        test: /\.css$/i,
        use: [
          {
            loader: "style-loader",
            options: {
              injectType: "lazyStyleTag",
              // Do not forget that this code will be used in the browser and
              // not all browsers support latest ECMA features like `let`, `const`, `arrow function expression` and etc,
              // we recommend use only ECMA 5 features,
              // but it is depends what browsers you want to support
              insert: require.resolve("./insert-function.js"),
            },
          },
          "css-loader",
        ],
      },
    ],
  },
};

将样式插入到提供的元素中,如果未提供目标,则插入到 head 标签中。

custom-square.css

div {
  width: 50px;
  height: 50px;
  background-color: red;
}

custom-square.js

import customSquareStyles from "./custom-square.css";

class CustomSquare extends HTMLElement {
  constructor() {
    super();

    this.attachShadow({ mode: "open" });

    const divElement = document.createElement("div");

    divElement.textContent = "Text content.";

    this.shadowRoot.appendChild(divElement);

    customSquareStyles.use({ target: this.shadowRoot });

    // You can override injected styles
    const bgPurple = new CSSStyleSheet();
    const width = this.getAttribute("w");
    const height = this.getAttribute("h");

    bgPurple.replace(`div { width: ${width}px; height: ${height}px; }`);

    this.shadowRoot.adoptedStyleSheets = [bgPurple];

    // `divElement` will have `100px` width, `100px` height and `red` background color
  }
}

customElements.define("custom-square", CustomSquare);

export default CustomSquare;

贡献

我们欢迎所有贡献!如果您是新用户,请在提交问题或拉取请求之前花一些时间阅读我们的贡献指南。

贡献指南

许可证

MIT