Webpack stylus-loader

2023-05-22 09:18 更新

一個 webpack 的 Stylus loader。將 Stylus 文件編譯為 CSS。

快速開始

首先,你需要安裝 stylus 和 stylus-loader:

$ npm install stylus stylus-loader --save-dev

然后將該 loader 添加到 webpack 配置中。例如:

webpack.config.js

module.exports = {
  module: {
    rules: [
      {
        test: /\.styl$/,
        loader: "stylus-loader", // 將 Stylus 文件編譯為 CSS
      },
    ],
  },
};

接著按照你習(xí)慣的方式運行 webpack。

可選項

Name Type Default Description
stylusOptions {Object|Function} {} Stylus 的可選項。
sourceMap {Boolean} compiler.devtool 啟用/禁用生成 SourceMap。
webpackImporter {Boolean} true 啟用/禁用默認(rèn)的 webpack importer。
additionalData {String|Function} undefined 在入口文件起始或末尾添加 Stylus 代碼。
implementation {String|Function} stylus 配置 Stylus 使用的實現(xiàn)庫。

stylusOptions

類型:?Object|Function? 默認(rèn)值:{}

通過 stylusOptions 屬性,你可以給 stylus-loader 配置 loader options 中任意特定的選項值。 所有可用選項可以查看 Stylus 文檔。 這些配置項需要將破折號(dash-case)轉(zhuǎn)換為駝峰值(camelCase)后進行設(shè)置。

Object

使用對象(Object)的形式傳遞 options 給 Stylus。

webpack.config.js

module.exports = {
  module: {
    rules: [
      {
        test: /\.styl$/,
        use: [
          {
            loader: "style-loader",
          },
          {
            loader: "css-loader",
          },
          {
            loader: "stylus-loader",
            options: {
              stylusOptions: {
                /**
                 * 指定要使用的 Stylus 插件。將插件作為
                 * 字符串進行傳遞,而不是從 Webpack 配置中導(dǎo)入。
                 *
                 * @type {(string|Function)[]}
                 * @default []
                 */
                use: ["nib"],

                /**
                 * 指定 path 的查找路徑。
                 *
                 * @type {string[]}
                 * @default []
                 */
                include: [path.join(__dirname, "src/styl/config")],

                /**
                 * 導(dǎo)入指定的 Stylus 文件或者路徑
                 *
                 * @type {string[]}
                 * @default []
                 */
                import: ["nib", path.join(__dirname, "src/styl/mixins")],

                /**
                 * 定義 Stylus 變量或者函數(shù)。
                 *
                 * @type {Array|Object}
                 * @default {}
                 */
                // 定義數(shù)組語法的推薦格式:[key, value, raw]
                define: [
                  ["$development", process.env.NODE_ENV === "development"],
                  ["rawVar", 42, true],
                ],
                // Object 語法已經(jīng)棄用(不可指定 "raw' 選項)
                // define: {
                //   $development: process.env.NODE_ENV === 'development',
                //   rawVar: 42,
                // },

                /**
                 * 是否包含通過 @import 導(dǎo)入的常規(guī) CSS。
                 *
                 * @type {boolean}
                 * @default false
                 */
                includeCSS: false,

                /**
                 * 解析導(dǎo)入文件中的相對 url()。
                 *
                 * @see https://stylus-lang.com/docs/js.html#stylusresolveroptions
                 *
                 * @type {boolean|Object}
                 * @default { nocheck: true }
                 */
                resolveURL: true,
                // resolveURL: { nocheck: true },

                /**
                 * 生成 CSS 后 注入注釋并指定其所在 Stylus 文件行。
                 *
                 * @see https://stylus-lang.com/docs/executable.html
                 *
                 * @type {boolean}
                 * @default false
                 */
                lineNumbers: true,

                /**
                 * 將 @import 和 @charset 移至文件頂部。
                 *
                 * @see https://stylus-lang.com/docs/executable.html
                 *
                 * @type {boolean}
                 * @default false
                 */
                hoistAtrules: true,

                /**
                 * 壓縮輸出的 CSS。
                 * 生產(chǎn)環(huán)境默認(rèn)值為 `true`
                 *
                 * @see https://stylus-lang.com/docs/executable.html
                 *
                 * @type {boolean}
                 * @default false
                 */
                compress: true,
              },
            },
          },
        ],
      },
    ],
  },
};

Function

允許根據(jù) loader 的 context 來設(shè)置 options,再傳遞給 Stylus。

module.exports = {
  module: {
    rules: [
      {
        test: /\.styl/,
        use: [
          "style-loader",
          "css-loader",
          {
            loader: "stylus-loader",
            options: {
              stylusOptions: (loaderContext) => {
                // 更多可用的屬性參見 https://webpack.js.org/api/loaders/
                const { resourcePath, rootContext } = loaderContext;
                const relativePath = path.relative(rootContext, resourcePath);

                if (relativePath === "styles/foo.styl") {
                  return {
                    paths: ["absolute/path/c", "absolute/path/d"],
                  };
                }

                return {
                  paths: ["absolute/path/a", "absolute/path/b"],
                };
              },
            },
          },
        ],
      },
    ],
  },
};

sourceMap

類型:?Boolean?

webpack.config.js

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

webpackImporter

類型:?Boolean? 默認(rèn)值:true

啟用/禁用 webpack 默認(rèn)的 importer。

在某些情況下,這樣做可以提高性能。 但是請慎用,因為可能會使得 aliases 和以 ~ 開頭的 @import 規(guī)則失效。

webpack.config.js

module.exports = {
  module: {
    rules: [
      {
        test: /\.styl/i,
        use: [
          "style-loader",
          "css-loader",
          {
            loader: "stylus-loader",
            options: {
              webpackImporter: false,
            },
          },
        ],
      },
    ],
  },
};

additionalData

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

在實際入口文件的起始位置添加 Stylus 代碼。 這種情況下,stylus-loader 只會追加并不會覆蓋文件內(nèi)容。

當(dāng)你的 Stylus 變量依賴環(huán)境變量時這個屬性將非常有用:

? 由于你注入了代碼,因此它將破壞入口文件的源映射關(guān)系。通常有比這更簡單的解決方案,例如多個 Stylus 入口文件。

String

module.exports = {
  module: {
    rules: [
      {
        test: /\.styl/,
        use: [
          "style-loader",
          "css-loader",
          {
            loader: "stylus-loader",
            options: {
              additionalData: `@env: ${process.env.NODE_ENV};`,
            },
          },
        ],
      },
    ],
  },
};

Function

Sync
module.exports = {
  module: {
    rules: [
      {
        test: /\.styl/,
        use: [
          "style-loader",
          "css-loader",
          {
            loader: "stylus-loader",
            options: {
              additionalData: (content, loaderContext) => {
                // 更多可用的屬性參見 https://webpack.js.org/api/loaders/
                const { resourcePath, rootContext } = loaderContext;
                const relativePath = path.relative(rootContext, resourcePath);

                if (relativePath === "styles/foo.styl") {
                  return "value = 100px" + content;
                }

                return "value 200px" + content;
              },
            },
          },
        ],
      },
    ],
  },
};
Async
module.exports = {
  module: {
    rules: [
      {
        test: /\.styl/,
        use: [
          "style-loader",
          "css-loader",
          {
            loader: "stylus-loader",
            options: {
              additionalData: async (content, loaderContext) => {
                // 更多可用的屬性參見 https://webpack.js.org/api/loaders/
                const { resourcePath, rootContext } = loaderContext;
                const relativePath = path.relative(rootContext, resourcePath);

                if (relativePath === "styles/foo.styl") {
                  return "value = 100px" + content;
                }

                return "value 200px" + content;
              },
            },
          },
        ],
      },
    ],
  },
};

implementation

類型:?Function | String?

特殊的 implementation 選項決定使用 Stylus 的哪個實現(xiàn)。將會覆蓋本地安裝的 stylus 的 peerDependency 版本。

Function

webpack.config.js

module.exports = {
  module: {
    rules: [
      {
        test: /\.styl/i,
        use: [
          "style-loader",
          "css-loader",
          {
            loader: "stylus-loader",
            options: {
              implementation: require("stylus"),
            },
          },
        ],
      },
    ],
  },
};

String

webpack.config.js

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

示例

常規(guī)用法

將 ?stylus-loader?、?css-loader? 和 ?style-loader? 串聯(lián)起來使用可立即將所有樣式更新到 DOM。

webpack.config.js

module.exports = {
  module: {
    rules: [
      {
        test: /\.styl$/,
        use: [
          {
            loader: "style-loader", // 從 JS 中創(chuàng)建樣式節(jié)點
          },
          {
            loader: "css-loader", // 將 CSS 轉(zhuǎn)為 CommonJS
          },
          {
            loader: "stylus-loader", // 將 Stylus 編譯為 CSS
          },
        ],
      },
    ],
  },
};

Source maps

為了生成 CSS 的 source map, 你需要在 loader 的可選項中設(shè)置 sourceMap 屬性。如果沒設(shè)置的話 loader 將會繼承你 webpack 中為生成 source map 設(shè)置的屬性值 devtool。

webpack.config.js

module.exports = {
  devtool: "source-map", // 任何類似于 "source-map" 的 devtool 值都可以
  module: {
    rules: [
      {
        test: /\.styl$/,
        use: [
          "style-loader",
          {
            loader: "css-loader",
            options: {
              sourceMap: true,
            },
          },
          {
            loader: "stylus-loader",
            options: {
              sourceMap: true,
            },
          },
        ],
      },
    ],
  },
};

stylus 中使用 nib

webpack.config.js

module.exports = {
  module: {
    rules: [
      {
        test: /\.styl$/,
        use: [
          {
            loader: "style-loader", // 從 JS 中創(chuàng)建樣式節(jié)點
          },
          {
            loader: "css-loader", // 將 CSS 轉(zhuǎn)為 CommonJS
          },
          {
            loader: "stylus-loader", // 將 Stylus 編譯為 CSS
            options: {
              stylusOptions: {
                use: [require("nib")()],
                import: ["nib"],
              },
            },
          },
        ],
      },
    ],
  },
};

導(dǎo)入 JSON 文件

Stylus 在 json 函數(shù)中無效。 因此 webpack 解析器不適用于 .json 文件。 可使用 stylus resolver。

index.styl

// 假設(shè)文件位置在這里 `node_modules/vars/vars.json`
json('vars.json')

@media queries-small
  body
    display nope

webpack.config.js

module.exports = {
  module: {
    rules: [
      {
        test: /\.styl$/,
        use: [
          "style-loader",
          "css-loader",
          {
            loader: "stylus-loader",
            options: {
              stylusOptions: {
                // 指定文件查找路徑。
                paths: ["node_modules/vars"],
              },
            },
          },
        ],
      },
    ],
  },
};

生產(chǎn)環(huán)境

在生產(chǎn)環(huán)境中推薦使用 MiniCssExtractPlugin 來提取樣式表到專門的文件中,這樣你的樣式就不需要依賴 JavaScript。

webpack 解析器

webpack 提供了一種 解析文件的高級機制。 stylus-loader 將所有的查詢結(jié)果傳遞給了 webpack 解析器。 因此你可以從 node_modules 中導(dǎo)入 Stylus 模塊。

@import 'bootstrap-styl/bootstrap/index.styl';

~ 用法已被廢棄,可以從代碼中刪除(我們建議這么做),但是我們會因為一些歷史原因一直支持這種寫法。 為什么你可以移除它呢?loader 首先會嘗試以相對路徑解析 @import,如果它不能被解析,loader 將會嘗試在 node_modules 中解析 @import。 只要在包名前加上 ~,告訴 webpack 在 modules 中進行查找。

@import "~bootstrap-styl/bootstrap/index.styl";

重要的是只在它的前面加上 ~,因為 ~/ 會被解析到根目錄。 webpack 需要區(qū)分 bootstrap 和 ~bootstrap,因為 CSS 和 Stylus 文件沒有特殊的語法可以導(dǎo)入相對路徑的文件。 @import "file" 和 @import "./file"; 寫法是等價的。

Stylus resolver

如果指定 paths 選項,將從指定的 paths 中搜索模塊。 這是 Stylus 的默認(rèn)行為。

webpack.config.js

module.exports = {
  module: {
    rules: [
      {
        test: /\.styl/,
        use: [
          {
            loader: "style-loader",
          },
          {
            loader: "css-loader",
          },
          {
            loader: "stylus-loader",
            options: {
              stylusOptions: {
                paths: [path.resolve(__dirname, "node_modules")],
              },
            },
          },
        ],
      },
    ],
  },
};

提取樣式

通過 webpack 打包 CSS 有很多好處,比如給引用圖片和字體文件路徑添加 hash, 在開發(fā)環(huán)境可以模塊熱更新。另一方面,在生產(chǎn)環(huán)境,根據(jù) JS 來控制應(yīng)用樣式表不是一個好的方式,可能會導(dǎo)致延遲渲染,甚至可能會出現(xiàn)閃爍現(xiàn)象。因此,在你最終的生產(chǎn)環(huán)境中將它們拆分成單獨的文件來存放通常是比較好的選擇。

有兩種從 bundle 中提取樣式表的方式:

  • extract-loader (簡單,但得專門指定 css-loader 的 output)
  • MiniCssExtractPlugin (較復(fù)雜,但適用于所有的場景)

貢獻

如果你還沒有看過我們的貢獻者指南請先花點時間看一下。

CONTRIBUTING

許可

MIT


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

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號