Webpack style-loader

2023-05-22 09:18 更新

把 CSS 插入到 DOM 中。

快速開始

首先,你需要安裝 ?style-loader?:

npm install --save-dev style-loader

推薦將 ?style-loader? 與 ?css-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"],
      },
    ],
  },
};

Options

名稱 類型 默認(rèn)值 描述
injectType {String} styleTag 配置把 styles 插入到 DOM 中的方式
attributes {Object} {} 添加自定義屬性到插入的標(biāo)簽中
insert {String|Function} head 在指定的位置插入標(biāo)簽
styleTagTransform {String|Function} undefined 當(dāng)將 'style' 標(biāo)簽插入到 DOM 中時,轉(zhuǎn)換標(biāo)簽和 css
base {Number} true 基于 (DLLPlugin) 設(shè)置 module ID
esModule {Boolean} false 使用 ES modules 語法

injectType

Type: String Default: styleTag

配置把 styles 插入到 DOM 中的方式。

可選值:

  • styleTag
  • singletonStyleTag
  • autoStyleTag
  • lazyStyleTag
  • lazySingletonStyleTag
  • lazyAutoStyleTag
  • linkTag

styleTag

通過使用多個 <style></style> 自動把 styles 插入到 DOM 中。該方式是默認(rèn)行為。

component.js

import "./styles.css";

使用 Locals (CSS Modules) 的例子:

component-with-css-modules.js

import styles from "./styles.css";

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

導(dǎo)入的對象保存著所有的 locals (class names)。

webpack.config.js

module.exports = {
  module: {
    rules: [
      {
        test: /\.css$/i,
        use: [
          // 由于是默認(rèn)行為,`injectType` 選項(xiàng)可以省略
          { loader: 'style-loader', options: { injectType: 'styleTag' } },
          'css-loader',
        ],
      },
    ],
  },
};

此 loader 插入的 style 效果如下:

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

singletonStyleTag

通過使用一個 <style></style> 來自動把 styles 插入到 DOM 中。

? Source map 不起作用

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"];

導(dǎo)入的對象保存著所有的 locals (class names)。

webpack.config.js

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

loader 插入的 styles 如下:

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

autoStyleTag

與 styleTag 相同,但是當(dāng)代碼在 IE6-9 中運(yùn)行時,請打開 singletonStyleTag 模式。

lazyStyleTag

在需要時使用多個 <style></style> 把 styles 插入到 DOM 中。

推薦 lazy style 遵循使用 .lazy.css 作為后綴的命名約定,style-loader 基本用法是使用 .css 作為文件后綴(其他文件也一樣,比如:.lazy.less 和 .less)。

當(dāng)使用 lazyStyleTag 時,style-loader 將惰性插入 styles,在需要使用 styles 時可以通過 style.use() / style.unuse() 使 style 可用。

?? 調(diào)用 unuse 多于 use 時,其表現(xiàn)會不確定。因此,請不要這么做。

component.js

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

styles.use();
// 要移除 styles 時你可以調(diào)用
// 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"];

導(dǎo)入的對象的 locals 屬性保存著所有的 locals (class names)。

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 效果如下:

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

lazySingletonStyleTag

在必要時,使用 <style></style> 把 style 插入的 DOM 中。

推薦 lazy style 遵循使用 .lazy.css 作為后綴的命名約定,style-loader 基本用法是使用 .css 作為文件后綴(其他文件也一樣,比如:.lazy.less 和 .less)。

當(dāng)使用 lazySingletonStyleTag 時,style-loader 將惰性插入 styles,在需要使用 styles 時可以通過 style.use() / style.unuse() 使 style 可用。

?? Source maps 不起作用
?? 調(diào)用 unuse 多于 use 時,其表現(xiàn)會不確定。因此,請不要這么做。

component.js

import styles from "./styles.css";

styles.use();
// 要移除 styles 時你可以調(diào)用
// 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"];

導(dǎo)入的對象的 locals 屬性保存著所有的 locals (class names)。

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

此 loader 生成的代碼如下:

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

lazyAutoStyleTag

與 lazyStyleTag 相同,但是當(dāng)代碼在 IE6-9 中運(yùn)行時,請打開 lazySingletonStyleTag 模式。

linkTag

使用多個 ?<link rel="stylesheet" href="path/to/file.css">? 將 styles 插入到 DOM 中。

?? 此 loader 會在運(yùn)行時使用 JavaScript 動態(tài)地插入 。要靜態(tài)插入  時請使用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" },
        ],
      },
    ],
  },
};

此 loader 生成的代碼如下:

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

attributes

Type: ?Object Default: {}?

如果配置了 attributes,style-loader 將會在 <style> / <link> 上綁定指定的 attributes 以及它們的值。

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: ?String|Function? Default: head

默認(rèn)情況下,除非指定 insert,否則 style-loader 會把 <style> / <link> 添加到頁面的 <head> 標(biāo)簽尾部。

這會使得 style-loader 創(chuàng)建的 CSS 比 <head> 標(biāo)簽內(nèi)已經(jīng)存在的 CSS 擁有更高的優(yōu)先級。 當(dāng)默認(rèn)行為不能滿足你的需求時,你可以使用其他值,但我們不推薦這么做。

如果你指定 iframe 作為插入的目標(biāo)時,請確保你有足夠的訪問權(quán)限,styles 將會被插入到 content document 的 head 標(biāo)簽中。

String

Selector

配置 styles 插入 DOM 的自定義 query selector。

webpack.config.js

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

允許設(shè)置自定義函數(shù)的絕對路徑,該函數(shù)能夠覆蓋默認(rèn)行為并且能夠在任意位置插入樣式。

? 不要忘了這個函數(shù)會在瀏覽器中調(diào)用,由于不是所有瀏覽器都支持最新的 ECMA 特性,如:let,const,arrow function expression 等。我們推薦使用 babel-loader 以支持最新的 ECMA 特性。 ? 不要忘了版本較舊的瀏覽器中某些 DOM 方法并不可用,所以我們推薦只使用 DOM core level 2 properties,但這取決于想要支持的瀏覽器版本。

webpack.config.js

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

一個新的 <style> 或 <link> 元素將會被插入到 body 標(biāo)簽底部。

Function

允許覆蓋默認(rèn)行為并把 styles 插入到任意位置。

? 不要忘了這個函數(shù)會在瀏覽器中調(diào)用,由于不是所有瀏覽器都支持最新的 ECMA 特性,如:let,const,arrow function expression 等,我們推薦只使用 ECMA 5 特性,但這取決于你想要支持的瀏覽器版本。
? 不要忘了版本較舊的瀏覽器中某些 DOM 方法并不可用,所以我們推薦只使用 DOM core level 2 properties,但這取決于想要支持的瀏覽器版本。

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 標(biāo)簽頂部插入styles。

你可以給 style.use(options) 傳遞任何參數(shù),并且這些值會被傳遞給 insert 與 styleTagTransform 函數(shù)。

webpack.config.js

module.exports = {
  module: {
    rules: [
      {
        test: /\.css$/i,
        use: [
          {
            loader: "style-loader",
            options: {
              injectType: "lazyStyleTag",
              // 不要忘記這些代碼會在瀏覽器中使用,
              // 并且不是所有的瀏覽器都支持 `let`、`const`、箭頭函數(shù)表達(dá)式等高級 ECMA 特性。
              // 我們建議只使用 ECMA 5 特性,
              // 但是這取決于你想支持的瀏覽器
              insert: function insertIntoTarget(element, options) {
                var parent = options.target || document.head;

                parent.appendChild(element);
              },
            },
          },
          "css-loader",
        ],
      },
    ],
  },
};

向指定元素添加樣式,沒有指定時將會插入到 head 標(biāo)簽中?,F(xiàn)在你可以向 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 });

    // 你可以覆蓋注入的樣式
    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` 將會擁有 `100px` 寬,`100px` 高和 `red` 背景顏色
  }
}

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

export default CustomSquare;

styleTagTransform

類型:?String | Function? 默認(rèn)值:undefined

String

允許設(shè)置自定義函數(shù)的絕對路徑,該函數(shù)能夠覆蓋 styleTagTransform 默認(rèn)行為。

? 不要忘了這個函數(shù)會在瀏覽器中調(diào)用,由于不是所有瀏覽器都支持最新的 ECMA 特性,如:let,const,arrow 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

當(dāng)將 'style' 標(biāo)簽插入到 DOM 中時,轉(zhuǎn)換標(biāo)簽和 css。

? 不要忘記該代碼會在瀏覽器中使用,并且不是所有的瀏覽器都支持想 let、const、箭頭函數(shù) 等最新的 ECMA 特性,我們建議僅使用 ECMA5 特性,但這取決于你想支持什么瀏覽器。 ? 不要忘記有一些 DOM 方法在老的瀏覽器中是不可用的,我們推薦只使用 DOM core level 2 properties,但這取決于你想支持什么瀏覽器。

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

這個配置主要是作為使用 DllPlugin 時出現(xiàn) css clashes 問題時的解決方案。base 允許你通過指定一個比 DllPlugin1 使用的 css 模塊 id 大的值,來避免應(yīng)用程序中的 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: ?Boolean? Default: true

默認(rèn)情況下,style-loader 生成使用 ES 模塊語法的 JS 模塊。在某些情況下使用 ES 模塊語法更好,比如:module concatenation 和 tree shaking 時。

你可以使用下面的配置啟用 CommonJS 模塊語法:

webpack.config.js

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

示例

推薦

對于 production 模式的構(gòu)建,建議從你的包中提取 CSS,以便以后能夠使用 CSS/JS 資源的并行加載。 可以使用 mini-css-extract-plugin 實(shí)現(xiàn),因?yàn)樗梢詣?chuàng)建單獨(dú)的 css 文件。 對于 development 模式(包括 webpack-dev-server),你可以使用 style-loader,因?yàn)樗褂枚鄠€ <style></style> 將 CSS 插入到 DOM 中,并且運(yùn)行得會更快。

? 不要將 style-loader 于 mini-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()]),
};

Named export for CSS Modules

? 本地命名導(dǎo)出時,會將其名稱轉(zhuǎn)換為 camelCase 的形式。
? 并且不允許在 css 的 class 名中使用 JavaScript 的保留字。
? 在 css-loader 中,應(yīng)啟用 esModule 和 modules.namedExport 配置項(xiàng)。

styles.css

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

index.js

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

console.log(fooBaz, bar);

你可以使用如下方法為 ES 模塊啟用命名導(dǎo)出功能:

webpack.config.js

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

Source maps

因此,想要生成 source map,則需將 style-loader 之前執(zhí)行 loader 的 sourceMap 選項(xiàng)設(shè)置為true。

webpack.config.js

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

Nonce

有兩種方式使用 nonce:

  • 使用 attributes 選項(xiàng)
  • 使用 __webpack_nonce__ 變量
? attributes 擁有比 __webpack_nonce__ 更高的優(yōu)先級

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

此 loader 生成代碼如下:

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

__webpack_nonce__ $#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"],
      },
    ],
  },
};

此 loader 生成代碼如下:

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

Insert styles at top

在 head 標(biāo)簽頂部插入 style。

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

在目標(biāo)元素前插入 style

在 #id 元素前面插入 style。

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

Custom Elements (Shadow DOM)

你可以為 lazyStyleTag 類型定義自定義目標(biāo)。

webpack.config.js

module.exports = {
  module: {
    rules: [
      {
        test: /\.css$/i,
        use: [
          {
            loader: "style-loader",
            options: {
              injectType: "lazyStyleTag",
              // 不要忘記這些代碼會在瀏覽器中使用,
              // 并且不是所有的瀏覽器都支持 `let`、`const`、箭頭函數(shù)表達(dá)式等高級 ECMA 特性。
              // 我們建議只使用 ECMA 5 特性,
              // 但是這取決于你想支持的瀏覽器
              insert: function insertIntoTarget(element, options) {
                var parent = options.target || document.head;

                parent.appendChild(element);
              },
            },
          },
          "css-loader",
        ],
      },
    ],
  },
};

向指定元素添加樣式,沒有指定時將會插入到 head 標(biāo)簽中。

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 });

    // 你可以覆蓋注入的樣式
    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` 將會擁有 `100px` 寬,`100px` 高和 `red` 背景顏色
  }
}

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

export default CustomSquare;

Contributing

如果您尚未了解,建議您閱讀以下貢獻(xiàn)指引。

License

MIT


以上內(nèi)容是否對您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號