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 結合使用

然後將 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"],
      },
    ],
  },
};

安全性警告

此 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 模組)

component-with-css-modules.js

import styles from "./styles.css";

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

所有 Locals(類別名稱)都儲存在匯入的物件中。

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" } },
          "css-loader",
        ],
      },
    ],
  },
};

loader 會注入類似這樣的樣式

<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 styles from "./styles.css";

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

所有 Locals(類別名稱)都儲存在匯入的物件中。

webpack.config.js

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

loader 會注入類似這樣的樣式

<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 from "./styles.lazy.css";

styles.use();

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

所有當地 (類別名稱) 儲存在匯入物件的 locals 屬性中。

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" } },
          "css-loader",
        ],
      },
    ],
  },
};

loader 會注入類似這樣的樣式

<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 from "./styles.lazy.css";

styles.use();

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

所有當地 (類別名稱) 儲存在匯入物件的 locals 屬性中。

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" },
          },
          "css-loader",
        ],
      },
    ],
  },
};

載入器會產生這個

<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 style from "./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
  | ((htmlElement: HTMLElement, options: Record<string, any>) => void);

預設值:head

預設情況下,style-loader 會將 <style>/<link> 元素附加到樣式目標的結尾,也就是頁面的 <head> 標籤,除非由 insert 指定。這將導致載入器建立的 CSS 優先於目標中已存在的 CSS。如果您不適合標準行為,您可以使用其他值,但我們不建議這麼做。如果您鎖定 iframe,請確保您有足夠的存取權限,樣式會注入到內容文件標頭中。

string

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("modulePath"),
            },
          },
          "css-loader",
        ],
      },
    ],
  },
};

新的 <style>/<link> 元素將插入到 body 標籤的底部。

function

允許覆寫預設行為並在任何位置插入樣式。

警告

請勿忘記此程式碼將在瀏覽器中使用,且並非所有瀏覽器都支援最新的 ECMA 功能,例如 letconstarrow function expression 等,我們建議僅使用 ECMA 5 功能,但這取決於您想要支援的瀏覽器

警告

請勿忘記某些 DOM 方法在舊版瀏覽器中可能無法使用,我們建議僅使用 DOM 核心層級 2 屬性,但這取決於您想要支援的瀏覽器

webpack.config.js

module.exports = {
  module: {
    rules: [
      {
        test: /\.css$/i,
        use: [
          {
            loader: "style-loader",
            options: {
              insert: 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;
              },
            },
          },
          "css-loader",
        ],
      },
    ],
  },
};

head 標籤的頂端插入樣式。

您可以將任何參數傳遞至 style.use(options),此值將傳遞至 insertstyleTagTransform 函式。

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: function insertIntoTarget(element, options) {
                var parent = options.target || document.head;

                parent.appendChild(element);
              },
            },
          },
          "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
  | ((
      css: string,
      styleElement: HTMLStyleElement,
      options: Record<string, any>
    ) => void);

預設:undefined

string

允許設定自訂函式的絕對路徑,以覆寫預設行為 styleTagTransform。

警告

請勿忘記此程式碼將在瀏覽器中使用,且並非所有瀏覽器都支援最新的 ECMA 功能,例如 letconstarrow function expression 等,我們建議僅使用 ECMA 5 功能,但這取決於您想要支援的瀏覽器

webpack.config.js

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

function

在將「style」標籤插入 DOM 時,轉換標籤和 css。

警告

請勿忘記此程式碼將在瀏覽器中使用,且並非所有瀏覽器都支援最新的 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: function (css, style) {
                // Do something ...
                style.innerHTML = `${css}.modify{}\n`;

                document.head.appendChild(style);
              },
            },
          },
          "css-loader",
        ],
      },
    ],
  },
};

base

type base = number;

此設定主要用於解決使用一個或多個 DllPlugin 時發生的 CSS 衝突base 允許您透過指定大於 DllPlugin1 使用範圍的 CSS 模組 ID 基底,來防止 app 的 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 模組是有益的,例如在 模組串接tree shaking 的情況下。

您可以使用以下方式啟用 CommonJS 模組語法

webpack.config.js

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

範例

建議

對於 production 建置,建議從您的套件中提取 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 模組的名稱匯出

警告

本機名稱會轉換為 camelCase

警告

不允許在 CSS 類別名稱中使用 JavaScript 保留字。

警告

應啟用 css-loader 中的選項 esModulemodules.namedExport

styles.css

.foo-baz {
  color: red;
}
.bar {
  color: blue;
}

index.js

import { fooBaz, bar } from "./styles.css";

console.log(fooBaz, bar);

你可以使用以下方式啟用 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 標籤的最上方插入樣式。

webpack.config.js

module.exports = {
  module: {
    rules: [
      {
        test: /\.css$/i,
        use: [
          {
            loader: "style-loader",
            options: {
              insert: 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;
              },
            },
          },
          "css-loader",
        ],
      },
    ],
  },
};

在目標元素之前插入樣式

插入樣式於 #id 元素之前。

webpack.config.js

module.exports = {
  module: {
    rules: [
      {
        test: /\.css$/i,
        use: [
          {
            loader: "style-loader",
            options: {
              insert: 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;
              },
            },
          },
          "css-loader",
        ],
      },
    ],
  },
};

自訂元素 (Shadow DOM)

您可以為 lazyStyleTag 類型定義樣式的自訂目標。

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: function insertIntoTarget(element, options) {
                var parent = options.target || document.head;

                parent.appendChild(element);
              },
            },
          },
          "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