可打印

babel-loader

本 README 适用于 babel-loader v8/v9/v10 和 Babel v7。如果您正在使用旧版 Babel v6,请参阅 7.x 分支文档。

NPM Status codecov

此包允许使用 Babelwebpack 转译 JavaScript 文件。

注意:输出相关问题应报告到 Babel 的问题追踪器。

安装

babel-loader支持的 webpack 版本支持的 Babel 版本支持的 Node.js 版本
8.x4.x 或 5.x7.x>= 8.9
9.x5.x^7.12.0>= 14.15.0
10.x^5.61.0^7.12.0 || ^8.0.0-alpha^18.20.0 || ^20.10.0 || >=22.0.0`
npm install -D babel-loader @babel/core @babel/preset-env webpack

用法

webpack 文档:加载器

在你的 webpack 配置对象中,你需要将 babel-loader 添加到模块列表中,如下所示:

module: {
  rules: [
    {
      test: /\.(?:js|mjs|cjs)$/,
      exclude: /node_modules/,
      use: {
        loader: 'babel-loader',
        options: {
          targets: "defaults",
          presets: [
            ['@babel/preset-env']
          ]
        }
      }
    }
  ]
}

选项

请参阅 babel 选项

你可以通过使用 options 属性向加载器传递选项。

module: {
  rules: [
    {
      test: /\.(?:js|mjs|cjs)$/,
      exclude: /node_modules/,
      use: {
        loader: 'babel-loader',
        options: {
          targets: "defaults",
          presets: [
            ['@babel/preset-env']
          ],
          plugins: ['@babel/plugin-proposal-decorators', { version: "2023-11" }]
        }
      }
    }
  ]
}

此处传递的 options 将与 Babel 配置文件(例如 babel.config.js.babelrc合并

此加载器还支持以下加载器特定选项:

  • cacheDirectory:默认值为 false。设置后,给定目录将用于缓存加载器的结果。未来的 webpack 构建将尝试从缓存中读取,以避免在每次运行时都运行可能昂贵的 Babel 重新编译过程。如果选项中设置为 true ({cacheDirectory: true}),加载器将使用 node_modules/.cache/babel-loader 中的默认缓存目录,如果任何根目录中找不到 node_modules 文件夹,则回退到默认的操作系统临时文件目录。

  • cacheIdentifier:默认值是由 @babel/core 的版本和 babel-loader 的版本组成的字符串。最终的缓存 ID 将由输入文件路径、通过 Babel.loadPartialConfigAsync 合并的 Babel 配置以及 cacheIdentifier 决定。合并的 Babel 配置将由 babel.config.js.babelrc 文件(如果存在)或环境变量 BABEL_ENVNODE_ENV 的值决定。cacheIdentifier 可以设置为自定义值,如果标识符发生变化,则强制清除缓存。

  • cacheCompression:默认值为 true。设置后,每个 Babel 转换输出都将用 Gzip 压缩。如果你想禁用缓存压缩,请将其设置为 false——如果你的项目转译数千个文件,这可能会受益。

  • customize:默认值为 null。一个模块的路径,该模块导出一个 custom 回调函数,类似于你会传递给 .custom() 的回调。由于你已经需要创建一个新文件才能使用它,建议你改为使用 .custom 来创建一个包装加载器。只有在你必须继续直接使用 babel-loader 但仍想自定义时才使用此选项。

  • metadataSubscribers:默认值为 []。接受一个上下文函数名称数组。例如,如果你传入 ['myMetadataPlugin'],你将在 webpack 插件的钩子中为 context.myMetadataPlugin 分配一个订阅函数,并且该函数将使用 metadata 调用。请参阅 https://github.com/babel/babel-loader/main/test/metadata.test.js 获取示例。

故障排除

启用调试模式日志

指定 webpack 选项 stats.loggingDebug 以输出详细的调试日志。

// webpack.config.js
module.exports = {
  // ...
  stats: {
    loggingDebug: ["babel-loader"]
  }
}

babel-loader 很慢!

确保你转换的文件尽可能少。因为你可能匹配 /\.m?js$/,所以你可能会转换 node_modules 文件夹或其他不需要的源。

要排除 node_modules,请参阅上面文档中 loaders 配置中的 exclude 选项。

你还可以使用 cacheDirectory 选项将 babel-loader 的速度提高多达 2 倍。这会将转换缓存到文件系统。

我的 node_modules 中的某些文件未针对 IE 11 进行转译

尽管我们通常建议不编译 node_modules,但在使用不支持 IE 11 或任何旧版目标的库时,你可能需要这样做。

为此,你可以使用 testnot 的组合,或者传递一个函数给你的 exclude 选项。你还可以使用负向先行正则表达式,如此处建议的那样。

{
    test: /\.(?:js|mjs|cjs)$/,
    exclude: {
      and: [/node_modules/], // Exclude libraries in node_modules ...
      not: [
        // Except for a few of them that needs to be transpiled because they use modern syntax
        /unfetch/,
        /d3-array|d3-scale/,
        /@hapi[\\/]joi-date/,
      ]
    },
    use: {
      loader: 'babel-loader',
      options: {
        presets: [
          ['@babel/preset-env', { targets: "ie 11" }]
        ]
      }
    }
  }

Babel 将辅助函数注入到每个文件并使我的代码膨胀!

Babel 对 _extend 等常见函数使用非常小的辅助函数。默认情况下,这将被添加到每个需要它的文件中。

你可以改为将 Babel 运行时作为单独的模块引入,以避免重复。

以下配置禁用了 Babel 中每个文件的自动运行时注入,转而需要 @babel/plugin-transform-runtime 并使所有辅助函数引用都使用它。

有关更多信息,请参阅文档

注意:你必须运行 npm install -D @babel/plugin-transform-runtime 将其包含在你的项目中,并运行 npm install @babel/runtime@babel/runtime 本身作为依赖项。

rules: [
  // the 'transform-runtime' plugin tells Babel to
  // require the runtime instead of inlining it.
  {
    test: /\.(?:js|mjs|cjs)$/,
    exclude: /node_modules/,
    use: {
      loader: 'babel-loader',
      options: {
        presets: [
          ['@babel/preset-env', { targets: "defaults" }]
        ],
        plugins: ['@babel/plugin-transform-runtime']
      }
    }
  }
]

注意:transform-runtime 和自定义 polyfills(例如 Promise 库)

由于 @babel/plugin-transform-runtime 包含一个 polyfill,该 polyfill 又包含自定义的 regenerator-runtimecore-js,因此以下使用 webpack.ProvidePlugin 的常规 shiming 方法将不起作用:

// ...
        new webpack.ProvidePlugin({
            'Promise': 'bluebird'
        }),
// ...

以下方法也行不通:

require('@babel/runtime/core-js/promise').default = require('bluebird');

var promise = new Promise;

输出为(使用 runtime

'use strict';

var _Promise = require('@babel/runtime/core-js/promise')['default'];

require('@babel/runtime/core-js/promise')['default'] = require('bluebird');

var promise = new _Promise();

之前的 Promise 库在被覆盖之前就被引用和使用了。

一种方法是在你的应用程序中有一个“引导”步骤,在应用程序之前首先覆盖默认的全局变量。

// bootstrap.js

require('@babel/runtime/core-js/promise').default = require('bluebird');

// ...

require('./app');

babel 的 Node.js API 已移至 babel-core

如果你收到此消息,这意味着你已安装 npm 包 babel 并在 webpack 配置中使用了加载器的短表示法(自 webpack 2.x 起不再有效)。

  {
    test: /\.(?:js|mjs|cjs)$/,
    loader: 'babel',
  }

webpack 随后会尝试加载 babel 包而不是 babel-loader

要解决此问题,你应该卸载 npm 包 babel,因为它在 Babel v6 中已弃用。(而是安装 @babel/cli@babel/core。)如果你的某个依赖项正在安装 babel 并且你无法自行卸载它,请在 webpack 配置中使用加载器的完整名称:

  {
    test: /\.(?:js|mjs|cjs)$/,
    loader: 'babel-loader',
  }

排除不应转译的库

如果 core-jswebpack/buildin 被 Babel 转译,它们将导致错误。

你需要将它们从 babel-loader 中排除。

{
  "loader": "babel-loader",
  "options": {
    "exclude": [
      // \\ for Windows, / for macOS and Linux
      /node_modules[\\/]core-js/,
      /node_modules[\\/]webpack[\\/]buildin/,
    ],
    "presets": [
      "@babel/preset-env"
    ]
  }
}

顶级函数(IIFE)仍然是箭头函数(在 Webpack 5 上)

该函数是在运行 babel-loader 之后由 Webpack 本身注入的。默认情况下,Webpack 假定你的目标环境支持某些 ES2015 特性,但你可以使用 output.environment Webpack 选项(文档)覆盖此行为。

为避免顶级箭头函数,你可以使用 output.environment.arrowFunction

// webpack.config.js
module.exports = {
  // ...
  output: {
    // ...
    environment: {
      // ...
      arrowFunction: false, // <-- this line does the trick
    },
  },
};

根据 webpack 目标自定义配置

Webpack 支持捆绑多个目标。对于你可能希望为每个目标(例如 web node)使用不同 Babel 配置的情况,此加载器通过 Babel 的 caller API 提供一个 target 属性。

例如,根据 webpack 目标更改传递给 @babel/preset-env 的环境目标:

// babel.config.js

module.exports = api => {
  return {
    presets: [
      [
        "@babel/preset-env",
        {
          useBuiltIns: "entry",
          // caller.target will be the same as the target option from webpack
          targets: api.caller(caller => caller && caller.target === "node")
            ? { node: "current" }
            : { chrome: "58", ie: "11" }
        }
      ]
    ]
  }
}

自定义加载器

babel-loader 暴露了一个加载器构建器实用工具,允许用户为它处理的每个文件添加 Babel 配置的自定义处理。

.custom 接受一个回调函数,该函数将使用加载器中的 babel 实例进行调用,以便工具可以确保它使用的是与加载器本身完全相同的 @babel/core 实例。

在你希望自定义但实际上没有文件调用 .custom 的情况下,你还可以传递 customize 选项,其中包含指向导出你的 custom 回调函数的文件路径字符串。

示例

// Export from "./my-custom-loader.js" or whatever you want.
module.exports = require("babel-loader").custom(babel => {
  // Extract the custom options in the custom plugin
  function myPlugin(api, { opt1, opt2 }) {
    return {
      visitor: {},
    };
  }

  return {
    // Passed the loader options.
    customOptions({ opt1, opt2, ...loader }) {
      return {
        // Pull out any custom options that the loader might have.
        custom: { opt1, opt2 },

        // Pass the options back with the two custom options removed.
        loader,
      };
    },

    // Passed Babel's 'PartialConfig' object.
    config(cfg, { customOptions }) {
      if (cfg.hasFilesystemConfig()) {
        // Use the normal config
        return cfg.options;
      }

      return {
        ...cfg.options,
        plugins: [
          ...(cfg.options.plugins || []),

          // Include a custom plugin in the options and passing it the customOptions object.
          [myPlugin, customOptions],
        ],
      };
    },

    result(result) {
      return {
        ...result,
        code: result.code + "\n// Generated by some custom loader",
      };
    },
  };
});
// And in your Webpack config
module.exports = {
  // ..
  module: {
    rules: [{
      // ...
      loader: path.join(__dirname, 'my-custom-loader.js'),
      // ...
    }]
  }
};

customOptions(options: Object): { custom: Object, loader: Object }

给定加载器的选项,从 babel-loader 的选项中分离出自定义选项。

config(cfg: PartialConfig, options: { source, customOptions }): Object

给定 Babel 的 PartialConfig 对象,返回应传递给 babel.transformoptions 对象。

result(result: Result): Result

给定 Babel 的结果对象,允许加载器对其进行额外调整。

许可证

MIT

coffee-loader

npm node tests coverage discussion size

CoffeeScript 编译为 JavaScript。

入门

首先,你需要安装 coffeescriptcoffee-loader

npm install --save-dev coffeescript coffee-loader

yarn add -D coffeescript coffee-loader

pnpm add -D coffeescript coffee-loader

然后将加载器添加到你的 webpack.config.js 中。例如:

file.coffee

# Assignment:
number   = 42
opposite = true

# Conditions:
number = -42 if opposite

# Functions:
square = (x) -> x * x

# Arrays:
list = [1, 2, 3, 4, 5]

# Objects:
math =
  root:   Math.sqrt
  square: square
  cube:   (x) -> x * square x

# Splats:
race = (winner, runners...) ->
  print winner, runners

# Existence:
alert "I knew it!" if elvis?

# Array comprehensions:
cubes = (math.cube num for num in list)

webpack.config.js

module.exports = {
  module: {
    rules: [
      {
        test: /\.coffee$/,
        loader: "coffee-loader",
      },
    ],
  },
};

替代用法

import coffee from "coffee-loader!./file.coffee";

最后,使用你通常使用的方法运行 webpack(例如,通过 CLI 或 npm 脚本)。

选项

类型:Object 默认值:{ bare: true }

你可以在此处找到所有可用的 CoffeeScript 选项。

有关 transpile 选项的文档,请参阅本节

[!注意]

sourceMap 选项默认取自 compiler.devtool 的值。

[!注意]

filename 选项取自 webpack 加载器 API 的值,但其值将被忽略。

webpack.config.js

module.exports = {
  module: {
    rules: [
      {
        test: /\.coffee$/,
        loader: "coffee-loader",
        options: {
          bare: false,
          transpile: {
            presets: ["@babel/env"],
          },
        },
      },
    ],
  },
};

示例

CoffeeScript 和 Babel

来自 CoffeeScript 2 文档

[!注意]

CoffeeScript 2 使用最新的现代语法生成 JavaScript。你希望代码运行的运行时或浏览器可能不支持所有这些语法。在这种情况下,现代 JavaScript 需要转换为可在旧版 Node 或旧版浏览器中运行的旧版 JavaScript;例如:将 { a } = obj 转换为 a = obj.a。这种转换是使用 Babel、Bublé 或 Traceur Compiler 等转译器完成的。

你需要安装 @babel/core@babel/preset-env,然后创建一个配置文件。

npm install --save-dev @babel/core @babel/preset-env
echo '{ "presets": ["@babel/env"] }' > .babelrc

webpack.config.js

module.exports = {
  module: {
    rules: [
      {
        test: /\.coffee$/,
        loader: "coffee-loader",
        options: {
          transpile: {
            presets: ["@babel/env"],
          },
        },
      },
    ],
  },
};

Literate CoffeeScript

要使用 Literate CoffeeScript,你应该进行设置:

webpack.config.js

module.exports = {
  module: {
    rules: [
      {
        test: /\.coffee$/,
        loader: "coffee-loader",
        options: {
          literate: true,
        },
      },
    ],
  },
};

贡献

如果你尚未阅读,请花一点时间阅读我们的贡献指南。

CONTRIBUTING

许可证

MIT

css-loader

npm node tests coverage discussion size

css-loader@importurl() 解析为 import/require() 并进行处理。

入门

[!警告]

要使用最新版本的 css-loader,需要 webpack@5

首先,你需要安装 css-loader

npm install --save-dev css-loader

yarn add -D css-loader

pnpm add -D css-loader

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

file.js

import * as css from "file.css";

webpack.config.js

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

最后,使用你通常使用的方法运行 webpack(例如,通过 CLI 或 npm 脚本)。

如果你需要将 CSS 提取到单独的文件中(即不在 JS 模块中存储 CSS),请考虑使用推荐示例

选项

url

类型

type url =
  | boolean
  | {
      filter: (url: string, resourcePath: string) => boolean;
    };

默认值:true

启用或禁用对 CSS 函数 urlimage-set 的处理。

  • 如果设置为 falsecss-loader 将不会解析 urlimage-set 中指定的任何路径。
  • 你还可以传递一个函数,根据资产路径动态控制此行为。

从版本 4.0.0 开始,绝对路径根据服务器根目录解析。

解析示例

url(image.png) => require('./image.png')
url('image.png') => require('./image.png')
url(./image.png) => require('./image.png')
url('./image.png') => require('./image.png')
url('http://dontwritehorriblecode.com/2112.png') => require('http://dontwritehorriblecode.com/2112.png')
image-set(url('image2x.png') 1x, url('image1x.png') 2x) => require('./image1x.png') and require('./image2x.png')

要从 node_modules 路径(包括 resolve.modules)或 alias 导入资产,请在其前面加上 ~

url(~module/image.png) => require('module/image.png')
url('~module/image.png') => require('module/image.png')
url(~aliasDirectory/image.png) => require('otherDirectory/image.png')

boolean

启用/禁用 url() 解析。

webpack.config.js

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

object

允许过滤 url() 值。

任何被过滤的 url() 将不会被解析(保留在代码中,原样不动)。

webpack.config.js

module.exports = {
  module: {
    rules: [
      {
        test: /\.css$/i,
        loader: "css-loader",
        options: {
          url: {
            filter: (url, resourcePath) => {
              // resourcePath - path to css file

              // Don't handle `img.png` urls
              if (url.includes("img.png")) {
                return false;
              }

              // Don't handle images under root-relative /external_images/
              if (/^\/external_images\//.test(url)) {
                return false;
              }

              return true;
            },
          },
        },
      },
    ],
  },
};

import

类型

type importFn =
  | boolean
  | {
      filter: (
        url: string,
        media: string,
        resourcePath: string,
        supports?: string,
        layer?: string,
      ) => boolean;
    };

默认值:true

允许你启用或禁用 @import at-rule 的处理。

控制 @import 语句的解析方式。

@import 中的绝对 URL 将在运行时代码中移动。

解析示例

@import 'style.css' => require('./style.css')
@import url(style.css) => require('./style.css')
@import url('style.css') => require('./style.css')
@import './style.css' => require('./style.css')
@import url(./style.css) => require('./style.css')
@import url('./style.css') => require('./style.css')
@import url('http://dontwritehorriblecode.com/style.css') => @import url('http://dontwritehorriblecode.com/style.css') in runtime

要从 node_modules 路径(包括 resolve.modules)或 alias 导入样式,请在其前面加上 ~

@import url(~module/style.css) => require('module/style.css')
@import url('~module/style.css') => require('module/style.css')
@import url(~aliasDirectory/style.css) => require('otherDirectory/style.css')

boolean

启用/禁用 @import 解析。

webpack.config.js

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

object

filter

类型

type filter = (url: string, media: string, resourcePath: string) => boolean;

默认值:undefined

允许过滤 @import

任何被过滤的 @import 将不会被解析(保留在代码中,原样不动)。

webpack.config.js

module.exports = {
  module: {
    rules: [
      {
        test: /\.css$/i,
        loader: "css-loader",
        options: {
          import: {
            filter: (url, media, resourcePath) => {
              // resourcePath - path to css file

              // Don't handle `style.css` import
              if (url.includes("style.css")) {
                return false;
              }

              return true;
            },
          },
        },
      },
    ],
  },
};

modules

类型

type modules =
  | boolean
  | "local"
  | "global"
  | "pure"
  | "icss"
  | {
      auto: boolean | regExp | ((resourcePath: string) => boolean);
      mode:
        | "local"
        | "global"
        | "pure"
        | "icss"
        | ((resourcePath) => "local" | "global" | "pure" | "icss");
      localIdentName: string;
      localIdentContext: string;
      localIdentHashSalt: string;
      localIdentHashFunction: string;
      localIdentHashDigest: string;
      localIdentRegExp: string | regExp;
      getLocalIdent: (
        context: LoaderContext,
        localIdentName: string,
        localName: string,
      ) => string;
      namedExport: boolean;
      exportGlobals: boolean;
      exportLocalsConvention:
        | "as-is"
        | "camel-case"
        | "camel-case-only"
        | "dashes"
        | "dashes-only"
        | ((name: string) => string);
      exportOnlyLocals: boolean;
      getJSON: ({
        resourcePath,
        imports,
        exports,
        replacements,
      }: {
        resourcePath: string;
        imports: object[];
        exports: object[];
        replacements: object[];
      }) => Promise<void> | void;
    };

默认值:undefined

允许你启用或禁用 CSS Modules 或 ICSS 并配置它们。

  • undefined:为所有匹配 /\.module\.\w+$/i.test(filename)/\.icss\.\w+$/i.test(filename) 正则表达式的文件启用 CSS 模块。
  • true:为所有文件启用 CSS 模块。
  • false:为所有文件禁用 CSS 模块。
  • string:为所有文件禁用 CSS 模块并设置 mode 选项(有关详细信息,请参阅mode)。
  • object:为所有文件启用 CSS 模块,除非提供了 modules.auto 选项。否则,modules.auto 选项将决定是否为 CSS 模块(有关详细信息,请参阅auto)。

modules 选项启用/禁用 CSS Modules 规范并配置其行为。

设置 modules: false 可以提高性能,因为我们避免解析 CSS Modules 特性,这对于使用原生 CSS 或其他技术的开发人员很有用。

webpack.config.js

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

特性

作用域
  • 使用 local 值需要你指定 :global 类。
  • 使用 global 值需要你指定 :local 类。
  • 使用 pure 值要求选择器必须包含至少一个本地类或 ID。

你可以在此处找到有关作用域模块的更多信息。

使用 CSS Modules,样式是局部作用域的,防止与全局样式冲突。

使用 :local(.className) 在本地作用域中声明一个 className。本地标识符由模块导出。

  • 使用 :local(不带括号)可以为此选择器开启本地模式。
  • :global(.className) 表示法可用于声明显式全局选择器。
  • 使用 :global(不带括号)可以为此选择器开启全局模式。

加载器将本地选择器替换为唯一的、带作用域的标识符。所选的唯一标识符由模块导出。

:local(.className) {
  background: red;
}
:local .className {
  color: green;
}
:local(.className .subClass) {
  color: green;
}
:local .className .subClass :global(.global-class-name) {
  color: blue;
}

输出(示例)

._23_aKvs-b8bW2Vg3fwHozO {
  background: red;
}
._23_aKvs-b8bW2Vg3fwHozO {
  color: green;
}
._23_aKvs-b8bW2Vg3fwHozO ._13LGdX8RMStbBE9w-t0gZ1 {
  color: green;
}
._23_aKvs-b8bW2Vg3fwHozO ._13LGdX8RMStbBE9w-t0gZ1 .global-class-name {
  color: blue;
}

[!注意]

标识符被导出

exports.locals = {
  className: "_23_aKvs-b8bW2Vg3fwHozO",
  subClass: "_13LGdX8RMStbBE9w-t0gZ1",
};

建议对本地选择器使用 CamelCase 命名,因为它简化了在导入的 JS 模块中的使用。

尽管你可以使用 :local(#someId),但不推荐这样做。对于模块化样式,优先使用类而不是 ID。

组合

在声明本地类名时,你可以将其由一个或多个其他本地类名组合而成。

:local(.className) {
  background: red;
  color: yellow;
}

:local(.subClass) {
  composes: className;
  background: blue;
}

这不会改变最终的 CSS 输出,但生成的 subClass 将在其导出中包含两个类名。

exports.locals = {
  className: "_23_aKvs-b8bW2Vg3fwHozO",
  subClass: "_13LGdX8RMStbBE9w-t0gZ1 _23_aKvs-b8bW2Vg3fwHozO",
};
._23_aKvs-b8bW2Vg3fwHozO {
  background: red;
  color: yellow;
}

._13LGdX8RMStbBE9w-t0gZ1 {
  background: blue;
}
导入

从另一个模块导入本地类名。

[!注意]

强烈建议在导入文件时包含文件扩展名,因为可以导入任何扩展名的文件,并且事先不知道要使用哪个文件。

:local(.continueButton) {
  composes: button from "library/button.css";
  background: red;
}
:local(.nameEdit) {
  composes: edit highlight from "./edit.css";
  background: red;
}

要从多个模块导入,请使用多个 composes: 规则。

:local(.className) {
  composes:
    edit highlight from "./edit.css",
    button from "module/button.css",
    classFromThisModule;
  background: red;
}

:local(.className) {
  composes: edit highlight from "./edit.css";
  composes: button from "module/button.css";
  composes: classFromThisModule;
  background: red;
}

你可以使用 @value 来指定要在整个文档中重用的值。

我们建议遵循命名约定:

  • 值使用 v- 前缀
  • 选择器使用 s- 前缀
  • 媒体规则使用 m- 前缀。
@value v-primary: #BF4040;
@value s-black: black-selector;
@value m-large: (min-width: 960px);

.header {
  color: v-primary;
  padding: 0 10px;
}

.s-black {
  color: black;
}

@media m-large {
  .header {
    padding: 0 20px;
  }
}

boolean

启用 CSS Modules 特性。

webpack.config.js

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

string

启用 CSS Modules 特性并设置 mode

webpack.config.js

module.exports = {
  module: {
    rules: [
      {
        test: /\.css$/i,
        loader: "css-loader",
        options: {
          // Using `local` value has same effect like using `modules: true`
          modules: "global",
        },
      },
    ],
  },
};

object

启用 CSS Modules 特性并通过 options 配置其行为。

webpack.config.js

module.exports = {
  module: {
    rules: [
      {
        test: /\.css$/i,
        loader: "css-loader",
        options: {
          modules: {
            mode: "local",
            auto: true,
            exportGlobals: true,
            localIdentName: "[path][name]__[local]--[hash:base64:5]",
            localIdentContext: path.resolve(__dirname, "src"),
            localIdentHashSalt: "my-custom-hash",
            namedExport: true,
            exportLocalsConvention: "as-is",
            exportOnlyLocals: false,
            getJSON: ({ resourcePath, imports, exports, replacements }) => {},
          },
        },
      },
    ],
  },
};
auto

类型

type auto =
  | boolean
  | regExp
  | ((
      resourcePath: string,
      resourceQuery: string,
      resourceFragment: string,
    ) => boolean);

默认值:undefined

modules 选项是一个对象时,允许根据文件名、查询或片段自动启用 CSS 模块或 ICSS。

可能的值

  • undefined:为所有文件启用 CSS 模块。
  • true:为匹配 /\.module\.\w+$/i.test(filename)/\.icss\.\w+$/i.test(filename) 正则表达式的文件启用 CSS 模块。
  • false:为所有文件禁用 CSS 模块。
  • RegExp:为所有匹配 /RegExp/i.test(filename) 正则表达式的文件启用 CSS 模块。
  • function:根据满足你的过滤函数检查的文件名启用 CSS 模块。
boolean

可能的值

  • true:启用 CSS 模块或可互操作 CSS (ICSS) 格式,将 modules.mode 选项设置为 local 值,适用于所有满足 /\.module(s)?\.\w+$/i.test(filename) 条件的文件;或者将 modules.mode 选项设置为 icss 值,适用于所有满足 /\.icss\.\w+$/i.test(filename) 条件。
  • false:为所有文件根据文件名禁用 CSS 模块或 ICSS 格式。

webpack.config.js

module.exports = {
  module: {
    rules: [
      {
        test: /\.css$/i,
        loader: "css-loader",
        options: {
          modules: {
            auto: true,
          },
        },
      },
    ],
  },
};
RegExp

根据满足你的正则表达式检查的文件名启用 CSS 模块。

webpack.config.js

module.exports = {
  module: {
    rules: [
      {
        test: /\.css$/i,
        loader: "css-loader",
        options: {
          modules: {
            auto: /\.custom-module\.\w+$/i,
          },
        },
      },
    ],
  },
};
function

根据满足你的过滤函数检查的文件名、查询或片段启用 CSS 模块。

webpack.config.js

module.exports = {
  module: {
    rules: [
      {
        test: /\.css$/i,
        loader: "css-loader",
        options: {
          modules: {
            auto: (resourcePath, resourceQuery, resourceFragment) => {
              return resourcePath.endsWith(".custom-module.css");
            },
          },
        },
      },
    ],
  },
};
mode

类型

type mode =
  | "local"
  | "global"
  | "pure"
  | "icss"
  | ((
      resourcePath: string,
      resourceQuery: string,
      resourceFragment: string,
    ) => "local" | "global" | "pure" | "icss");

默认值:'local'

设置 mode 选项。当您想要 local 模式时可以省略该值。

控制应用于输入样式的编译级别。

  • localglobalpure 处理 classid 作用域以及 @value 值。
  • icss 将仅编译低级 可互操作 CSS (ICSS) 格式,用于声明 CSS 与其他语言之间的 :import:export 依赖关系。

ICSS 支撑 CSS Module 支持,并为其他工具提供低级语法以实现其自身的 CSS 模块变体。

string

可能的值 - localglobalpureicss

webpack.config.js

module.exports = {
  module: {
    rules: [
      {
        test: /\.css$/i,
        loader: "css-loader",
        options: {
          modules: {
            mode: "global",
          },
        },
      },
    ],
  },
};
function

允许根据文件名、查询或片段为 mode 选项设置不同的值。可能的返回值 - localglobalpureicss

webpack.config.js

module.exports = {
  module: {
    rules: [
      {
        test: /\.css$/i,
        loader: "css-loader",
        options: {
          modules: {
            // Callback must return "local", "global", or "pure" values
            mode: (resourcePath, resourceQuery, resourceFragment) => {
              if (/pure.css$/i.test(resourcePath)) {
                return "pure";
              }

              if (/global.css$/i.test(resourcePath)) {
                return "global";
              }

              return "local";
            },
          },
        },
      },
    ],
  },
};
localIdentName

类型

type localIdentName = string;

默认值:'[hash:base64]'

允许配置生成的本地标识符名称。

有关选项的更多信息,请参阅:

支持的模板字符串

  • [name] 资源的 basename
  • [folder] 相对于 compiler.context 选项或 modules.localIdentContext 选项的资源文件夹。
  • [path] 相对于 compiler.context 选项或 modules.localIdentContext 选项的资源路径。
  • [file] - 文件名和路径。
  • [ext] - 带前导 . 的扩展名。
  • [hash] - 字符串的哈希值,根据 localIdentHashSaltlocalIdentHashFunctionlocalIdentHashDigestlocalIdentHashDigestLengthlocalIdentContextresourcePathexportName 生成。
  • [<hashFunction>:hash:<hashDigest>:<hashDigestLength>] - 带哈希设置的哈希值。
  • [local] - 原始类。

建议

  • 开发时使用 '[path][name]__[local]'
  • 生产时使用 '[hash:base64]'

[local] 占位符包含原始类。

注意:所有保留字符(<>:"/\|?*)和控制文件系统字符(不包括 [local] 占位符中的字符)将转换为 -

webpack.config.js

module.exports = {
  module: {
    rules: [
      {
        test: /\.css$/i,
        loader: "css-loader",
        options: {
          modules: {
            localIdentName: "[path][name]__[local]--[hash:base64:5]",
          },
        },
      },
    ],
  },
};
localIdentContext

类型

type localIdentContex = string;

默认值:compiler.context

允许为本地标识符名称重新定义基本加载器上下文。

webpack.config.js

module.exports = {
  module: {
    rules: [
      {
        test: /\.css$/i,
        loader: "css-loader",
        options: {
          modules: {
            localIdentContext: path.resolve(__dirname, "src"),
          },
        },
      },
    ],
  },
};
localIdentHashSalt

类型

type localIdentHashSalt = string;

默认值:undefined

允许添加自定义哈希以生成更唯一的类。

有关更多信息,请参阅 output.hashSalt

webpack.config.js

module.exports = {
  module: {
    rules: [
      {
        test: /\.css$/i,
        loader: "css-loader",
        options: {
          modules: {
            localIdentHashSalt: "hash",
          },
        },
      },
    ],
  },
};
localIdentHashFunction

类型

type localIdentHashFunction = string;

默认值:md4

允许指定哈希函数来生成类。

有关更多信息,请参阅 output.hashFunction

webpack.config.js

module.exports = {
  module: {
    rules: [
      {
        test: /\.css$/i,
        loader: "css-loader",
        options: {
          modules: {
            localIdentHashFunction: "md4",
          },
        },
      },
    ],
  },
};
localIdentHashDigest

类型

type localIdentHashDigest = string;

默认值:hex

允许指定哈希摘要来生成类。

有关更多信息,请参阅 output.hashDigest

webpack.config.js

module.exports = {
  module: {
    rules: [
      {
        test: /\.css$/i,
        loader: "css-loader",
        options: {
          modules: {
            localIdentHashDigest: "base64",
          },
        },
      },
    ],
  },
};
localIdentHashDigestLength

类型

type localIdentHashDigestLength = number;

默认值:20

允许指定哈希摘要长度来生成类。

有关更多信息,请参阅 output.hashDigestLength

webpack.config.js

module.exports = {
  module: {
    rules: [
      {
        test: /\.css$/i,
        loader: "css-loader",
        options: {
          modules: {
            localIdentHashDigestLength: 5,
          },
        },
      },
    ],
  },
};
hashStrategy

类型:'resource-path-and-local-name' | 'minimal-subset' 默认值:'resource-path-and-local-name'

计算哈希时是否应使用本地名称。

  • 'resource-path-and-local-name':在哈希时同时使用资源路径和本地名称。模块中的每个标识符总是获得自己的哈希摘要。
  • 'minimal-subset':自动检测标识符名称是否可以从哈希中省略。使用此值可以优化输出,以获得更好的 GZIP 或 Brotli 压缩。

webpack.config.js

module.exports = {
  module: {
    rules: [
      {
        test: /\.css$/i,
        loader: "css-loader",
        options: {
          modules: {
            hashStrategy: "minimal-subset",
          },
        },
      },
    ],
  },
};
localIdentRegExp

类型

type localIdentRegExp = string | RegExp;

默认值:undefined

webpack.config.js

module.exports = {
  module: {
    rules: [
      {
        test: /\.css$/i,
        loader: "css-loader",
        options: {
          modules: {
            localIdentRegExp: /page-(.*)\.css/i,
          },
        },
      },
    ],
  },
};
getLocalIdent

类型

type getLocalIdent = (
  context: LoaderContext,
  localIdentName: string,
  localName: string,
) => string;

默认值:undefined

允许指定一个函数来生成类名。

默认情况下,我们使用内置函数来生成类名。

如果你的自定义函数返回 nullundefined,则使用内置生成器作为 fallback

webpack.config.js

module.exports = {
  module: {
    rules: [
      {
        test: /\.css$/i,
        loader: "css-loader",
        options: {
          modules: {
            getLocalIdent: (context, localIdentName, localName, options) => {
              return "whatever_random_class_name";
            },
          },
        },
      },
    ],
  },
};
namedExport

类型

type namedExport = boolean;

默认值:取决于 esModule 选项的值。如果 esModule 选项的值为 true,则 namedExport 默认为 true;否则,默认为 false

启用或禁用本地的 ES 模块命名导出。

[!警告]

namedExporttrue 时,不能直接使用 default 类名,因为 default 是 ECMAScript 模块中的保留关键字。它会自动重命名为 _default

styles.css

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

index.js

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

// If using `exportLocalsConvention: "as-is"` (default value):
console.log(styles["foo-baz"], styles.bar);

// If using `exportLocalsConvention: "camel-case-only"`:
console.log(styles.fooBaz, styles.bar);

// For the `default` classname
console.log(styles["_default"]);

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

webpack.config.js

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

要为 namedExport 设置自定义名称,可以使用 exportLocalsConvention 选项作为函数。

请参阅下面的示例部分。

exportGlobals

类型

type exportsGLobals = boolean;

默认值:false

允许 css-loader 从全局类或 ID 导出名称,这样你就可以将其用作本地名称。

webpack.config.js

module.exports = {
  module: {
    rules: [
      {
        test: /\.css$/i,
        loader: "css-loader",
        options: {
          modules: {
            exportGlobals: true,
          },
        },
      },
    ],
  },
};
exportLocalsConvention

类型

type exportLocalsConvention =
  | "as-is"
  | "camel-case"
  | "camel-case-only"
  | "dashes"
  | "dashes-only"
  | ((name: string) => string);

默认值:取决于 modules.namedExport 选项的值

  • 如果为 true - as-is
  • 否则为 camel-case-only(类名转换为 camelCase,原始名称被删除)。

[!警告]

当命名导出为 false 时,本地名称将转换为 camelCase,即 exportLocalsConvention 选项默认值为 camelCaseOnly。你可以将其设置回任何其他有效选项,但不是有效 JavaScript 标识符的选择器可能会遇到不完全实现整个模块规范的问题。

导出类名的样式。

string

默认情况下,导出的 JSON 键与类名一致(即 as-is 值)。

名称类型描述
'as-is'string类名将按原样导出。
'camel-case'string类名将转换为 camelCase,但原始类名不会从本地变量中删除。
'camel-case-only'string类名将转换为 camelCase,并且原始类名将从本地变量中删除。
'dashes'string类名中只有连字符将被转换为 camelCase
'dashes-only'string类名中的连字符将被转换为 camelCase,原始类名将从本地变量中删除

file.css

.class-name {
}

file.js

import { className } from "file.css";

webpack.config.js

module.exports = {
  module: {
    rules: [
      {
        test: /\.css$/i,
        loader: "css-loader",
        options: {
          modules: {
            exportLocalsConvention: "camel-case-only",
          },
        },
      },
    ],
  },
};
function

webpack.config.js

module.exports = {
  module: {
    rules: [
      {
        test: /\.css$/i,
        loader: "css-loader",
        options: {
          modules: {
            exportLocalsConvention: function (name) {
              return name.replace(/-/g, "_");
            },
          },
        },
      },
    ],
  },
};

webpack.config.js

module.exports = {
  module: {
    rules: [
      {
        test: /\.css$/i,
        loader: "css-loader",
        options: {
          modules: {
            exportLocalsConvention: function (name) {
              return [
                name.replace(/-/g, "_"),
                // dashesCamelCase
                name.replace(/-+(\w)/g, (match, firstLetter) =>
                  firstLetter.toUpperCase(),
                ),
              ];
            },
          },
        },
      },
    ],
  },
};
exportOnlyLocals

类型

type exportOnlyLocals = boolean;

默认值:false

仅导出本地变量。

当你在预渲染(例如 SSR)中使用 css 模块很有用

对于使用 mini-css-extract-plugin 进行预渲染,你应该在预渲染包中使用此选项,而不是 style-loader!css-loader

它不嵌入 CSS;它只导出标识符映射。

webpack.config.js

module.exports = {
  module: {
    rules: [
      {
        test: /\.css$/i,
        loader: "css-loader",
        options: {
          modules: {
            exportOnlyLocals: true,
          },
        },
      },
    ],
  },
};
getJSON

类型

type getJSON = ({
  resourcePath,
  imports,
  exports,
  replacements,
}: {
  resourcePath: string;
  imports: object[];
  exports: object[];
  replacements: object[];
}) => Promise<void> | void;

默认值:undefined

启用回调函数以输出 CSS 模块映射 JSON。

回调函数将用一个包含以下内容的对象调用:

  • resourcePath:原始资源的绝对路径,例如 /foo/bar/baz.module.css

  • imports:一个导入对象数组,包含导入类型和文件路径的数据,例如:

[
  {
    "type": "icss_import",
    "importName": "___CSS_LOADER_ICSS_IMPORT_0___",
    "url": "\"-!../../../../../node_modules/css-loader/dist/cjs.js??ruleSet[1].rules[4].use[1]!../../../../../node_modules/postcss-loader/dist/cjs.js!../../../../../node_modules/sass-loader/dist/cjs.js!../../../../baz.module.css\"",
    "icss": true,
    "index": 0
  }
]

(请注意,这将包含所有导入,而不仅仅是与 CSS Modules 相关的导入。)

  • exports:一个导出对象数组,包含导出的名称和值,例如:
[
  {
    "name": "main",
    "value": "D2Oy"
  }
]
  • replacements:一个导入替换对象数组,用于链接 importsexports,例如:
{
  "replacementName": "___CSS_LOADER_ICSS_IMPORT_0_REPLACEMENT_0___",
  "importName": "___CSS_LOADER_ICSS_IMPORT_0___",
  "localName": "main"
}

使用 getJSON,可以输出一个包含所有 CSS 模块映射的文件。

在以下示例中,我们使用 getJSON 缓存规范映射并为任何组合值(通过 composes)添加替代,然后使用自定义插件整合这些值并输出到文件。

webpack.config.js

const path = require("path");
const fs = require("fs");

const CSS_LOADER_REPLACEMENT_REGEX =
  /(___CSS_LOADER_ICSS_IMPORT_\d+_REPLACEMENT_\d+___)/g;
const REPLACEMENT_REGEX = /___REPLACEMENT\[(.*?)]\[(.*?)]___/g;
const IDENTIFIER_REGEX = /\[(.*?)]\[(.*?)]/;
const replacementsMap = {};
const canonicalValuesMap = {};
const allExportsJson = {};

function generateIdentifier(resourcePath, localName) {
  return `[${resourcePath}][${localName}]`;
}

function addReplacements(resourcePath, imports, exportsJson, replacements) {
  const importReplacementsMap = {};

  // create a dict to quickly identify imports and get their absolute stand-in strings in the currently loaded file
  // e.g., { '___CSS_LOADER_ICSS_IMPORT_0_REPLACEMENT_0___': '___REPLACEMENT[/foo/bar/baz.css][main]___' }
  importReplacementsMap[resourcePath] = replacements.reduce(
    (acc, { replacementName, importName, localName }) => {
      const replacementImportUrl = imports.find(
        (importData) => importData.importName === importName,
      ).url;
      const relativePathRe = /.*!(.*)"/;
      const [, relativePath] = replacementImportUrl.match(relativePathRe);
      const importPath = path.resolve(path.dirname(resourcePath), relativePath);
      const identifier = generateIdentifier(importPath, localName);
      return { ...acc, [replacementName]: `___REPLACEMENT${identifier}___` };
    },
    {},
  );

  // iterate through the raw exports and add stand-in variables
  // ('___REPLACEMENT[<absolute_path>][<class_name>]___')
  // to be replaced in the plugin below
  for (const [localName, classNames] of Object.entries(exportsJson)) {
    const identifier = generateIdentifier(resourcePath, localName);

    if (CSS_LOADER_REPLACEMENT_REGEX.test(classNames)) {
      // if there are any replacements needed in the concatenated class names,
      // add them all to the replacements map to be replaced altogether later
      replacementsMap[identifier] = classNames.replaceAll(
        CSS_LOADER_REPLACEMENT_REGEX,
        (_, replacementName) =>
          importReplacementsMap[resourcePath][replacementName],
      );
    } else {
      // otherwise, no class names need replacements so we can add them to
      // canonical values map and all exports JSON verbatim
      canonicalValuesMap[identifier] = classNames;

      allExportsJson[resourcePath] = allExportsJson[resourcePath] || {};
      allExportsJson[resourcePath][localName] = classNames;
    }
  }
}

function replaceReplacements(classNames) {
  return classNames.replaceAll(
    REPLACEMENT_REGEX,
    (_, resourcePath, localName) => {
      const identifier = generateIdentifier(resourcePath, localName);

      if (identifier in canonicalValuesMap) {
        return canonicalValuesMap[identifier];
      }

      // Recurse through other stand-in that may be imports
      const canonicalValue = replaceReplacements(replacementsMap[identifier]);

      canonicalValuesMap[identifier] = canonicalValue;

      return canonicalValue;
    },
  );
}

function getJSON({ resourcePath, imports, exports, replacements }) {
  const exportsJson = exports.reduce((acc, { name, value }) => {
    return { ...acc, [name]: value };
  }, {});

  if (replacements.length > 0) {
    // replacements present --> add stand-in values for absolute paths and local names,
    // which will be resolved to their canonical values in the plugin below
    addReplacements(resourcePath, imports, exportsJson, replacements);
  } else {
    // no replacements present --> add to canonicalValuesMap verbatim
    // since all values here are canonical/don't need resolution
    for (const [key, value] of Object.entries(exportsJson)) {
      const id = `[${resourcePath}][${key}]`;

      canonicalValuesMap[id] = value;
    }

    allExportsJson[resourcePath] = exportsJson;
  }
}

class CssModulesJsonPlugin {
  constructor(options) {
    this.options = options;
  }

  // eslint-disable-next-line class-methods-use-this
  apply(compiler) {
    compiler.hooks.emit.tap("CssModulesJsonPlugin", () => {
      for (const [identifier, classNames] of Object.entries(replacementsMap)) {
        const adjustedClassNames = replaceReplacements(classNames);

        replacementsMap[identifier] = adjustedClassNames;

        const [, resourcePath, localName] = identifier.match(IDENTIFIER_REGEX);

        allExportsJson[resourcePath] = allExportsJson[resourcePath] || {};
        allExportsJson[resourcePath][localName] = adjustedClassNames;
      }

      fs.writeFileSync(
        this.options.filepath,
        JSON.stringify(
          // Make path to be relative to `context` (your project root)
          Object.fromEntries(
            Object.entries(allExportsJson).map((key) => {
              key[0] = path
                .relative(compiler.context, key[0])
                .replace(/\\/g, "/");

              return key;
            }),
          ),
          null,
          2,
        ),
        "utf8",
      );
    });
  }
}

module.exports = {
  module: {
    rules: [
      {
        test: /\.css$/i,
        loader: "css-loader",
        options: { modules: { getJSON } },
      },
    ],
  },
  plugins: [
    new CssModulesJsonPlugin({
      filepath: path.resolve(__dirname, "./output.css.json"),
    }),
  ],
};

在上面,所有导入别名在 getJSON 中被替换为 ___REPLACEMENT[<resourcePath>][<localName>]___,并在自定义插件中解析。所有 CSS 映射都包含在 allExportsJson 中。

{
  "foo/bar/baz.module.css": {
    "main": "D2Oy",
    "header": "thNN"
  },
  "foot/bear/bath.module.css": {
    "logo": "sqiR",
    "info": "XMyI"
  }
}

这将被保存到名为 output.css.json 的本地文件中。

importLoaders

类型

type importLoaders = number;

默认值:0

允许启用/禁用或设置在 CSS 加载器之前应用于 @import at-rule、CSS Modules 和 ICSS 导入(即 @import/composes/@value value from './values.css'/等)的加载器数量。

选项 importLoaders 允许你配置在 css-loader 之前应用于 @import 资源和 CSS Modules/ICSS 导入的加载器数量。

webpack.config.js

module.exports = {
  module: {
    rules: [
      {
        test: /\.css$/i,
        use: [
          "style-loader",
          {
            loader: "css-loader",
            options: {
              importLoaders: 2,
              // 0 => no loaders (default);
              // 1 => postcss-loader;
              // 2 => postcss-loader, sass-loader
            },
          },
          "postcss-loader",
          "sass-loader",
        ],
      },
    ],
  },
};

未来当模块系统(例如 webpack)支持按来源匹配加载器时,这可能会改变。

sourceMap

类型

type sourceMap = boolean;

默认值:取决于 compiler.devtool 的值

默认情况下,Source Map 的生成取决于 devtool 选项。除了 evalfalse 值之外,所有值都启用 Source Map 生成。

webpack.config.js

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

esModule

类型

type esModule = boolean;

默认值:true

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

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

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

webpack.config.js

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

exportType

类型

type exportType = "array" | "string" | "css-style-sheet";

默认值:'array'

允许将样式导出为包含模块的数组、字符串或可构造样式表(即CSSStyleSheet)。

默认值为 'array',即加载器导出一个带有特定 API 的模块数组,该 API 用于 style-loader 或其他加载器。

webpack.config.js

module.exports = {
  module: {
    rules: [
      {
        assert: { type: "css" },
        loader: "css-loader",
        options: {
          exportType: "css-style-sheet",
        },
      },
    ],
  },
};

src/index.js

import sheet from "./styles.css" assert { type: "css" };

document.adoptedStyleSheets = [sheet];
shadowRoot.adoptedStyleSheets = [sheet];

'array'

默认导出是一个模块数组,具有在 style-loader 或其他地方使用的特定 API。

webpack.config.js

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

src/index.js

// `style-loader` applies styles to DOM
import "./styles.css";

'string'

[!警告]

你不应该将 style-loadermini-css-extract-plugin 与此值一起使用。

如果你想将其与 CSS 模块一起使用,则应启用 esModule 选项。默认情况下,对于本地变量,将使用命名导出

默认导出是 string

webpack.config.js

module.exports = {
  module: {
    rules: [
      {
        test: /\.(sa|sc|c)ss$/i,
        use: ["css-loader", "postcss-loader", "sass-loader"],
      },
    ],
  },
};

src/index.js

import sheet from "./styles.css";

console.log(sheet);

'css-style-sheet'

[!警告]

@import 规则尚未被允许,更多信息

[!警告]

你不再需要 style-loader,请将其移除。

[!警告]

如果你想将其与 CSS 模块一起使用,则应启用 esModule 选项。默认情况下,对于本地变量,将使用命名导出

[!警告]

由于 bugChrome 目前不支持 Source Map

默认导出是一个可构造样式表(即CSSStyleSheet)。

对于自定义元素和 Shadow DOM 很有用。

更多信息

webpack.config.js

module.exports = {
  module: {
    rules: [
      {
        assert: { type: "css" },
        loader: "css-loader",
        options: {
          exportType: "css-style-sheet",
        },
      },

      // For Sass/SCSS:
      //
      // {
      //   assert: { type: "css" },
      //   rules: [
      //     {
      //       loader: "css-loader",
      //       options: {
      //         exportType: "css-style-sheet",
      //         // Other options
      //       },
      //     },
      //     {
      //       loader: "sass-loader",
      //       options: {
      //         // Other options
      //       },
      //     },
      //   ],
      // },
    ],
  },
};

src/index.js

// Example for Sass/SCSS:
// import sheet from "./styles.scss" assert { type: "css" };

// Example for CSS modules:
// import sheet, { myClass } from "./styles.scss" assert { type: "css" };

// Example for CSS:
import sheet from "./styles.css" assert { type: "css" };

document.adoptedStyleSheets = [sheet];
shadowRoot.adoptedStyleSheets = [sheet];

为了迁移目的,你可以使用以下配置:

module.exports = {
  module: {
    rules: [
      {
        test: /\.css$/i,
        oneOf: [
          {
            assert: { type: "css" },
            loader: "css-loader",
            options: {
              exportType: "css-style-sheet",
              // Other options
            },
          },
          {
            use: [
              "style-loader",
              {
                loader: "css-loader",
                options: {
                  // Other options
                },
              },
            ],
          },
        ],
      },
    ],
  },
};

示例

推荐

对于 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: [
      {
        // If you enable `experiments.css` or `experiments.futureDefaults`, please uncomment line below
        // type: "javascript/auto",
        test: /\.(sa|sc|c)ss$/i,
        use: [
          devMode ? "style-loader" : MiniCssExtractPlugin.loader,
          "css-loader",
          "postcss-loader",
          "sass-loader",
        ],
      },
    ],
  },
  plugins: [].concat(devMode ? [] : [new MiniCssExtractPlugin()]),
};

使用 /* webpackIgnore: true */ 注释禁用 URL 解析

借助 /* webpackIgnore: true */ 注释,可以禁用规则和单个声明的源处理。

/* webpackIgnore: true */
@import url(./basic.css);
@import /* webpackIgnore: true */ url(./imported.css);

.class {
  /* Disabled url handling for the all urls in the 'background' declaration */
  color: red;
  /* webpackIgnore: true */
  background: url("./url/img.png"), url("./url/img.png");
}

.class {
  /* Disabled url handling for the first url in the 'background' declaration */
  color: red;
  background:
    /* webpackIgnore: true */ url("./url/img.png"), url("./url/img.png");
}

.class {
  /* Disabled url handling for the second url in the 'background' declaration */
  color: red;
  background:
    url("./url/img.png"),
    /* webpackIgnore: true */ url("./url/img.png");
}

/* prettier-ignore */
.class {
  /* Disabled url handling for the second url in the 'background' declaration */
  color: red;
  background: url("./url/img.png"),
    /* webpackIgnore: true */
    url("./url/img.png");
}

/* prettier-ignore */
.class {
  /* Disabled url handling for third and sixth urls in the 'background-image' declaration */
  background-image: image-set(
    url(./url/img.png) 2x,
    url(./url/img.png) 3x,
    /* webpackIgnore:  true */ url(./url/img.png) 4x,
    url(./url/img.png) 5x,
    url(./url/img.png) 6x,
    /* webpackIgnore:  true */
    url(./url/img.png) 7x
  );
}

资产

以下 webpack.config.js 可以加载 CSS 文件,将小尺寸的 PNG/JPG/GIF/SVG 图像以及字体嵌入为 数据 URL,并将较大文件复制到输出目录。

对于 webpack v5

webpack.config.js

module.exports = {
  module: {
    rules: [
      {
        test: /\.css$/i,
        use: ["style-loader", "css-loader"],
      },
      {
        test: /\.(png|jpe?g|gif|svg|eot|ttf|woff|woff2)$/i,
        // More information here https://webpack.js.cn/guides/asset-modules/
        type: "asset",
      },
    ],
  },
};

提取

对于生产构建,建议从你的 bundle 中提取 CSS,以便以后能够并行加载 CSS/JS 资源。

  • 这可以通过在生产模式下运行时使用 mini-css-extract-plugin 提取 CSS 来实现。

  • 作为替代方案,如果寻求更好的开发性能和模拟生产的 CSS 输出,extract-css-chunks-webpack-plugin 提供了一个热模块重载友好的 mini-css-extract-plugin 扩展版本。在开发环境中,它支持实时 CSS 文件热模块替换;在非开发环境中,其工作方式与 mini-css 类似。

纯 CSS、CSS Modules 和 PostCSS

当你的项目中包含纯 CSS(不带 CSS 模块)、CSS 模块和 PostCSS 时,你可以使用此设置:

webpack.config.js

module.exports = {
  module: {
    rules: [
      {
        // For pure CSS - /\.css$/i,
        // For Sass/SCSS - /\.((c|sa|sc)ss)$/i,
        // For Less - /\.((c|le)ss)$/i,
        test: /\.((c|sa|sc)ss)$/i,
        use: [
          "style-loader",
          {
            loader: "css-loader",
            options: {
              // Run `postcss-loader` on each CSS `@import` and CSS modules/ICSS imports, do not forget that `sass-loader` compile non CSS `@import`'s into a single file
              // If you need run `sass-loader` and `postcss-loader` on each CSS `@import` please set it to `2`
              importLoaders: 1,
            },
          },
          {
            loader: "postcss-loader",
            options: { plugins: () => [postcssPresetEnv({ stage: 0 })] },
          },
          // Can be `less-loader`
          {
            loader: "sass-loader",
          },
        ],
      },
      // For webpack v5
      {
        test: /\.(png|jpe?g|gif|svg|eot|ttf|woff|woff2)$/i,
        // More information here https://webpack.js.cn/guides/asset-modules/
        type: "asset",
      },
    ],
  },
};

使用别名解析未解析的 URL

index.css

.class {
  background: url(/assets/unresolved/img.png);
}

webpack.config.js

module.exports = {
  module: {
    rules: [
      {
        test: /\.css$/i,
        use: ["style-loader", "css-loader"],
      },
    ],
  },
  resolve: {
    alias: {
      "/assets/unresolved/img.png": path.resolve(
        __dirname,
        "assets/real-path-to-img/img.png",
      ),
    },
  },
};

带自定义导出名称的命名导出

webpack.config.js

module.exports = {
  module: {
    rules: [
      {
        test: /\.css$/i,
        loader: "css-loader",
        options: {
          modules: {
            namedExport: true,
            exportLocalsConvention: function (name) {
              return name.replace(/-/g, "_");
            },
          },
        },
      },
    ],
  },
};

分离 Interoperable CSS 专用特性和 CSS Module 特性

以下设置是一个示例,仅允许使用 Interoperable CSS 特性(例如 :import:export),而不使用其他 CSS Module 功能,通过为所有不符合 *.module.scss 命名约定的文件设置 mode 选项。这仅供参考,因为在 v4 之前,将 ICSS 特性应用于所有文件是 css-loader 的默认行为。

同时,在此示例中,所有匹配 *.module.scss 的文件都被视为 CSS Modules

假设一个示例场景:项目需要将 Canvas 绘图变量与 CSS 同步——Canvas 绘图使用与 HTML 背景(通过 CSS 中的类名设置)相同的颜色(在 JavaScript 中通过颜色名称设置)。

webpack.config.js

module.exports = {
  module: {
    rules: [
      // ...
      // --------
      // SCSS ALL EXCEPT MODULES
      {
        test: /\.scss$/i,
        exclude: /\.module\.scss$/i,
        use: [
          {
            loader: "style-loader",
          },
          {
            loader: "css-loader",
            options: {
              importLoaders: 1,
              modules: {
                mode: "icss",
              },
            },
          },
          {
            loader: "sass-loader",
          },
        ],
      },
      // --------
      // SCSS MODULES
      {
        test: /\.module\.scss$/i,
        use: [
          {
            loader: "style-loader",
          },
          {
            loader: "css-loader",
            options: {
              importLoaders: 1,
              modules: {
                mode: "local",
              },
            },
          },
          {
            loader: "sass-loader",
          },
        ],
      },
      // --------
      // ...
    ],
  },
};

variables.scss

文件仅作为 ICSS 处理。

$colorBackground: red;
:export {
  colorBackgroundCanvas: $colorBackground;
}

Component.module.scss

文件作为 CSS Module 处理。

@import "variables.scss";
.componentClass {
  background-color: $colorBackground;
}

Component.jsx

在 JavaScript 中直接使用 CSS Module 功能和 SCSS 变量。

import * as svars from "variables.scss";
import * as styles from "Component.module.scss";

// Render DOM with CSS modules class name
// <div className={styles.componentClass}>
//   <canvas ref={mountsCanvas}/>
// </div>

// Somewhere in JavaScript canvas drawing code use the variable directly
// const ctx = mountsCanvas.current.getContext('2d',{alpha: false});
ctx.fillStyle = `${svars.colorBackgroundCanvas}`;

贡献

我们欢迎所有贡献!

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

CONTRIBUTING

许可证

MIT

exports-loader

npm node tests coverage discussion size

允许你为源文件使用 module.exportsexport 设置导出。

当源文件不包含导出或某些内容未导出时很有用。

有关兼容性问题的更多信息,请参阅官方文档中的垫片指南。

[!警告]

默认情况下,加载器使用 ES 模块语法生成导出。

[!警告]

请注意:修改现有导出(exportmodule.exportsexports)或添加新导出可能会导致错误。

入门

首先,你需要安装 exports-loader

npm install exports-loader --save-dev

yarn add -D exports-loader

pnpm add -D exports-loader

内联

|%20(空格)允许分隔导出的 syntaxnamealias

文档和语法示例可以在此处阅读。

[!警告]

%20 在查询字符串中代表一个空格,因为 URL 中不允许有空格。

然后将加载器添加到所需的 import 语句或 require 调用中。例如:

import { myFunction } from "exports-loader?exports=myFunction!./file.js";
// Adds the following code to the file's source:
//
// ...
// Code
// ...
//
// export { myFunction }

myFunction("Hello world");
import {
  myVariable,
  myFunction,
} from "exports-loader?exports=myVariable,myFunction!./file.js";
// Adds the following code to the file's source:
//
// ...
// Code
// ...
//
// export { myVariable, myFunction };

const newVariable = myVariable + "!!!";

console.log(newVariable);

myFunction("Hello world");
const {
  myFunction,
} = require("exports-loader?type=commonjs&exports=myFunction!./file.js");
// Adds the following code to the file's source:
//
// ...
// Code
// ...
//
// module.exports = { myFunction }

myFunction("Hello world");
// Alternative syntax:
// import myFunction from 'exports-loader?exports=default%20myFunction!./file.js';
import myFunction from "exports-loader?exports=default|myFunction!./file.js";
// `%20` is space in a query string, equivalently `default myFunction`
// Adds the following code to the file's source:
//
// ...
// Code
// ...
//
// exports default myFunction;

myFunction("Hello world");
const myFunction = require("exports-loader?type=commonjs&exports=single|myFunction!./file.js");
// `|` is separator in a query string, equivalently `single|myFunction`
// Adds the following code to the file's source:
//
// ...
// Code
// ...
//
// module.exports = myFunction;

myFunction("Hello world");
import { myFunctionAlias } from "exports-loader?exports=named|myFunction|myFunctionAlias!./file.js";
// `|` is separator in a query string, equivalently `named|myFunction|myFunctionAlias`
// Adds the following code to the file's source:
//
// ...
// Code
// ...
//
// exports { myFunction as myFunctionAlias };

myFunctionAlias("Hello world");

字符串值的描述可以在下面的文档中找到。

使用配置

webpack.config.js

module.exports = {
  module: {
    rules: [
      {
        // You can use `regexp`
        // test: /vendor\.js/$
        test: require.resolve("./path/to/vendor.js"),
        loader: "exports-loader",
        options: {
          exports: "myFunction",
        },
      },
    ],
  },
};

最后,使用你通常使用的方法运行 webpack(例如,通过 CLI 或 npm 脚本)。

选项

名称类型默认值描述
type{String}module生成导出的格式
导出{String|Object|Array<String|Object>}undefined导出列表

type

类型:String 默认值:module

生成导出的格式。

可能的值 - commonjs (CommonJS 模块语法) 和 module (ES 模块语法)。

commonjs

webpack.config.js

module.exports = {
  module: {
    rules: [
      {
        test: require.resolve("./path/to/vendor.js"),
        loader: "exports-loader",
        options: {
          type: "commonjs",
          exports: "Foo",
        },
      },
    ],
  },
};

生成输出

// ...
// Code
// ...

module.exports = { Foo };

module

webpack.config.js

module.exports = {
  module: {
    rules: [
      {
        test: require.resolve("./path/to/vendor.js"),
        loader: "exports-loader",
        options: {
          type: "module",
          exports: "Foo",
        },
      },
    ],
  },
};

生成输出

// ...
// Code
// ...

export { Foo };

exports

类型:String|Array 默认值:undefined

导出列表。

String

允许使用字符串描述导出。

语法

|%20(空格)允许分隔导出的 syntaxnamealias

字符串语法 - [[syntax] [name] [alias]][[syntax]|[name]|[alias]],其中

  • [syntax] (可省略) -

    • 如果 typemodule - 可以是 defaultnamed
    • 如果 typecommonjs - 可以是 singlemultiple
  • [name] - 导出值的名称(必填

  • [alias] - 导出值的别名(可省略

示例

  • [Foo] - 生成 export { Foo };
  • [default Foo] - 生成 export default Foo;
  • [named Foo] - 生成 export { Foo };
  • [named Foo FooA] - 生成 export { Foo as FooA };
  • [single Foo] - 生成 module.exports = Foo;
  • [multiple Foo] - 生成 module.exports = { Foo };
  • [multiple Foo FooA] - 生成 module.exports = { 'FooA': Foo };
  • [named [name] [name]Alias] - 生成 ES 模块命名导出,并以其他名称导出与文件名相等的值。对于 single.js,它将是 singlesingleAlias,生成 export { single as singleAlias };

[!警告]

你需要设置 type: "commonjs" 来使用 singlemultiple 语法。

[!警告]

别名不能与 defaultsingle 语法一起使用。

示例
ES 模块默认导出

webpack.config.js

module.exports = {
  module: {
    rules: [
      {
        test: require.resolve("./path/to/vendor.js"),
        loader: "exports-loader",
        options: {
          exports: "default Foo",
        },
      },
    ],
  },
};

生成输出

// ...
// Code
// ...

export default Foo;
ES 模块命名导出

webpack.config.js

module.exports = {
  module: {
    rules: [
      {
        test: require.resolve("./path/to/vendor.js"),
        loader: "exports-loader",
        options: {
          exports: "named Foo FooA",
        },
      },
    ],
  },
};

生成输出

// ...
// Code
// ...

export { Foo as FooA };
CommonJS 单一导出

webpack.config.js

module.exports = {
  module: {
    rules: [
      {
        test: require.resolve("./path/to/vendor.js"),
        loader: "exports-loader",
        options: {
          type: "commonjs",
          exports: "single Foo",
        },
      },
    ],
  },
};

生成输出

// ...
// Code
// ...

module.exports = Foo;
CommonJS 多个导出

webpack.config.js

module.exports = {
  module: {
    rules: [
      {
        test: require.resolve("./path/to/vendor.js"),
        loader: "exports-loader",
        options: {
          type: "commonjs",
          exports: "multiple Foo FooA",
        },
      },
    ],
  },
};

生成输出

// ...
// Code
// ...

module.exports = { FooA: Foo };

Object

允许使用对象描述导出。

属性

  • syntax - 对于 module 类型(ES 模块模块格式)可以是 defaultnamed,对于 commonjs 类型(CommonJS 模块格式)可以是 singlemultiple可省略
  • name - 导出值的名称(必填
  • alias - 导出值的别名(可省略
示例
ES 模块默认导出

webpack.config.js

module.exports = {
  module: {
    rules: [
      {
        test: require.resolve("./path/to/vendor.js"),
        loader: "exports-loader",
        options: {
          exports: {
            syntax: "default",
            name: "Foo",
          },
        },
      },
    ],
  },
};

生成输出

// ...
// Code
// ...

export default Foo;
ES 模块命名导出

webpack.config.js

module.exports = {
  module: {
    rules: [
      {
        test: require.resolve("./path/to/vendor.js"),
        loader: "exports-loader",
        options: {
          exports: {
            syntax: "named",
            name: "Foo",
            alias: "FooA",
          },
        },
      },
    ],
  },
};

生成输出

// ...
// Code
// ...

export { Foo as FooA };
CommonJS 单一导出

webpack.config.js

module.exports = {
  module: {
    rules: [
      {
        test: require.resolve("./path/to/vendor.js"),
        loader: "exports-loader",
        options: {
          type: "commonjs",
          exports: {
            syntax: "single",
            name: "Foo",
          },
        },
      },
    ],
  },
};

生成输出

// ...
// Code
// ...

module.exports = Foo;
CommonJS 多个导出

webpack.config.js

module.exports = {
  module: {
    rules: [
      {
        test: require.resolve("./path/to/vendor.js"),
        loader: "exports-loader",
        options: {
          type: "commonjs",
          exports: {
            syntax: "multiple",
            name: "Foo",
            alias: "FooA",
          },
        },
      },
    ],
  },
};

生成输出

// ...
// Code
// ...

module.exports = { FooA: Foo };

Array

允许指定多个导出。每个项可以是字符串对象

[!警告]

由于 CommonJS 格式限制,无法同时使用 singlemultiple 语法。

[!警告]

由于 ES 模块格式限制,无法使用多个 default 值。

[!警告]

由于 CommonJS 格式限制,无法使用多个 single 值。

示例
CommonJS 多个导出

webpack.config.js

module.exports = {
  module: {
    rules: [
      {
        test: require.resolve("./path/to/vendor.js"),
        loader: "exports-loader",
        options: {
          type: "commonjs",
          exports: ["Foo", "multiple Bar", "multiple Baz BazA"],
        },
      },
    ],
  },
};

生成输出

// ...
// Code
// ...

module.exports = { Foo, Bar, BazA: Bar };
ES 模块默认导出和命名导出同时使用

webpack.config.js

module.exports = {
  module: {
    rules: [
      {
        test: require.resolve("./path/to/vendor.js"),
        loader: "exports-loader",
        options: {
          exports: ["default Foo", "named Bar BarA"],
        },
      },
    ],
  },
};

生成输出

// ...
// Code
// ...

export default Foo;
export { Bar as BarA };
命名导出

webpack.config.js

module.exports = {
  module: {
    rules: [
      {
        test: require.resolve("./path/to/vendor.js"),
        loader: "exports-loader",
        options: {
          exports: [
            { syntax: "named", name: "Foo", alias: "FooA" },
            { syntax: "named", name: "Bar" },
            "Baz",
          ],
        },
      },
    ],
  },
};

生成输出

// ...
// Code
// ...

export { Foo as FooA, Bar, Baz };

贡献

我们欢迎所有贡献!

如果你是新用户,请花一些时间阅读我们的贡献指南。

CONTRIBUTING

许可证

MIT

expose-loader

npm node tests coverage discussion size

expose-loader 加载器允许将模块(全部或部分)暴露给全局对象(selfwindowglobal)。

有关兼容性提示和示例,请查阅官方文档中的垫片指南。

入门

首先,你需要安装 expose-loader

npm install expose-loader --save-dev

yarn add -D expose-loader

pnpm add -D expose-loader

(如果你使用 webpack 4,请安装 expose-loader@1 并遵循相应的说明。)

然后你可以使用两种方法使用 expose-loader

内联

|%20(空格)允许分隔暴露的 globalNamemoduleLocalNameoverride

文档和语法示例可以在此处阅读。

[!警告]

%20 在查询字符串中代表一个空格,因为 URL 中不允许有空格。

import $ from "expose-loader?exposes=$,jQuery!jquery";
//
// Adds the `jquery` to the global object under the names `$` and `jQuery`
import { concat } from "expose-loader?exposes=_.concat!lodash/concat";
//
// Adds the `lodash/concat` to the global object under the name `_.concat`
import {
  map,
  reduce,
} from "expose-loader?exposes=_.map|map,_.reduce|reduce!underscore";
//
// Adds the `map` and `reduce` method from `underscore` to the global object under the name `_.map` and `_.reduce`

使用配置

src/index.js

import $ from "jquery";

webpack.config.js

module.exports = {
  module: {
    rules: [
      {
        test: require.resolve("jquery"),
        loader: "expose-loader",
        options: {
          exposes: ["$", "jQuery"],
        },
      },
      {
        test: require.resolve("underscore"),
        loader: "expose-loader",
        options: {
          exposes: [
            "_.map|map",
            {
              globalName: "_.reduce",
              moduleLocalName: "reduce",
            },
            {
              globalName: ["_", "filter"],
              moduleLocalName: "filter",
            },
          ],
        },
      },
    ],
  },
};

require.resolve 的调用是 Node.js 函数(与 webpack 处理中的 require.resolve 无关)。

require.resolve 返回模块的绝对路径("/.../app/node_modules/jquery/dist/jquery.js")。

因此,暴露仅适用于 jquery 模块,并且仅在 bundle 中使用时才暴露。

最后,使用你通常使用的方法运行 webpack(例如,通过 CLI 或 npm 脚本)。

选项

名称类型默认值描述
暴露{String|Object|Array<String|Object>}undefined暴露列表
globalObjectStringundefined用于全局上下文的对象

exposes

类型

type exposes =
  | string
  | {
      globalName: string | Array<string>;
      moduleLocalName?: string;
      override?: boolean;
    }
  | Array<
      | string
      | {
          globalName: string | Array<string>;
          moduleLocalName?: string;
          override?: boolean;
        }
    >;

默认值:undefined

暴露列表。

string

允许使用 string 来描述一个暴露。

语法

|%20(空格)允许分隔暴露的 globalNamemoduleLocalNameoverride

字符串语法 - [[globalName] [moduleLocalName] [override]][[globalName]|[moduleLocalName]|[override]],其中

  • globalName - 全局对象上的名称,例如浏览器环境中的 window.$ (必填)
  • moduleLocalName - 模块的方法/变量等的名称(模块必须导出它)(可省略)
  • override - 允许覆盖全局对象中的现有值(可省略

如果未指定 moduleLocalName,则它将整个模块暴露给全局对象,否则仅暴露 moduleLocalName 的值。

src/index.js

import $ from "jquery";
import _ from "underscore";

webpack.config.js

module.exports = {
  module: {
    rules: [
      {
        test: require.resolve("jquery"),
        loader: "expose-loader",
        options: {
          // For `underscore` library, it can be `_.map map` or `_.map|map`
          exposes: "$",
          // To access please use `window.$` or `globalThis.$`
        },
      },
      {
        // test: require.resolve("jquery"),
        test: /node_modules[/\\]underscore[/\\]modules[/\\]index-all\.js$/,
        loader: "expose-loader",
        type: "javascript/auto",
        options: {
          // For `underscore` library, it can be `_.map map` or `_.map|map`
          exposes: "_",
          // To access please use `window._` or `globalThis._`
        },
      },
    ],
  },
};

object

允许使用对象描述一个暴露。

globalName

类型

type globalName = string | Array<string>;

默认值:undefined

全局对象中的名称。(必填)。

src/index.js

import _ from "underscore";

webpack.config.js

module.exports = {
  module: {
    rules: [
      {
        test: /node_modules[/\\]underscore[/\\]modules[/\\]index-all\.js$/,
        loader: "expose-loader",
        type: "javascript/auto",
        options: {
          exposes: {
            // Can be `['_', 'filter']`
            globalName: "_.filter",
            moduleLocalName: "filter",
          },
        },
      },
    ],
  },
};
moduleLocalName

类型

type moduleLocalName = string;

默认值:undefined

模块的方法/变量等的名称(模块必须导出它)。

如果指定了 moduleLocalName,则它仅暴露 moduleLocalName 的值。

src/index.js

import _ from "underscore";

webpack.config.js

module.exports = {
  module: {
    rules: [
      {
        test: /node_modules[/\\]underscore[/\\]modules[/\\]index-all\.js$/,
        loader: "expose-loader",
        type: "javascript/auto",
        options: {
          exposes: {
            globalName: "_.filter",
            moduleLocalName: "filter",
          },
        },
      },
    ],
  },
};
override

类型

type override = boolean;

默认值:false

默认情况下,加载器不会覆盖全局对象中的现有值,因为这是不安全的。

development 模式下,如果全局对象中已存在该值,我们将抛出错误。

但你可以使用此选项配置加载器以覆盖全局对象中的现有值。

要强制覆盖全局对象中已存在的值,你可以将 override 选项设置为 true

src/index.js

import $ from "jquery";

webpack.config.js

module.exports = {
  module: {
    rules: [
      {
        test: require.resolve("jquery"),
        loader: "expose-loader",
        options: {
          exposes: {
            globalName: "$",
            override: true,
          },
        },
      },
    ],
  },
};

array

src/index.js

import _ from "underscore";

webpack.config.js

module.exports = {
  module: {
    rules: [
      {
        test: /node_modules[/\\]underscore[/\\]modules[/\\]index-all\.js$/,
        loader: "expose-loader",
        type: "javascript/auto",
        options: {
          exposes: [
            "_.map map",
            {
              globalName: "_.filter",
              moduleLocalName: "filter",
            },
            {
              globalName: ["_", "find"],
              moduleLocalName: "myNameForFind",
            },
          ],
        },
      },
    ],
  },
};

它将mapfilterfind(在 myNameForFind 名称下)方法暴露给全局对象。

在浏览器中,这些方法将以 windows._.map(..args)windows._.filter(...args)windows._.myNameForFind(...args) 的形式可用。

globalObject

type globalObject = string;

默认值:undefined

用于全局上下文的对象

import _ from "underscore";

webpack.config.js

module.exports = {
  module: {
    rules: [
      {
        test: /node_modules[/\\]underscore[/\\]modules[/\\]index-all\.js$/,
        loader: "expose-loader",
        type: "javascript/auto",
        options: {
          exposes: [
            {
              globalName: "_",
            },
          ],
          globalObject: "this",
        },
      },
    ],
  },
};

示例

暴露本地模块

index.js

import { method1 } from "./my-module.js";

my-module.js

function method1() {
  console.log("method1");
}

function method2() {
  console.log("method1");
}

export { method1, method2 };

webpack.config.js

module.exports = {
  module: {
    rules: [
      {
        test: /my-module\.js$/,
        loader: "expose-loader",
        options: {
          exposes: "mod",
          // // To access please use `window.mod` or `globalThis.mod`
        },
      },
    ],
  },
};

贡献

我们欢迎所有贡献!

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

CONTRIBUTING

许可证

MIT

html-loader

npm node tests coverage discussion size

将 HTML 导出为字符串。在编译器要求时,HTML 会被最小化。

入门

首先,你需要安装 html-loader

npm install --save-dev html-loader

yarn add -D html-loader

pnpm add -D html-loader

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

file.js

import html from "./file.html";

webpack.config.js

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

选项

sources

类型

type sources =
  | boolean
  | {
      list?: Array<{
        tag?: string;
        attribute?: string;
        type?: string;
        filter?: (
          tag: string,
          attribute: string,
          attributes: string,
          resourcePath: string,
        ) => boolean;
      }>;
      urlFilter?: (
        attribute: string,
        value: string,
        resourcePath: string,
      ) => boolean;
      scriptingEnabled?: boolean;
    };

默认值:true

默认情况下,每个可加载属性(例如 - <img src="image.png"/>)都会被导入(const img = require('./image.png')new URL("./image.png", import.meta.url))。你可能需要在配置中为图像指定加载器(推荐使用资产模块)。

支持的标签和属性

  • audio 标签的 src 属性
  • embed 标签的 src 属性
  • img 标签的 src 属性
  • img 标签的 srcset 属性
  • input 标签的 src 属性
  • object 标签的 data 属性
  • script 标签的 src 属性
  • script 标签的 href 属性
  • script 标签的 xlink:href 属性
  • source 标签的 src 属性
  • source 标签的 srcset 属性
  • track 标签的 src 属性
  • video 标签的 poster 属性
  • video 标签的 src 属性
  • image 标签的 xlink:href 属性
  • image 标签的 href 属性
  • use 标签的 xlink:href 属性
  • use 标签的 href 属性
  • link 标签的 href 属性,当 rel 属性包含 stylesheet, icon, shortcut icon, mask-icon, apple-touch-icon, apple-touch-icon-precomposed, apple-touch-startup-image, manifest, prefetch, preload 时;或者当 itemprop 属性为 image, logo, screenshot, thumbnailurl, contenturl, downloadurl, duringmedia, embedurl, installurl, layoutimage
  • link 标签的 imagesrcset 属性,当 rel 属性包含 stylesheet, icon, shortcut icon, mask-icon, apple-touch-icon, apple-touch-icon-precomposed, apple-touch-startup-image, manifest, prefetch, preload
  • meta 标签的 content 属性,当 name 属性为 msapplication-tileimage, msapplication-square70x70logo, msapplication-square150x150logo, msapplication-wide310x150logo, msapplication-square310x310logo, msapplication-config, twitter:image 时;或者当 property 属性为 og:image, og:image:url, og:image:secure_url, og:audio, og:audio:secure_url, og:video, og:video:secure_url, vk:image 时;或者当 itemprop 属性为 image, logo, screenshot, thumbnailurl, contenturl, downloadurl, duringmedia, embedurl, installurl, layoutimage
  • meta 标签 content 属性中的 icon-uri 值组件,当 name 属性为 msapplication-task

boolean

  • true:启用所有默认标签和属性的处理
  • false:完全禁用处理

webpack.config.js

module.exports = {
  module: {
    rules: [
      {
        test: /\.html$/i,
        loader: "html-loader",
        options: {
          // Disables attributes processing
          sources: false,
        },
      },
    ],
  },
};

object

允许你指定要处理哪些标签和属性,过滤它们,过滤 URL 并处理以 / 开头的源。

例如:

webpack.config.js

module.exports = {
  module: {
    rules: [
      {
        test: /\.html$/i,
        loader: "html-loader",
        options: {
          sources: {
            list: [
              // All default supported tags and attributes
              "...",
              {
                tag: "img",
                attribute: "data-src",
                type: "src",
              },
              {
                tag: "img",
                attribute: "data-srcset",
                type: "srcset",
              },
            ],
            urlFilter: (attribute, value, resourcePath) => {
              // The `attribute` argument contains a name of the HTML attribute.
              // The `value` argument contains a value of the HTML attribute.
              // The `resourcePath` argument contains a path to the loaded HTML file.

              if (/example\.pdf$/.test(value)) {
                return false;
              }

              return true;
            },
          },
        },
      },
    ],
  },
};

list

类型

type list = Array<{
  tag?: string;
  attribute?: string;
  type?: string;
  filter?: (
    tag: string,
    attribute: string,
    attributes: string,
    resourcePath: string,
  ) => boolean;
}>;

默认值:支持的标签和属性

允许设置要处理哪些标签和属性以及如何处理,以及过滤其中一些标签和属性的功能。

使用 ... 语法允许你扩展默认支持的标签和属性

例如:

webpack.config.js

module.exports = {
  module: {
    rules: [
      {
        test: /\.html$/i,
        loader: "html-loader",
        options: {
          sources: {
            list: [
              // All default supported tags and attributes
              "...",
              {
                tag: "img",
                attribute: "data-src",
                type: "src",
              },
              {
                tag: "img",
                attribute: "data-srcset",
                type: "srcset",
              },
              {
                // Tag name
                tag: "link",
                // Attribute name
                attribute: "href",
                // Type of processing, can be `src` or `scrset`
                type: "src",
                // Allow to filter some attributes
                filter: (tag, attribute, attributes, resourcePath) => {
                  // The `tag` argument contains a name of the HTML tag.
                  // The `attribute` argument contains a name of the HTML attribute.
                  // The `attributes` argument contains all attributes of the tag.
                  // The `resourcePath` argument contains a path to the loaded HTML file.

                  if (/my-html\.html$/.test(resourcePath)) {
                    return false;
                  }

                  if (!/stylesheet/i.test(attributes.rel)) {
                    return false;
                  }

                  if (
                    attributes.type &&
                    attributes.type.trim().toLowerCase() !== "text/css"
                  ) {
                    return false;
                  }

                  return true;
                },
              },
            ],
          },
        },
      },
    ],
  },
};

如果未指定标签名,它将处理所有标签。

你可以使用自定义过滤器来指定要处理的 HTML 元素。

例如:

webpack.config.js

module.exports = {
  module: {
    rules: [
      {
        test: /\.html$/i,
        loader: "html-loader",
        options: {
          sources: {
            list: [
              {
                // Attribute name
                attribute: "src",
                // Type of processing, can be `src` or `scrset`
                type: "src",
                // Allow to filter some attributes (optional)
                filter: (tag, attribute, attributes, resourcePath) => {
                  // The `tag` argument contains a name of the HTML tag.
                  // The `attribute` argument contains a name of the HTML attribute.
                  // The `attributes` argument contains all attributes of the tag.
                  // The `resourcePath` argument contains a path to the loaded HTML file.

                  // choose all HTML tags except img tag
                  return tag.toLowerCase() !== "img";
                },
              },
            ],
          },
        },
      },
    ],
  },
};

过滤器也可以用于扩展支持的元素和属性。

例如,过滤器可以帮助处理引用资产的 meta 标签:

module.exports = {
  module: {
    rules: [
      {
        test: /\.html$/i,
        loader: "html-loader",
        options: {
          sources: {
            list: [
              {
                tag: "meta",
                attribute: "content",
                type: "src",
                filter: (tag, attribute, attributes, resourcePath) => {
                  if (
                    attributes.value === "og:image" ||
                    attributes.name === "twitter:image"
                  ) {
                    return true;
                  }

                  return false;
                },
              },
            ],
          },
        },
      },
    ],
  },
};

[!注意]

带有 tag 选项的源优先于不带 tag 选项的源。

过滤器可用于禁用默认源。

例如:

module.exports = {
  module: {
    rules: [
      {
        test: /\.html$/i,
        loader: "html-loader",
        options: {
          sources: {
            list: [
              "...",
              {
                tag: "img",
                attribute: "src",
                type: "src",
                filter: () => false,
              },
            ],
          },
        },
      },
    ],
  },
};

urlFilter

类型

type urlFilter = (
  attribute: string,
  value: string,
  resourcePath: string,
) => boolean;

默认值:undefined

允许过滤 URL。所有被过滤的 URL 将不会被解析(保留在代码中,原样不动)。不可请求的源(例如 <img src="javascript:void(0)"/>)默认不处理。

module.exports = {
  module: {
    rules: [
      {
        test: /\.html$/i,
        loader: "html-loader",
        options: {
          sources: {
            urlFilter: (attribute, value, resourcePath) => {
              // The `attribute` argument contains a name of the HTML attribute.
              // The `value` argument contains a value of the HTML attribute.
              // The `resourcePath` argument contains a path to the loaded HTML file.

              if (/example\.pdf$/.test(value)) {
                return false;
              }

              return true;
            },
          },
        },
      },
    ],
  },
};

scriptingEnabled

类型

type scriptingEnabled = boolean;

默认值:true

默认情况下,html-loader 中的解析器将 <noscript> 标签内的内容解释为纯 #text,因此在处理过程中会忽略这些标签内内容的解析。

为了启用 <noscript> 内部的处理,让解析器将内容识别为 #AST,请将此选项设置为:false

附加信息:scriptingEnabled

webpack.config.js

module.exports = {
  module: {
    rules: [
      {
        test: /\.html$/i,
        loader: "html-loader",
        options: {
          sources: {
            // Enables processing inside the <noscript> tag
            scriptingEnabled: false,
          },
        },
      },
    ],
  },
};

preprocessor

类型

type preprocessor = (content: string, loaderContext: LoaderContext) => string;

默认值:undefined

允许在加载器处理之前对内容进行预处理。

[!警告]

你应始终返回有效的 HTML。

file.hbs

<div>
  <p>{{firstname}} {{lastname}}</p>
  <img src="image.png" alt="alt" />
<div>

function

你可以将 preprocessor 选项设置为 function 实例。

webpack.config.js

const Handlebars = require("handlebars");

module.exports = {
  module: {
    rules: [
      {
        test: /\.hbs$/i,
        loader: "html-loader",
        options: {
          preprocessor: (content, loaderContext) => {
            let result;

            try {
              result = Handlebars.compile(content)({
                firstname: "Value",
                lastname: "OtherValue",
              });
            } catch (error) {
              loaderContext.emitError(error);

              return content;
            }

            return result;
          },
        },
      },
    ],
  },
};

你也可以将 preprocessor 选项设置为异步函数实例。

例如:

webpack.config.js

const Handlebars = require("handlebars");

module.exports = {
  module: {
    rules: [
      {
        test: /\.hbs$/i,
        loader: "html-loader",
        options: {
          preprocessor: async (content, loaderContext) => {
            let result;

            try {
              result = await Handlebars.compile(content)({
                firstname: "Value",
                lastname: "OtherValue",
              });
            } catch (error) {
              await loaderContext.emitError(error);

              return content;
            }

            return result;
          },
        },
      },
    ],
  },
};

postprocessor

类型

type postprocessor = (content: string, loaderContext: LoaderContext) => string;

默认值:undefined

允许在替换所有属性(如 src/srcset/等)后对内容进行后处理。

file.html

<img src="image.png" />
<img src="<%= 'Hello ' + (1+1) %/>" />
<img src="<%= require('./image.png') %>" />
<img src="<%= new URL('./image.png', import.meta.url) %>" />
<div><%= require('./gallery.html').default %></div>

function

你可以将 postprocessor 选项设置为 function 实例。

webpack.config.js

const Handlebars = require("handlebars");

module.exports = {
  module: {
    rules: [
      {
        test: /\.html$/i,
        loader: "html-loader",
        options: {
          postprocessor: (content, loaderContext) => {
            // When you environment supports template literals (using browserslist or options) we will generate code using them
            const isTemplateLiteralSupported = content[0] === "`";

            return content
              .replace(/<%=/g, isTemplateLiteralSupported ? `\${` : '" +')
              .replace(/%>/g, isTemplateLiteralSupported ? "}" : '+ "');
          },
        },
      },
    ],
  },
};

你也可以将 postprocessor 选项设置为异步 function 实例。

例如:

webpack.config.js

const Handlebars = require("handlebars");

module.exports = {
  module: {
    rules: [
      {
        test: /\.hbs$/i,
        loader: "html-loader",
        options: {
          postprocessor: async (content, loaderContext) => {
            const value = await getValue();
            // When you environment supports template literals (using browserslist or options) we will generate code using them
            const isTemplateLiteralSupported = content[0] === "`";

            return content
              .replace(/<%=/g, isTemplateLiteralSupported ? `\${` : '" +')
              .replace(/%>/g, isTemplateLiteralSupported ? "}" : '+ "')
              .replace("my-value", value);
          },
        },
      },
    ],
  },
};

minimize

类型

type minimize =
  | boolean
  | {
      caseSensitive?: boolean;
      collapseWhitespace?: boolean;
      conservativeCollapse?: boolean;
      keepClosingSlash?: boolean;
      minifyCSS?: boolean;
      minifyJS?: boolean;
      removeComments?: boolean;
      removeRedundantAttributes?: boolean;
      removeScriptTypeAttributes?: boolean;
      removeStyleLinkTypeAttributes?: boolean;
    };

默认值:生产模式下为 true,否则为 false

使用此选项可以启用或自定义 html-loader 的 HTML 最小化功能。

boolean

默认启用的最小化规则如下:

({
  caseSensitive: true,
  collapseWhitespace: true,
  conservativeCollapse: true,
  keepClosingSlash: true,
  minifyCSS: true,
  minifyJS: true,
  removeComments: true,
  removeRedundantAttributes: true,
  removeScriptTypeAttributes: true,
  removeStyleLinkTypeAttributes: true,
});

webpack.config.js

module.exports = {
  module: {
    rules: [
      {
        test: /\.html$/i,
        loader: "html-loader",
        options: {
          minimize: true,
        },
      },
    ],
  },
};

object

webpack.config.js

有关可用选项的更多信息,请参阅 html-minifier-terser 的文档。

可以使用 webpack.config.js 中的以下选项覆盖默认规则:

webpack.config.js

module.exports = {
  module: {
    rules: [
      {
        test: /\.html$/i,
        loader: "html-loader",
        options: {
          minimize: {
            removeComments: false,
            collapseWhitespace: false,
          },
        },
      },
    ],
  },
};

默认规则可以扩展

webpack.config.js

const { defaultMinimizerOptions } = require("html-loader");

module.exports = {
  module: {
    rules: [
      {
        test: /\.html$/i,
        loader: "html-loader",
        options: {
          minimize: {
            ...defaultMinimizerOptions,
            removeComments: false,
            collapseWhitespace: false,
          },
        },
      },
    ],
  },
};

esModule

类型

type esModule = boolean;

默认值:true

默认情况下,html-loader 生成使用 ES 模块语法的 JS 模块。在某些情况下,使用 ES 模块是有益的,例如模块连接摇树优化

如果你想生成 CommonJS 模块(例如,module.exports =),请设置:

webpack.config.js

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

示例

使用 <!-- webpackIgnore: true --> 注释禁用 URL 解析

使用 <!-- webpackIgnore: true --> 注释可阻止 html-loader 处理下一个 HTML 标签的 URL。当你不想让 Webpack 自动处理资产导入时,这很有用。

<!-- Disabled url handling for the src attribute -->
<!-- webpackIgnore: true -->
<img src="image.png" />

<!-- Disabled url handling for the src and srcset attributes -->
<!-- webpackIgnore: true -->
<img
  srcset="image.png 480w, image.png 768w"
  src="image.png"
  alt="Elva dressed as a fairy"
/>

<!-- Disabled url handling for the content attribute -->
<!-- webpackIgnore: true -->
<meta itemprop="image" content="./image.png" />

<!-- Disabled url handling for the href attribute -->
<!-- webpackIgnore: true -->
<link rel="icon" type="image/png" sizes="192x192" href="./image.png" />

roots

使用 resolve.roots 可以指定一个目录列表,其中解析服务器相对 URL(以 '/' 开头)的请求。

webpack.config.js

module.exports = {
  context: __dirname,
  module: {
    rules: [
      {
        test: /\.html$/i,
        loader: "html-loader",
        options: {},
      },
      {
        test: /\.jpg$/,
        type: "asset/resource",
      },
    ],
  },
  resolve: {
    roots: [path.resolve(__dirname, "fixtures")],
  },
};

file.html

<img src="/image.jpg" />
// => image.jpg in __dirname/fixtures will be resolved

CDN

webpack.config.js

module.exports = {
  module: {
    rules: [
      {
        test: /\.jpg$/,
        type: "asset/resource",
      },
      {
        test: /\.png$/,
        type: "asset/inline",
      },
    ],
  },
  output: {
    publicPath: "http://cdn.example.com/[fullhash]/",
  },
};

file.html

<img src="image.jpg" data-src="image2x.png" />

index.js

require("html-loader!./file.html");

// => '<img src="http://cdn.example.com/49eba9f/a992ca.jpg" data-src="image2x.png"/>'
require('html-loader?{"sources":{"list":[{"tag":"img","attribute":"data-src","type":"src"}]}}!./file.html');

// => '<img src="image.jpg" data-src="data:image/png;base64,..." />'
require('html-loader?{"sources":{"list":[{"tag":"img","attribute":"src","type":"src"},{"tag":"img","attribute":"data-src","type":"src"}]}}!./file.html');

// => '<img src="http://cdn.example.com/49eba9f/a992ca.jpg" data-src="data:image/png;base64,..." />'

处理 scriptlink 标签

script.file.js

console.log(document);

style.file.css

a {
  color: red;
}

file.html

<!doctype html>
<html>
  <head>
    <meta charset="UTF-8" />
    <title>Title of the document</title>
    <link rel="stylesheet" type="text/css" href="./style.file.css" />
  </head>
  <body>
    Content of the document......
    <script src="./script.file.js"></script>
  </body>
</html>

webpack.config.js

module.exports = {
  module: {
    rules: [
      {
        test: /\.html$/,
        type: "asset/resource",
        generator: {
          filename: "[name][ext]",
        },
      },
      {
        test: /\.html$/i,
        use: ["html-loader"],
      },
      {
        test: /\.js$/i,
        exclude: /\.file.js$/i,
        loader: "babel-loader",
      },
      {
        test: /\.file.js$/i,
        type: "asset/resource",
      },
      {
        test: /\.css$/i,
        exclude: /\.file.css$/i,
        loader: "css-loader",
      },
      {
        test: /\.file.css$/i,
        type: "asset/resource",
      },
    ],
  },
};

模板

你可以通过利用 html-loader 中的 preprocessor 选项来使用任何模板引擎。preprocessor 函数接收文件内容和加载器上下文,允许你在 HTML 被 webpack 处理之前对其进行转换。

下面是 handlebars 的一个示例。

file.hbs

<div>
  <p>{{firstname}} {{lastname}}</p>
  <img src="image.png" alt="alt" />
<div>

webpack.config.js

const Handlebars = require("handlebars");

module.exports = {
  module: {
    rules: [
      {
        test: /\.hbs$/i,
        loader: "html-loader",
        options: {
          preprocessor: (content, loaderContext) => {
            let result;

            try {
              result = Handlebars.compile(content)({
                firstname: "Value",
                lastname: "OtherValue",
              });
            } catch (error) {
              loaderContext.emitError(error);

              return content;
            }

            return result;
          },
        },
      },
    ],
  },
};

此设置将使用 Handlebars 转换 file.hbs 模板,然后将结果传递给 html-loader

PostHTML

您可以使用 PostHTML 在 HTML 处理之前对其进行转换,而无需额外的加载器。这对于转换图像格式、添加属性或重构标记等任务非常有用。

file.html

<img src="image.jpg" />

webpack.config.js

const posthtml = require("posthtml");
const posthtmlWebp = require("posthtml-webp");

module.exports = {
  module: {
    rules: [
      {
        test: /\.hbs$/i,
        loader: "html-loader",
        options: {
          preprocessor: (content, loaderContext) => {
            let result;

            try {
              result = posthtml().use(plugin).process(content, { sync: true });
            } catch (error) {
              loaderContext.emitError(error);

              return content;
            }

            return result.html;
          },
        },
      },
    ],
  },
};

导出为 HTML 文件

一个非常常见的场景是将 HTML 导出到它们自己的 .html 文件中,以便直接提供它们而不是通过 JavaScript 注入。这可以通过 html-loaderasset modules 的组合来实现。

html-loader 将解析 URL,require 图像和您期望的一切。extract loader 会将 JavaScript 解析回正确的 HTML 文件,确保图像被正确地 require 并指向正确的路径,而 asset modules 将为您写入 .html 文件。示例

webpack.config.js

module.exports = {
  output: {
    assetModuleFilename: "[name][ext]",
  },
  module: {
    rules: [
      {
        test: /\.html$/,
        type: "asset/resource",
        generator: {
          filename: "[name][ext]",
        },
      },
      {
        test: /\.html$/i,
        use: ["html-loader"],
      },
    ],
  },
};

贡献

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

CONTRIBUTING

许可证

MIT

imports-loader

npm node tests cover discussion size

imports loader 允许您使用依赖于特定全局变量的模块。

这对于依赖于 $ 等全局变量或 this 预期为 window 对象的第三方模块特别有用。imports loader 可以添加必要的 require('whatever') 调用,以便这些模块与 webpack 一起工作。

有关兼容性问题的更多提示,请参阅 webpack 官方文档中的 Shimming

[!警告]

默认情况下,此加载器生成 ES 模块命名语法。

[!警告]

请注意,原始代码中现有的导入 (import/require) 和导入新值可能会导致失败。

入门

首先,您需要安装 imports-loader

npm install imports-loader --save-dev

yarn add -D imports-loader

pnpm add -D imports-loader

假设您有此文件

example.js

$("img").doSomeAwesomeJqueryPluginStuff();

然后,您可以通过两种方法配置 imports-loaderjquery 值注入到模块中。

内联

|%20 (空格) 允许分隔导入的 syntax, moduleName, namealias。文档和语法示例可在 此处 阅读。

[!警告]

%20 在查询字符串中代表 space,因为 URL 中不能使用空格

// Alternative syntax:
//
// import myLib from 'imports-loader?imports=default%20jquery%20$!./example.js';
//
// `%20` is space in a query string, equivalently `default jquery $`
import myLib from "imports-loader?imports=default|jquery|$!./example.js";
// Adds the following code to the beginning of example.js:
//
// import $ from "jquery";
//
// ...
// Code
// ...
import myLib from "imports-loader?imports=default|jquery|$,angular!./example.js";
// `|` is separator in a query string, equivalently `default|jquery|$` and `angular`
// Adds the following code to the beginning of example.js:
//
// import $ from "jquery";
// import angular from "angular";
//
// ...
// Code
// ...
import myLib from "imports-loader?imports=named|library|myMethod,angular!./example.js";
// `|` is separator in a query string, equivalently `named|library|myMethod` and `angular`
// Adds the following code to the beginning of example.js:
//
// import { myMethod } from "library";
// import angular from "angular";
//
// ...
// Code
// ...
const myLib = require(
  `imports-loader?type=commonjs&imports=single|jquery|$,angular!./example.js`,
);
// `|` is separator in a query string, equivalently `single|jquery|$` and `angular`
// Adds the following code to the beginning of example.js:
//
// var $ = require("jquery");
// var angular = require("angular");
//
// ...
// Code
// ...
const myLib = require(
  `imports-loader?type=commonjs&imports=single|myLib|myMethod&wrapper=window&!./example.js`,
);
// `|` is separator in a query string, equivalently `single|myLib|myMethod` and `angular`
// Adds the following code to the example.js:
//
// const myMethod = require('myLib');
//
// (function () {
// ...
// Code
// ...
// }.call(window));
import myLib from "imports-loader?additionalCode=var%20myVariable%20=%20false;!./example.js";
// Adds the following code to the beginning of example.js:
//
// var myVariable = false;
//
// ...
// Code
// ...

使用配置

webpack.config.js

module.exports = {
  module: {
    rules: [
      {
        // You can use `regexp`
        // test: /example\.js$/
        test: require.resolve("example.js"),
        use: [
          {
            loader: "imports-loader",
            options: {
              imports: [
                "default jquery $",
                "default lib_2 lib_2_default",
                "named lib_3 lib2_method_1",
                "named lib_3 lib2_method_2 lib_2_method_2_short",
                "namespace lib_4 my_namespace",
                "side-effects lib_5",
                {
                  syntax: "default",
                  moduleName: "angular",
                  name: "angular",
                },
              ],
            },
          },
        ],
      },
    ],
  },
};

生成输出

import $ from "jquery";
import lib_2_default from "lib_2";
import { lib2_method_1, lib2_method_2 as lib_2_method_2_short } from "lib_3";
import * as my_namespace from "lib_4";
import "lib_5";
import angular from "angular";

最后,使用你通常使用的方法运行 webpack(例如,通过 CLI 或 npm 脚本)。

选项

type

类型

type type = string;

默认值:module

定义生成的导出的格式。

可能的值

  • commonjs (CommonJS 模块语法)
  • module (ES 模块语法)。

commonjs

webpack.config.js

module.exports = {
  module: {
    rules: [
      {
        test: require.resolve("example.js"),
        loader: "imports-loader",
        options: {
          syntax: "default",
          type: "commonjs",
          imports: "Foo",
        },
      },
    ],
  },
};

生成输出

var Foo = require("Foo");

// ...
// Code
// ...

module

webpack.config.js

module.exports = {
  module: {
    rules: [
      {
        test: require.resolve("example.js"),
        loader: "imports-loader",
        options: {
          type: "module",
          imports: "Foo",
        },
      },
    ],
  },
};

生成输出

import Foo from "Foo";

// ...
// Code
// ...

imports

类型

type imports =
  | string
  | {
      syntax:
        | "default"
        | "named"
        | "namespace"
        | "side-effects"
        | "single"
        | "multiple"
        | "pure";
      moduleName: string;
      name: string;
      alias: string;
    }
  | Array<
      | string
      | {
          syntax:
            | "default"
            | "named"
            | "namespace"
            | "side-effects"
            | "single"
            | "multiple"
            | "pure";
          moduleName: string;
          name: string;
          alias: string;
        }
    >;

默认值:undefined

导入列表。

string

允许使用字符串描述导出。

语法

|%20 (空格) 允许分隔导入的 syntax, moduleName, namealias

字符串语法 - [[syntax] [moduleName] [name] [alias]][[syntax]|[moduleName]|[name]|[alias]],其中

  • [syntax] (可省略)

    • 如果 typemodule - 可以是 defaultnamednamespaceside-effects,默认值为 default
    • 如果 typecommonjs - 可以是 singlemultiplepure,默认值为 single
  • [moduleName] - 导入模块的名称 (必填)

  • [name] - 导入值的名称 (必填)

  • [alias] - 导入值的别名 (可省略)

示例

如果类型为 module

  • [Foo] - 生成 import Foo from "Foo";
  • [default Foo] - 生成 import Foo from "Foo";
  • [default ./my-lib Foo] - 生成 import Foo from "./my-lib";
  • [named Foo FooA] - 生成 import { FooA } from "Foo";
  • [named Foo FooA Bar] - 生成 import { FooA as Bar } from "Foo";
  • [namespace Foo FooA] - 生成 import * as FooA from "Foo";
  • [side-effects Foo] - 生成 import "Foo";

如果类型为 commonjs

  • [Foo] - 生成 const Foo = require("Foo");
  • [single Foo] - 生成 const Foo = require("Foo");
  • [single ./my-lib Foo] - 生成 const Foo = require("./my-lib");
  • [multiple Foo FooA Bar] - 生成 const { FooA: Bar } = require("Foo");
  • [pure Foo] - 生成 require("Foo");

[!警告]

您需要设置 type: "commonjs" 才能使用 singlemultiplepure 语法。

[!警告]

别名不能与 defaultnamespaceside-effectssinglepure 语法一起使用。

示例
ES 模块默认导入

webpack.config.js

module.exports = {
  module: {
    rules: [
      {
        test: require.resolve("./path/to/example.js"),
        loader: "imports-loader",
        options: {
          imports: "default lib myName",
        },
      },
    ],
  },
};

生成输出

import myName from "lib";

// ...
// Code
// ...
CommonJS 单一导入

webpack.config.js

module.exports = {
  module: {
    rules: [
      {
        test: require.resolve("./path/to/example.js"),
        loader: "imports-loader",
        options: {
          type: "commonjs",
          imports: "single lib myName",
        },
      },
    ],
  },
};

生成输出

var myName = require("lib");

// ...
// Code
// ...

object

允许使用对象描述导入。

属性

  • 语法:

    • 如果 typemodule - 可以是 defaultnamednamespaceside-effects
    • 如果 typecommonjs - 可以是 singlemultiplepure
  • moduleName - 导入模块的名称 (必填)

  • name - 导入值的名称 (必填)

  • alias - 导入值的别名 (可省略)

[!警告]

别名不能与 defaultnamespaceside-effectssinglepure 语法一起使用。

示例

webpack.config.js

module.exports = {
  module: {
    rules: [
      {
        test: require.resolve("example.js"),
        use: [
          {
            loader: "imports-loader",
            options: {
              imports: {
                syntax: "named",
                moduleName: "lib_2",
                name: "lib2_method_2",
                alias: "lib_2_method_2_alias",
              },
            },
          },
        ],
      },
    ],
  },
};

生成输出

import { lib2_method_2 as lib_2_method_2_alias } from "lib_2";

// ...
// Code
// ...

array

允许指定多个导入。每个项可以是 stringobject

示例

webpack.config.js

module.exports = {
  module: {
    rules: [
      {
        test: require.resolve("example.js"),
        use: [
          {
            loader: "imports-loader",
            options: {
              imports: [
                {
                  moduleName: "angular",
                },
                {
                  syntax: "default",
                  moduleName: "jquery",
                  name: "$",
                },
                "default lib_2 lib_2_default",
                "named lib_2 lib2_method_1",
                "named lib_2 lib2_method_2 lib_2_method_2_alias",
                "namespace lib_3 lib_3_all",
                "side-effects lib_4",
              ],
            },
          },
        ],
      },
    ],
  },
};

生成输出

import angular from "angular";
import $ from "jquery";
import lib_2_default from "lib_2";
import { lib2_method_1, lib2_method_2 as lib_2_method_2_alias } from "lib_2";
import * as lib_3_all from "lib_3";
import "lib_4";

// ...
// Code
// ...

wrapper

类型

type wrapper =
  | boolean
  | string
  | {
      thisArg: string;
      args: Record<string, string> | Array<string>;
    };

默认值:undefined

使用给定的 thisArgargs 将模块代码封装在一个函数中 ((function () { ... }).call();)。

[!警告]

如果源代码包含 ES 模块导入,请勿使用此选项。它适用于传统或不兼容 ESM 的代码。

boolean

将代码封装在具有默认上下文的 IIFE(立即调用函数表达式)中。

webpack.config.js

module.exports = {
  module: {
    rules: [
      {
        test: require.resolve("example.js"),
        use: [
          {
            loader: "imports-loader",
            options: {
              imports: {
                moduleName: "jquery",
                name: "$",
              },
              wrapper: true,
            },
          },
        ],
      },
    ],
  },
};

生成输出

import $ from "jquery";

(function () {
  // ...
  // Code
  // ...
}).call();

string

将自定义 thisArg 传递给 .call() 上下文。

webpack.config.js

module.exports = {
  module: {
    rules: [
      {
        test: require.resolve("example.js"),
        use: [
          {
            loader: "imports-loader",
            options: {
              imports: {
                moduleName: "jquery",
                name: "$",
              },
              wrapper: "window",
            },
          },
        ],
      },
    ],
  },
};

生成输出

import $ from "jquery";

(function () {
  // ...
  // Code
  // ...
}).call(window);

object

允许高级控制:指定 this 上下文和传递给 IIFE 的自定义参数

webpack.config.js

module.exports = {
  module: {
    rules: [
      {
        test: require.resolve("example.js"),
        use: [
          {
            loader: "imports-loader",
            options: {
              imports: {
                moduleName: "jquery",
                name: "$",
              },
              wrapper: {
                thisArg: "window",
                args: ["myVariable", "myOtherVariable"],
              },
            },
          },
        ],
      },
    ],
  },
};

生成输出

import $ from "jquery";

(function (myVariable, myOtherVariable) {
  // ...
  // Code
  // ...
}).call(window, myVariable, myOtherVariable);

具有不同参数名称的 object

允许使用键值对象重新映射函数签名中的参数名称。

webpack.config.js

module.exports = {
  module: {
    rules: [
      {
        test: require.resolve("example.js"),
        use: [
          {
            loader: "imports-loader",
            options: {
              imports: {
                moduleName: "jquery",
                name: "$",
              },
              wrapper: {
                thisArg: "window",
                args: {
                  myVariable: "var1",
                  myOtherVariable: "var2",
                },
              },
            },
          },
        ],
      },
    ],
  },
};

生成输出

import $ from "jquery";

(function (var1, var2) {
  // ...
  // Code
  // ...
}).call(window, myVariable, myOtherVariable);

additionalCode

类型

type additionalCode = string;

默认值:undefined

在模块代码之前添加自定义代码作为前导。

示例
定义自定义变量

webpack.config.js

module.exports = {
  module: {
    rules: [
      {
        test: require.resolve("example.js"),
        use: [
          {
            loader: "imports-loader",
            options: {
              imports: {
                moduleName: "jquery",
                name: "$",
              },
              additionalCode: "var myVariable = false;",
            },
          },
        ],
      },
    ],
  },
};

生成输出

import $ from "jquery";

var myVariable = false;

// ...
// Code
// ...
禁用 AMD 导入语法

webpack.config.js

module.exports = {
  module: {
    rules: [
      {
        test: require.resolve("example.js"),
        use: [
          {
            loader: "imports-loader",
            options: {
              imports: {
                moduleName: "jquery",
                name: "$",
              },
              additionalCode:
                "var define = false; /* Disable AMD for misbehaving libraries */",
            },
          },
        ],
      },
    ],
  },
};

生成输出

import $ from "jquery";

var define = false; /* Disable AMD for misbehaving libraries */

// ...
// Code
// ...

贡献

我们欢迎贡献!如果您有兴趣帮助改进此加载器,请花一点时间阅读我们的贡献指南。

CONTRIBUTING

许可证

MIT

less-loader

npm node tests cover discussion size

用于 webpack 的 Less 加载器,将 Less 文件编译为 CSS。

入门

首先,您需要安装 lessless-loader

npm install less less-loader --save-dev

yarn add -D less less-loader

pnpm add -D less less-loader

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

webpack.config.js

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

最后,使用你通常使用的方法运行 webpack(例如,通过 CLI 或 npm 脚本)。

选项

lessOptions

类型

type lessOptions = import('less').options | ((loaderContext: LoaderContext) => import('less').options})

默认值:{ relativeUrls: true }

您可以通过 加载器选项 中的 lessOptions 属性,将任何 Less 特定的选项传递给 less-loader。有关所有可用选项(短横线命名法),请参阅 Less 文档

由于我们将这些选项以编程方式传递给 Less,因此您需要在此处以驼峰命名法传递它们

object

使用对象将选项直接传递给 Less。

webpack.config.js

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

function

允许根据加载器上下文动态设置 Less 选项。

module.exports = {
  module: {
    rules: [
      {
        test: /\.less$/i,
        use: [
          "style-loader",
          "css-loader",
          {
            loader: "less-loader",
            options: {
              lessOptions: (loaderContext) => {
                // More information about available properties https://webpack.js.cn/api/loaders/
                const { resourcePath, rootContext } = loaderContext;
                const relativePath = path.relative(rootContext, resourcePath);

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

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

additionalData

类型

type additionalData =
  | string
  | ((content: string, loaderContext: LoaderContext) => string);

默认值:undefined

在实际入口文件前或后添加 Less 代码。在这种情况下,less-loader 不会覆盖源文件,而只会预置入口文件的内容。

当您的一些 Less 变量依赖于环境时,这尤其有用。

由于您正在注入代码,这将破坏入口文件中的源映射。通常,有比这更简单的解决方案,例如使用多个 Less 入口文件。

string

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

function

Sync
module.exports = {
  module: {
    rules: [
      {
        test: /\.less$/i,
        use: [
          "style-loader",
          "css-loader",
          {
            loader: "less-loader",
            options: {
              additionalData: (content, loaderContext) => {
                // More information about available properties https://webpack.js.cn/api/loaders/
                const { resourcePath, rootContext } = loaderContext;
                const relativePath = path.relative(rootContext, resourcePath);

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

                return "@value: 200px;" + content;
              },
            },
          },
        ],
      },
    ],
  },
};
Async
module.exports = {
  module: {
    rules: [
      {
        test: /\.less$/i,
        use: [
          "style-loader",
          "css-loader",
          {
            loader: "less-loader",
            options: {
              additionalData: async (content, loaderContext) => {
                // More information about available properties https://webpack.js.cn/api/loaders/
                const { resourcePath, rootContext } = loaderContext;
                const relativePath = path.relative(rootContext, resourcePath);

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

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

sourceMap

类型

type sourceMap = boolean;

默认值:取决于 compiler.devtool 的值

默认情况下,源映射的生成取决于 devtool 选项。除了 evalfalse 值之外,所有值都启用源映射生成。

webpack.config.js

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

webpackImporter

类型

type webpackImporter = boolean | "only";

默认值:true

启用或禁用默认的 webpack 导入器。

这在某些情况下可以提高性能。请谨慎使用,因为别名和从 node_modules 导入的 @import 将不起作用。

webpack.config.js

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

implementation

类型

type implementation = object | string;

less-loader 兼容 Less 3 和 4 版本

特殊的 implementation 选项决定使用哪个 Less 实现。它会覆盖本地安装的 lesspeerDependency 版本。

此选项仅对下游工具的作者真正有用,以简化 Less 3 到 4 的过渡。

object

使用 Less 实例的示例

webpack.config.js

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

string

使用已解析 Less 模块路径的示例

webpack.config.js

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

lessLogAsWarnOrErr

类型

type lessLogAsWarnOrErr = boolean;

默认值:false

Less 警告和错误将被视为 webpack 警告和错误,而不是静默记录。

warning.less

div {
  &:extend(.body1);
}

如果 lessLogAsWarnOrErr 设置为 false,它将只是一个日志,webpack 将成功编译,但如果您将此选项设置为 true,webpack 将在出现警告(或错误)时编译失败,并且如果相应配置,可能会中断构建。

webpack.config.js

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

示例

正常用法

less-loadercss-loaderstyle-loader 链接起来,立即将所有样式应用于 DOM。

webpack.config.js

module.exports = {
  module: {
    rules: [
      {
        test: /\.less$/i,
        use: [
          {
            loader: "style-loader", // Creates style nodes from JS strings
          },
          {
            loader: "css-loader", // Translates CSS into CommonJS
          },
          {
            loader: "less-loader", // Compiles Less to CSS
          },
        ],
      },
    ],
  },
};

不幸的是,Less 并不是将所有选项都一对一地映射到驼峰命名法。如有疑问,请检查其可执行文件并搜索短横线命名法的选项。

源映射

要为 CSS 启用源映射,您需要在加载器选项中传递 sourceMap 属性。如果未传递此属性,加载器将遵循 devtool 中设置的 webpack 源映射设置。

webpack.config.js

module.exports = {
  devtool: "source-map", // any "source-map"-like devtool is possible
  module: {
    rules: [
      {
        test: /\.less$/i,
        use: [
          "style-loader",
          {
            loader: "css-loader",
            options: {
              sourceMap: true,
            },
          },
          {
            loader: "less-loader",
            options: {
              sourceMap: true,
            },
          },
        ],
      },
    ],
  },
};

如果您想在 Chrome 中编辑原始 Less 文件,这里有一篇不错的博客文章。该博客文章是关于 Sass 的,但它也适用于 Less。

生产环境

通常,建议在生产环境中使用 MiniCssExtractPlugin 将样式表提取到专用文件中。这样,您的样式就不依赖于 JavaScript,从而提高了性能和可缓存性。

导入

首先,我们尝试使用内置的 less 解析逻辑,然后是 webpack 解析逻辑。

Webpack 解析器

webpack 提供了 高级文件解析机制。如果 less 无法解析 @importless-loader 会应用一个 Less 插件,将所有查询传递给 webpack 解析器。因此,您可以从 node_modules 导入 Less 模块。

@import "bootstrap/less/bootstrap";

使用 ~ 前缀(例如,@import "~bootstrap/less/bootstrap";)已弃用,可以从您的代码中移除(我们建议这样做),但出于历史原因,我们仍然支持它。为什么可以移除它?加载器将首先尝试将 @import 解析为相对路径,如果无法解析,加载器将尝试在 node_modules 中解析 @import

默认解析器选项可以通过 resolve.byDependency 修改。

webpack.config.js

module.exports = {
  devtool: "source-map", // any "source-map"-like devtool is possible
  module: {
    rules: [
      {
        test: /\.less$/i,
        use: ["style-loader", "css-loader", "less-loader"],
      },
    ],
  },
  resolve: {
    byDependency: {
      // More options can be found here https://webpack.js.cn/configuration/resolve/
      less: {
        mainFiles: ["custom"],
      },
    },
  },
};

Less 解析器

如果您指定 paths 选项,模块将在给定的 paths 中搜索。这是 less 的默认行为。paths 应该是一个包含绝对路径的数组

webpack.config.js

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

插件

要使用 Less 插件,只需像这样设置 plugins 选项即可

webpack.config.js

const CleanCSSPlugin = require('less-plugin-clean-css');

module.exports = {
  ...
    {
      loader: 'less-loader',
      options: {
        lessOptions: {
          plugins: [
            new CleanCSSPlugin({ advanced: true }),
          ],
        },
      },
    },
  ...
};

[!注意]

在自定义插件内部访问 加载器上下文 可以通过 pluginManager.webpackLoaderContext 属性完成。

module.exports = {
  install: function (less, pluginManager, functions) {
    functions.add("pi", function () {
      // Loader context is available in `pluginManager.webpackLoaderContext`

      return Math.PI;
    });
  },
};

提取样式表

将 CSS 与 webpack 捆绑有一些优点,例如使用哈希 URL 引用图像和字体,或在开发中使用 热模块替换 (HMR)

另一方面,在生产环境中,根据 JS 执行应用样式表并不是一个好主意。渲染可能会延迟,甚至可能会出现 FOUC(无样式内容的闪烁)。因此,将它们作为单独的文件放入最终生产构建中通常仍然更好。

有两种方法可以从捆绑包中提取样式表

CSS 模块陷阱

在使用 Less 与 CSS 模块 时,关于 url(...) 语句中的相对文件路径存在一个已知问题。请参阅此问题以获取解释

贡献

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

CONTRIBUTING

许可证

MIT

node-loader

npm node tests coverage discussion size

node-loader

一个 Node.js 插件 加载器。

允许连接带有 .node 扩展名的原生 Node 模块。

node-loader 仅适用于 node/async-node/electron-main/electron-renderer/electron-preload 目标。

入门

首先,您需要安装 node-loader

npm install node-loader --save-dev

yarn add -D node-loader

pnpm add -D node-loader

target 选项设置为 node/async-node/electron-main/electron-renderer/electron-preload 值,并且不要模拟 __dirname 全局变量。

webpack.config.js

module.exports = {
  resolve: {
    extensions: ["...", ".node"],
  },
  target: "node",
  node: {
    __dirname: false,
  },
  module: {
    rules: [
      {
        test: /\.node$/,
        loader: "node-loader",
      },
    ],
  },
};

内联

index.js

import node from "node-loader!./file.node";

并通过您喜欢的方法运行 webpack

配置

index.js

import node from "file.node";

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

webpack.config.js

module.exports = {
  target: "node",
  node: {
    __dirname: false,
  },
  module: {
    rules: [
      {
        test: /\.node$/,
        loader: "node-loader",
      },
    ],
  },
};

并通过您喜欢的方法运行 webpack

选项

名称类型默认值描述
标志{Number}undefined启用/禁用 url/image-set 函数处理
name{String|Function}'[contenthash].[ext]'为目标文件指定自定义文件名模板。

flags

类型:Number 默认值:undefined

flags 参数是一个整数,允许指定 dlopen 行为。有关详细信息,请参阅 process.dlopen 文档。

index.js

import node from "file.node";

webpack.config.js

const os = require("os");

module.exports = {
  target: "node",
  node: {
    __dirname: false,
  },
  module: {
    rules: [
      {
        test: /\.node$/,
        loader: "node-loader",
        options: {
          flags: os.constants.dlopen.RTLD_NOW,
        },
      },
    ],
  },
};

name

类型:String|Function 默认值:'[contenthash].[ext]'

为目标文件指定自定义文件名模板。

String

webpack.config.js

module.exports = {
  target: "node",
  node: {
    __dirname: false,
  },
  module: {
    rules: [
      {
        test: /\.node$/,
        loader: "node-loader",
        options: {
          name: "[path][name].[ext]",
        },
      },
    ],
  },
};

Function

webpack.config.js

module.exports = {
  target: "node",
  node: {
    __dirname: false,
  },
  module: {
    rules: [
      {
        test: /\.node$/,
        loader: "node-loader",
        options: {
          name(resourcePath, resourceQuery) {
            // `resourcePath` - `/absolute/path/to/file.js`
            // `resourceQuery` - `?foo=bar`

            if (process.env.NODE_ENV === "development") {
              return "[path][name].[ext]";
            }

            return "[contenthash].[ext]";
          },
        },
      },
    ],
  },
};

贡献

如果你尚未阅读,请花一点时间阅读我们的贡献指南。

CONTRIBUTING

许可证

MIT

postcss-loader

npm node tests coverage size

Webpack 讨论:discussion

PostCSS 聊天:chat-postcss

一个使用 PostCSS 处理 CSS 的加载器。

入门

您需要 webpack v5 才能使用最新版本。对于 Webpack v4,您必须安装 postcss-loader v4。

首先,您需要安装 postcss-loaderpostcss

npm install --save-dev postcss-loader postcss

yarn add -D postcss-loader postcss

pnpm add -D postcss-loader postcss

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

在以下配置中,使用了插件 postcss-preset-env,此插件默认未安装。

file.js

import css from "file.css";

webpack.config.js

module.exports = {
  module: {
    rules: [
      {
        test: /\.css$/i,
        use: [
          "style-loader",
          "css-loader",
          {
            loader: "postcss-loader",
            options: {
              postcssOptions: {
                plugins: [
                  [
                    "postcss-preset-env",
                    {
                      // Options
                    },
                  ],
                ],
              },
            },
          },
        ],
      },
    ],
  },
};

配置文件 替代用法

postcss.config.js

module.exports = {
  plugins: [
    [
      "postcss-preset-env",
      {
        // Options
      },
    ],
  ],
};

加载器会自动搜索配置文件。

webpack.config.js

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

最后,使用你通常使用的方法运行 webpack(例如,通过 CLI 或 npm 脚本)。

选项

execute

类型

type execute = boolean;

默认值:undefined

启用 PostCSS 解析器对 CSS-in-JS 的支持。如果您使用 JS 样式,请添加 execute 选项,使用 postcss-js 解析器。

webpack.config.js

module.exports = {
  module: {
    rules: [
      {
        test: /\.style.js$/,
        use: [
          "style-loader",
          {
            loader: "css-loader",
          },
          {
            loader: "postcss-loader",
            options: {
              postcssOptions: {
                parser: "postcss-js",
              },
              execute: true,
            },
          },
        ],
      },
    ],
  },
};

postcssOptions

请参阅文件 https://github.com/webpack-contrib/postcss-loader/blob/master/src/config.d.ts

类型

import type { Config as PostCSSConfig } from "postcss-load-config";
import type { LoaderContext } from "webpack";

type PostCSSLoaderContext = LoaderContext<PostCSSConfig>;

interface PostCSSLoaderAPI {
  mode: PostCSSLoaderContext["mode"];
  file: PostCSSLoaderContext["resourcePath"];
  webpackLoaderContext: PostCSSLoaderContext;
  env: PostCSSLoaderContext["mode"];
  options: PostCSSConfig;
}

export type PostCSSLoaderOptions =
  | PostCSSConfig
  | ((api: PostCSSLoaderAPI) => PostCSSConfig);

默认值:undefined

允许您设置 PostCSS options 和插件。

支持所有 PostCSS 选项。配置文件有一个特殊的 config 选项。它的工作原理和配置方式如下所述。

我们建议不要指定 fromtomap 选项,因为这可能导致源映射中的路径错误。如果需要源映射,请改用 sourcemap 选项。

对于大型项目,为了优化加载器的性能,最好在加载器配置中提供 postcssOptions 并指定 config: false。这种方法消除了在编译期间多次查找和加载外部配置文件的需要。

object

设置 plugins

webpack.config.js (推荐)

const myOtherPostcssPlugin = require("postcss-my-plugin");

module.exports = {
  module: {
    rules: [
      {
        test: /\.sss$/i,
        loader: "postcss-loader",
        options: {
          postcssOptions: {
            plugins: [
              "postcss-import",
              ["postcss-short", { prefix: "x" }],
              require.resolve("my-postcss-plugin"),
              myOtherPostcssPlugin({ myOption: true }),
              // Deprecated and will be removed in the next major release
              { "postcss-nested": { preserveEmpty: true } },
            ],
          },
        },
      },
    ],
  },
};

webpack.config.js (已弃用,将在下一个主要版本中移除)

module.exports = {
  module: {
    rules: [
      {
        test: /\.sss$/i,
        loader: "postcss-loader",
        options: {
          postcssOptions: {
            plugins: {
              "postcss-import": {},
              "postcss-short": { prefix: "x" },
            },
          },
        },
      },
    ],
  },
};

设置 syntax

webpack.config.js

module.exports = {
  module: {
    rules: [
      {
        test: /\.sss$/i,
        loader: "postcss-loader",
        options: {
          postcssOptions: {
            // Can be `string`
            syntax: "sugarss",
            // Can be `object`
            syntax: require("sugarss"),
          },
        },
      },
    ],
  },
};

设置 parser

webpack.config.js

module.exports = {
  module: {
    rules: [
      {
        test: /\.sss$/i,
        loader: "postcss-loader",
        options: {
          postcssOptions: {
            // Can be `string`
            parser: "sugarss",
            // Can be `object`
            parser: require("sugarss"),
            // Can be `function`
            parser: require("sugarss").parse,
          },
        },
      },
    ],
  },
};

设置 stringifier

webpack.config.js

const Midas = require("midas");
const midas = new Midas();

module.exports = {
  module: {
    rules: [
      {
        test: /\.sss$/i,
        loader: "postcss-loader",
        options: {
          postcssOptions: {
            // Can be `string`
            stringifier: "sugarss",
            // Can be `object`
            stringifier: require("sugarss"),
            // Can be `function`
            stringifier: midas.stringifier,
          },
        },
      },
    ],
  },
};

function

webpack.config.js

module.exports = {
  module: {
    rules: [
      {
        test: /\.(css|sss)$/i,
        loader: "postcss-loader",
        options: {
          postcssOptions: (loaderContext) => {
            if (/\.sss$/.test(loaderContext.resourcePath)) {
              return {
                parser: "sugarss",
                plugins: [
                  ["postcss-short", { prefix: "x" }],
                  "postcss-preset-env",
                ],
              };
            }

            return {
              plugins: [
                ["postcss-short", { prefix: "x" }],
                "postcss-preset-env",
              ],
            };
          },
        },
      },
    ],
  },
};

config

类型

type config = boolean | string;

默认值:true

允许您使用配置文件设置选项。配置文件中指定的选项与传递给加载器的选项结合使用,加载器选项会覆盖配置文件中的选项。

配置文件

加载器将在目录树中向上搜索以下位置的配置

  • package.json 中的 postcss 属性
  • JSON 或 YAML 格式的 .postcssrc 文件
  • .postcssrc.json.postcssrc.yaml.postcssrc.yml.postcssrc.js.postcssrc.cjs 文件
  • 导出对象的 postcss.config.jspostcss.config.cjs CommonJS 模块 (推荐)
配置文件示例

使用 object 符号

postcss.config.js (推荐)

module.exports = {
  // You can specify any options from https://postcss.org/api/#processoptions here
  // parser: 'sugarss',
  plugins: [
    // Plugins for PostCSS
    ["postcss-short", { prefix: "x" }],
    "postcss-preset-env",
  ],
};

使用 function 符号

postcss.config.js (推荐)

module.exports = (api) => {
  // `api.file` - path to the file
  // `api.mode` - `mode` value of webpack, please read https://webpack.js.cn/configuration/mode/
  // `api.webpackLoaderContext` - loader context for complex use cases
  // `api.env` - alias `api.mode` for compatibility with `postcss-cli`
  // `api.options` - the `postcssOptions` options

  if (/\.sss$/.test(api.file)) {
    return {
      // You can specify any options from https://postcss.org/api/#processoptions here
      parser: "sugarss",
      plugins: [
        // Plugins for PostCSS
        ["postcss-short", { prefix: "x" }],
        "postcss-preset-env",
      ],
    };
  }

  return {
    // You can specify any options from https://postcss.org/api/#processoptions here
    plugins: [
      // Plugins for PostCSS
      ["postcss-short", { prefix: "x" }],
      "postcss-preset-env",
    ],
  };
};

postcss.config.js (已弃用,将在下一个主要版本中移除)

module.exports = {
  // You can specify any options from https://postcss.org/api/#processoptions here
  // parser: 'sugarss',
  plugins: {
    // Plugins for PostCSS
    "postcss-short": { prefix: "x" },
    "postcss-preset-env": {},
  },
};
配置级联

您可以在不同的目录中使用不同的 postcss.config.js 文件。配置查找从 path.dirname(file) 开始,并向上遍历文件树,直到找到配置文件。

|– components
| |– component
| | |– index.js
| | |– index.png
| | |– style.css (1)
| | |– postcss.config.js (1)
| |– component
| | |– index.js
| | |– image.png
| | |– style.css (2)
|
|– postcss.config.js (1 && 2 (recommended))
|– webpack.config.js
|
|– package.json

设置 postcss.config.js 后,将 postcss-loader 添加到您的 webpack.config.js 中。您可以单独使用它,也可以与 css-loader 结合使用(推荐)。

css-loaderstyle-loader 之前,但如果在其他预处理器加载器(如 sass|less|stylus-loader之后使用 postcss-loader(因为 webpack 加载器从右到左/从下到上评估)。

webpack.config.js (推荐)

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

boolean

启用/禁用自动加载配置。

webpack.config.js

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

字符串

允许指定配置文件的路径。

webpack.config.js

const path = require("path");

module.exports = {
  module: {
    rules: [
      {
        test: /\.css$/i,
        loader: "postcss-loader",
        options: {
          postcssOptions: {
            config: path.resolve(__dirname, "custom.config.js"),
          },
        },
      },
    ],
  },
};

sourceMap

类型

type sourceMap = boolean;

默认值:取决于 compiler.devtool 的值

默认情况下,源映射的生成取决于 devtool 选项。除了 evalfalse 值之外,所有值都启用源映射生成。

webpack.config.js

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

替代设置

webpack.config.js

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

implementation

类型

type implementation = object;

implementation 的类型应与 postcss.d.ts 相同

默认值:postcss

特殊的 implementation 选项决定使用哪个 PostCSS 实现。它会覆盖本地安装的 postcsspeerDependency 版本。

此选项仅对下游工具的作者真正有用,以简化 PostCSS 7 到 8 的过渡。

function

webpack.config.js

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

字符串

webpack.config.js

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

示例

SugarSS

SugarSS 是一种基于空白的 PostCSS 语法。

您需要安装 sugarss

npm install --save-dev sugarss

使用 SugarSS 语法。

webpack.config.js

module.exports = {
  module: {
    rules: [
      {
        test: /\.sss$/i,
        use: [
          "style-loader",
          {
            loader: "css-loader",
            options: { importLoaders: 1 },
          },
          {
            loader: "postcss-loader",
            options: {
              postcssOptions: {
                parser: "sugarss",
              },
            },
          },
        ],
      },
    ],
  },
};

Autoprefixer

您需要安装 autoprefixer

npm install --save-dev autoprefixer

使用 autoprefixer 自动为 CSS 规则添加供应商前缀。

webpack.config.js

module.exports = {
  module: {
    rules: [
      {
        test: /\.css$/i,
        use: [
          "style-loader",
          {
            loader: "css-loader",
            options: { importLoaders: 1 },
          },
          {
            loader: "postcss-loader",
            options: {
              postcssOptions: {
                plugins: [
                  [
                    "autoprefixer",
                    {
                      // Autoprefixer options (optional)
                    },
                  ],
                ],
              },
            },
          },
        ],
      },
    ],
  },
};

[!警告]

postcss-preset-env 包含了 autoprefixer,因此如果您已经使用预设,则无需单独添加。更多信息

PostCSS Preset Env

您需要安装 postcss-preset-env

npm install --save-dev postcss-preset-env

webpack.config.js

module.exports = {
  module: {
    rules: [
      {
        test: /\.css$/i,
        use: [
          "style-loader",
          {
            loader: "css-loader",
            options: { importLoaders: 1 },
          },
          {
            loader: "postcss-loader",
            options: {
              postcssOptions: {
                plugins: [
                  [
                    "postcss-preset-env",
                    {
                      // Options
                    },
                  ],
                ],
              },
            },
          },
        ],
      },
    ],
  },
};

CSS 模块

什么是 CSS 模块?请在此处阅读

postcss-loader 方面无需额外选项即可支持 CSS 模块。要使其正常工作,请添加 css-loaderimportLoaders 选项。

webpack.config.js

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

CSS-in-JS 和 postcss-js

要处理用 JavaScript 编写的样式,您可以使用 postcss-js 作为解析器。

您需要安装 postcss-js

npm install --save-dev postcss-js

如果您想处理用 JavaScript 编写的样式,请使用 postcss-js 解析器。

webpack.config.js

module.exports = {
  module: {
    rules: [
      {
        test: /\.style.js$/,
        use: [
          "style-loader",
          {
            loader: "css-loader",
            options: {
              importLoaders: 2,
            },
          },
          {
            loader: "postcss-loader",
            options: {
              postcssOptions: {
                parser: "postcss-js",
              },
              execute: true,
            },
          },
          "babel-loader",
        ],
      },
    ],
  },
};

结果是您将能够以以下方式编写样式

import colors from "./styles/colors";

export default {
  ".menu": {
    color: colors.main,
    height: 25,
    "&_link": {
      color: "white",
    },
  },
};

[!警告]

如果您正在使用 Babel,则需要执行以下操作才能使设置生效

  1. babel-plugin-add-module-exports 添加到您的配置中。
  2. 每个样式模块只能有一个默认导出。

提取 CSS

要将 CSS 提取到单独的文件中,请使用 mini-css-extract-plugin

webpack.config.js

const isProductionMode = process.env.NODE_ENV === "production";

const MiniCssExtractPlugin = require("mini-css-extract-plugin");

module.exports = {
  mode: isProductionMode ? "production" : "development",
  module: {
    rules: [
      {
        test: /\.css$/,
        use: [
          isProductionMode ? MiniCssExtractPlugin.loader : "style-loader",
          "css-loader",
          "postcss-loader",
        ],
      },
    ],
  },
  plugins: [
    new MiniCssExtractPlugin({
      filename: isProductionMode ? "[name].[contenthash].css" : "[name].css",
    }),
  ],
};

💡 使用此设置可以在生产环境中提取和缓存 CSS,同时在开发过程中保持快速样式注入。

发出资产

要从 PostCSS 插件向 webpack 发出资产,需要在 result.messages 中添加一条消息。

消息应包含以下字段

  • type = asset - 消息类型(必需,应等于 asset
  • file - 文件名(必需)
  • content - 文件内容(必需)
  • sourceMap - sourceMap
  • info - 资产信息

webpack.config.js

const postcssCustomPlugin = (opts = {}) => {
  return {
    postcssPlugin: "postcss-custom-plugin",
    Once: (root, { result }) => {
      result.messages.push({
        type: "asset",
        file: "sprite.svg",
        content: "<svg>...</svg>",
      });
    },
  };
};

module.exports = {
  module: {
    rules: [
      {
        test: /\.css$/i,
        use: [
          "style-loader",
          "css-loader",
          {
            loader: "postcss-loader",
            options: {
              postcssOptions: {
                plugins: [postcssCustomPlugin()],
              },
            },
          },
        ],
      },
    ],
  },
};

ℹ️ 这允许您的插件生成额外的文件作为构建过程的一部分,并且 Webpack 会像处理任何其他发出的资产一样处理它们。

添加依赖项、上下文依赖项、构建依赖项、缺失依赖项

依赖项对于 webpack 理解何时需要对更改的文件进行重新编译是必要的。

有两种方法可以添加依赖项

  1. (推荐)。插件可以在 result.messages 中发出消息。

消息应包含以下字段

  • type = dependency - 消息类型(必需,应等于 dependencycontext-dependencybuild-dependencymissing-dependency
  • file - 绝对文件路径(必需)

webpack.config.js

const path = require("path");

const postcssCustomPlugin = (opts = {}) => {
  return {
    postcssPlugin: "postcss-custom-plugin",
    Once: (root, { result }) => {
      result.messages.push({
        type: "dependency",
        file: path.resolve(__dirname, "path", "to", "file"),
      });
    },
  };
};

module.exports = {
  module: {
    rules: [
      {
        test: /\.css$/i,
        use: [
          "style-loader",
          "css-loader",
          {
            loader: "postcss-loader",
            options: {
              postcssOptions: {
                plugins: [postcssCustomPlugin()],
              },
            },
          },
        ],
      },
    ],
  },
};

💡 您可以使用现成的插件 postcss-add-dependencies 来简化此过程。

  1. 在插件中传递 loaderContext(用于高级设置)。

webpack.config.js

const path = require("path");

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

⚠️ 仅当通过自定义 PostCSS 配置和动态导入或外部文件管理依赖项时才使用此方法。

postcss.config.js

通过 PostCSS api 对象传递 webpackLoaderContext

module.exports = (api) => ({
  plugins: [
    require("path/to/postcssCustomPlugin.js")({
      loaderContext: api.webpackLoaderContext,
    }),
  ],
});

postcssCustomPlugin.js

使用 loaderContext.addDependency 注册文件依赖项

const path = require("path");

const postcssCustomPlugin = (opts = {}) => {
  return {
    postcssPlugin: "postcss-custom-plugin",
    Once: (root, { result }) => {
      opts.loaderContext.addDependency(
        path.resolve(__dirname, "path", "to", "file"),
      );
    },
  };
};

postcssCustomPlugin.postcss = true;
module.exports = postcssCustomPlugin;

✅ 当您想要动态声明依赖项而无需依赖 result.messages 时,此方法是理想的选择,尤其是在更复杂的设置或共享插件配置中。

贡献

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

CONTRIBUTING

许可证

MIT

remark-loader

npm node tests cover discussion size

通过 remark 加载 markdown。

用法

只需将加载器添加到您的配置中,并传递选项。

import md from "markdown-file.md";

console.log(md);

webpack.config.js

import RemarkHTML from "remark-html";

module.exports = {
  // ...
  module: {
    rules: [
      {
        test: /\.md$/,
        use: [
          {
            loader: "html-loader",
          },
          {
            loader: "remark-loader",
            options: {
              remarkOptions: {
                plugins: [RemarkHTML],
              },
            },
          },
        ],
      },
    ],
  },
};

这是 remark 插件 的完整列表。

我们不再支持任何 react 特定的功能。如果您有兴趣将 JSX 与 Markdown 混合使用,请参阅出色的 MDX 项目。

选项

remarkOptions

Remark 选项

类型

type remarkOptions = {
  plugins: Array<string | Array>;
  settings: Object;
  data: Object;
};

插件

允许连接 remark 插件

类型

type plugins = Array<string | Array>;

默认值:[]

允许连接 remark 插件

字符串

webpack.config.js

import RemarkFrontmatter from "remark-frontmatter";

module.exports = {
  // ...
  module: {
    rules: [
      {
        test: /\.md$/,
        use: [
          {
            loader: "remark-loader",
            options: {
              remarkOptions: {
                plugins: [RemarkFrontmatter],
              },
            },
          },
        ],
      },
    ],
  },
};
数组

如果需要为插件指定选项,可以使用数组传递插件,其中第二个参数将是 options

webpack.config.js

import RemarkFrontmatter from "remark-frontmatter";
import RemarkBookmarks from "remark-bookmarks";

module.exports = {
  // ...
  module: {
    rules: [
      {
        test: /\.md$/,
        use: [
          {
            loader: "remark-loader",
            options: {
              remarkOptions: {
                plugins: [
                  RemarkFrontmatter,
                  [
                    RemarkBookmarks,
                    {
                      bookmarks: {
                        npm: "https://npmjs.net.cn/package/remark-bookmarks",
                      },
                    },
                  ],
                ],
              },
            },
          },
        ],
      },
    ],
  },
};

设置

Remark 设置

类型

type settings = Object;

默认值:undefined

remark-stringify 选项remark-parse 选项 传递给 remark

webpack.config.js

module.exports = {
  // ...
  module: {
    rules: [
      {
        test: /\.md$/,
        use: [
          {
            loader: "remark-loader",
            options: {
              remarkOptions: {
                settings: {
                  bullet: "+",
                  listItemIndent: "1",
                },
              },
            },
          },
        ],
      },
    ],
  },
};

数据

所有插件可用的信息

类型

type data = Object;

默认值:undefined

使用所有插件可用的信息配置 remark。此信息存储在内存中的键值存储中。

webpack.config.js

function examplePluginUsingData() {
  console.log(this.data);
  // { alpha: 'bravo', charlie: 'delta' }
}

module.exports = {
  // ...
  module: {
    rules: [
      {
        test: /\.md$/,
        use: [
          {
            loader: "remark-loader",
            options: {
              remarkOptions: {
                plugins: [examplePluginUsingData],
                data: {
                  alpha: "bravo",
                  charlie: "delta",
                },
              },
            },
          },
        ],
      },
    ],
  },
};

移除前置信息

移除前置信息

类型

type removeFrontMatter = boolean;

默认值:true

默认情况下,前置信息会被移除。要覆盖此行为,请将 removeFrontMatter 设置为 false 并将 remark-frontmatter 添加到插件中。

webpack.config.js

import RemarkFrontmatter from "remark-frontmatter";

module.exports = {
  // ...
  module: {
    rules: [
      {
        test: /\.md$/,
        use: [
          {
            loader: "remark-loader",
            options: {
              removeFrontMatter: false,
              remarkOptions: {
                plugins: [RemarkFrontmatter],
              },
            },
          },
        ],
      },
    ],
  },
};

灵感

这个项目受到了以下开源工作的启发

示例

Markdown 到 HTML

要获取 HTML,您需要将 remark-html 添加到 remark 插件中,并将 html-loader 添加到您的 webpack.config.js 中。

import md from "markdown-file.md";
console.log(md);

webpack.config.js

import RemarkHTML from "remark-html";

module.exports = {
  // ...
  module: {
    rules: [
      {
        test: /\.md$/,
        use: [
          {
            loader: "html-loader",
          },
          {
            loader: "remark-loader",
            options: {
              remarkOptions: {
                plugins: [RemarkHTML],
              },
            },
          },
        ],
      },
    ],
  },
};

Markdown 到 Markdown

index.js

import md from "markdown-file.md";
console.log(md);

webpack.config.js

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

贡献

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

CONTRIBUTING

许可证

MIT

sass-loader

npm node tests coverage discussion size

加载 Sass/SCSS 文件并将其编译为 CSS。

入门

首先,您需要安装 sass-loader

npm install sass-loader sass webpack --save-dev

yarn add -D sass-loader sass webpack

pnpm add -D sass-loader sass webpack

[!注意]

要在您的项目中启用 CSS 处理,您需要通过 npm i style-loader css-loader 安装 style-loadercss-loader

sass-loader 要求您自行安装 Dart SassNode Sass(更多文档可在下方找到)或 Sass Embedded

这允许您控制所有依赖项的版本并选择要使用的 Sass 实现。

[!注意]

我们强烈推荐使用 Sass EmbeddedDart Sass

[!警告]

Node Sass 不支持 Yarn PnP 并且不支持 @use 规则

sass-loadercss-loaderstyle-loader 链接起来,以立即将所有样式应用于 DOM,或与 mini-css-extract-plugin 链接,以将其提取到单独的文件中。

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

app.js

import "./style.scss";

style.scss

$body-color: red;

body {
  color: $body-color;
}

webpack.config.js

module.exports = {
  module: {
    rules: [
      {
        test: /\.s[ac]ss$/i,
        use: [
          // Creates `style` nodes from JS strings
          "style-loader",
          // Translates CSS into CommonJS
          "css-loader",
          // Compiles Sass to CSS
          "sass-loader",
        ],
      },
    ],
  },
};

最后通过您喜欢的方法运行 webpack(例如,通过 CLI 或 npm 脚本)。

production 模式下的 style(新 API,16 版本起默认)和 outputStyle(旧 API)选项

对于 production 模式,除非在 sassOptions 中另有指定,否则 style(新 API,16 版本起默认)和 outputStyle(旧 API)选项默认为 compressed

解析 importuse 规则

Webpack 提供了一种 高级文件解析机制

sass-loader 使用 Sass 的自定义导入器功能,将所有查询传递给 webpack 解析引擎,使您能够从 node_modules 导入 Sass 模块。

@import "bootstrap";

使用 ~ 已弃用,应从您的代码中移除,但出于历史原因,我们仍然支持它。

为什么可以移除它?加载器将首先尝试将 @import 解析为相对路径。如果无法解析,加载器将尝试在 node_modules 中解析 @import

在模块路径前加上 ~ 会告诉 webpack 搜索 node_modules

@import "~bootstrap";

重要的是只在路径前加上 ~,因为 ~/ 解析到主目录,这是不同的。

Webpack 需要区分 bootstrap~bootstrap,因为 CSS 和 Sass 文件没有特殊的语法来导入相对文件。

编写 @import "style.scss"@import "./style.scss"; 相同。

url(...) 的问题

由于 Sass 实现不提供 URL 重写,所有链接的资产必须相对于输出。

  • 如果您将生成的 CSS 传递给 css-loader,所有 URL 必须相对于入口文件(例如 main.scss)。
  • 如果您只是生成 CSS 而不将其传递给 css-loader,则 URL 必须相对于您的 Web 根目录。

您可能会对第一个问题感到惊讶,因为自然会期望相对引用相对于它们在其中指定的 .sass/.scss 文件解析(就像在常规 .css 文件中一样)。

幸运的是,这个问题有两种解决方案

  • 使用 resolve-url-loader 添加缺失的 URL 重写。将其放置在加载器链中 sass-loader 之前。

  • 库作者通常提供一个变量来修改资产路径。例如,bootstrap-sass 有一个 $icon-font-path

选项

implementation

类型

type implementation = object | string;

默认值:sass

特殊的 implementation 选项决定使用哪个 Sass 实现。

默认情况下,加载器根据您的依赖项解析实现。只需将所需的实现添加到您的 package.jsonsasssass-embeddednode-sass 包)并安装依赖项即可。

sass-loader 使用 sass (dart-sass) 实现的示例

package.json

{
  "devDependencies": {
    "sass-loader": "^7.2.0",
    "sass": "^1.22.10"
  }
}

sass-loader 使用 node-sass 实现的示例

package.json

{
  "devDependencies": {
    "sass-loader": "^7.2.0",
    "node-sass": "^5.0.0"
  }
}

sass-loader 使用 sass-embedded 实现的示例

package.json

{
  "devDependencies": {
    "sass-loader": "^7.2.0",
    "sass": "^1.22.10"
  },
  "optionalDependencies": {
    "sass-embedded": "^1.70.0"
  }
}

[!注意]

使用 optionalDependencies 意味着当 sass-embedded 不支持某个操作系统时,sass-loader 可以回退到 sass

请注意 sass-loader 解析实现的顺序

  1. sass-embedded
  2. sass
  3. node-sass

您可以使用 implementation 选项指定特定的实现,该选项接受上述值之一。

object

例如,要始终使用 Dart Sass,您可以传递

module.exports = {
  module: {
    rules: [
      {
        test: /\.s[ac]ss$/i,
        use: [
          "style-loader",
          "css-loader",
          {
            loader: "sass-loader",
            options: {
              // Prefer `dart-sass`, even if `sass-embedded` is available
              implementation: require("sass"),
            },
          },
        ],
      },
    ],
  },
};

string

例如,要使用 Dart Sass,您可以传递

module.exports = {
  module: {
    rules: [
      {
        test: /\.s[ac]ss$/i,
        use: [
          "style-loader",
          "css-loader",
          {
            loader: "sass-loader",
            options: {
              // Prefer `dart-sass`, even if `sass-embedded` is available
              implementation: require.resolve("sass"),
            },
          },
        ],
      },
    ],
  },
};

sassOptions

类型

type sassOptions =
  | import("sass").LegacyOptions<"async">
  | ((
      content: string | Buffer,
      loaderContext: LoaderContext,
      meta: any,
    ) => import("sass").LegacyOptions<"async">);

默认值:Sass 实现的默认值

Dart SassNode Sass 实现的选项。

[!注意]

dart-sasscharset 选项默认值为 true。我们强烈不鼓励将其设置为 false,因为 webpack 不支持 utf-8 以外的文件。

[!注意]

对于 scss 扩展名,syntax(新 API,16 版本起默认)和 indentedSyntax(旧 API)选项为 scss,对于 sass 扩展名为 indented,对于 css 扩展名为 css

[!注意]

datafile 等选项不可用,将被忽略。

ℹ 我们强烈不鼓励更改 sourceMap(新 API,16 版本起默认)、outFile(旧 API)、sourceMapContents(旧 API)、sourceMapEmbed(旧 API)和 sourceMapRoot(旧 API)选项,因为当 sourceMap 选项为 true 时,sass-loader 会自动设置这些选项。

[!注意]

在自定义导入器中访问 加载器上下文 可以通过 this.webpackLoaderContext 属性完成。

sass (dart-sass) 和 node-sass 的选项略有不同。

在使用它们之前,请查阅各自的文档

object

使用对象进行 Sass 实现设置。

webpack.config.js

module.exports = {
  module: {
    rules: [
      {
        test: /\.s[ac]ss$/i,
        use: [
          "style-loader",
          "css-loader",
          {
            loader: "sass-loader",
            options: {
              sassOptions: {
                style: `compressed`,
                loadPaths: ["absolute/path/a", "absolute/path/b"],
              },
            },
          },
        ],
      },
    ],
  },
};

function

允许根据加载器上下文使用不同的选项配置 Sass 实现。

module.exports = {
  module: {
    rules: [
      {
        test: /\.s[ac]ss$/i,
        use: [
          "style-loader",
          "css-loader",
          {
            loader: "sass-loader",
            options: {
              sassOptions: (loaderContext) => {
                // More information about available properties https://webpack.js.cn/api/loaders/
                const { resourcePath, rootContext } = loaderContext;
                const relativePath = path.relative(rootContext, resourcePath);

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

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

sourceMap

类型

type sourceMap = boolean;

默认值:取决于 compiler.devtool 的值

启用/禁用源映射生成。

默认情况下,源映射的生成取决于 devtool 选项。除了 evalfalse 之外,所有值都启用源映射生成。

ℹ 如果为 true,则 sassOptions 中的 sourceMap(新 API,16 版本起默认)、outFile(旧 API)、sourceMapContents(旧 API)、sourceMapEmbed(旧 API)和 sourceMapRoot(旧 API)将被忽略。

webpack.config.js

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

ℹ 在某些极少数情况下,node-sass 可能会输出无效的源映射(这是 node-sass 的错误)。

为了避免这种情况,您可以尝试将 node-sass 更新到最新版本,或者您可以尝试在 sassOptions 中将 outputStyle 选项设置为 compressed

webpack.config.js

module.exports = {
  module: {
    rules: [
      {
        test: /\.s[ac]ss$/i,
        use: [
          "style-loader",
          "css-loader",
          {
            loader: "sass-loader",
            options: {
              sourceMap: true,
              sassOptions: {
                outputStyle: "compressed",
              },
            },
          },
        ],
      },
    ],
  },
};

additionalData

类型

type additionalData =
  | string
  | ((content: string | Buffer, loaderContext: LoaderContext) => string);

默认值:undefined

在实际入口文件前预置 Sass/SCSS 代码。在这种情况下,sass-loader 不会覆盖 data 选项,而只会预置入口文件的内容。

当您的一些 Sass 变量依赖于环境时,这尤其有用

string

module.exports = {
  module: {
    rules: [
      {
        test: /\.s[ac]ss$/i,
        use: [
          "style-loader",
          "css-loader",
          {
            loader: "sass-loader",
            options: {
              additionalData: "$env: " + process.env.NODE_ENV + ";",
            },
          },
        ],
      },
    ],
  },
};

function

同步
module.exports = {
  module: {
    rules: [
      {
        test: /\.s[ac]ss$/i,
        use: [
          "style-loader",
          "css-loader",
          {
            loader: "sass-loader",
            options: {
              additionalData: (content, loaderContext) => {
                // More information about available properties https://webpack.js.cn/api/loaders/
                const { resourcePath, rootContext } = loaderContext;
                const relativePath = path.relative(rootContext, resourcePath);

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

                return "$value: 200px;" + content;
              },
            },
          },
        ],
      },
    ],
  },
};
异步
module.exports = {
  module: {
    rules: [
      {
        test: /\.s[ac]ss$/i,
        use: [
          "style-loader",
          "css-loader",
          {
            loader: "sass-loader",
            options: {
              additionalData: async (content, loaderContext) => {
                // More information about available properties https://webpack.js.cn/api/loaders/
                const { resourcePath, rootContext } = loaderContext;
                const relativePath = path.relative(rootContext, resourcePath);

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

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

webpackImporter

类型

type webpackImporter = boolean;

默认值:true

启用/禁用默认的 webpack 导入器。

这在某些情况下可以提高性能,但请谨慎使用,因为别名和以 ~ 开头的 @import 规则将不起作用。您可以传递自己的 importer 来解决此问题(请参阅 importer 文档)。

webpack.config.js

module.exports = {
  module: {
    rules: [
      {
        test: /\.s[ac]ss$/i,
        use: [
          "style-loader",
          "css-loader",
          {
            loader: "sass-loader",
            options: {
              webpackImporter: false,
            },
          },
        ],
      },
    ],
  },
};

warnRuleAsWarning

类型

type warnRuleAsWarning = boolean;

默认值:true

@warn 规则视为 webpack 警告。

style.scss

$known-prefixes: webkit, moz, ms, o;

@mixin prefix($property, $value, $prefixes) {
  @each $prefix in $prefixes {
    @if not index($known-prefixes, $prefix) {
      @warn "Unknown prefix #{$prefix}.";
    }

    -#{$prefix}-#{$property}: $value;
  }
  #{$property}: $value;
}

.tilt {
  // Oops, we typo'd "webkit" as "wekbit"!
  @include prefix(transform, rotate(15deg), wekbit ms);
}

所呈现的代码将抛出一个 webpack 警告而不是日志。

要忽略不必要的警告,可以使用 ignoreWarnings 选项。

webpack.config.js

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

api

类型

type api = "legacy" | "modern" | "modern-compiler";

默认值:对于 sass (dart-sass) 和 sass-embedded"modern",对于 node-sass"legacy"

允许您在 legacymodern API 之间切换。您可以在 此处 找到更多信息。modern-compiler 选项启用了现代 API,并支持 共享资源

[!注意]

同时使用 modern-compilersass-embedded 可显著提高性能并缩短构建时间。我们强烈建议使用它们。我们将在未来的主要版本中默认启用它们。

[!警告]

legacymodern API 的 Sass 选项不同。请查阅 文档 了解如何迁移到现代选项。

webpack.config.js

module.exports = {
  module: {
    rules: [
      {
        test: /\.s[ac]ss$/i,
        use: [
          "style-loader",
          "css-loader",
          {
            loader: "sass-loader",
            options: {
              api: "modern-compiler",
              sassOptions: {
                // Your sass options
              },
            },
          },
        ],
      },
    ],
  },
};

如何启用 @debug 输出

默认情况下,@debug 消息的输出是禁用的。将以下内容添加到 webpack.config.js 中以启用它们

module.exports = {
  stats: {
    loggingDebug: ["sass-loader"],
  },
  // ...
};

示例

将 CSS 提取到单独的文件中

对于生产构建,建议从捆绑包中提取 CSS,以便稍后并行加载 CSS/JS 资源。

从捆绑包中提取样式表有四种推荐方法

1. mini-css-extract-plugin

webpack.config.js

const MiniCssExtractPlugin = require("mini-css-extract-plugin");

module.exports = {
  module: {
    rules: [
      {
        test: /\.s[ac]ss$/i,
        use: [
          // fallback to style-loader in development
          process.env.NODE_ENV !== "production"
            ? "style-loader"
            : MiniCssExtractPlugin.loader,
          "css-loader",
          "sass-loader",
        ],
      },
    ],
  },
  plugins: [
    new MiniCssExtractPlugin({
      // Options similar to the same options in webpackOptions.output
      // both options are optional
      filename: "[name].css",
      chunkFilename: "[id].css",
    }),
  ],
};

2. 资产模块

webpack.config.js

module.exports = {
  entry: [__dirname + "/src/scss/app.scss"],
  module: {
    rules: [
      {
        test: /\.js$/,
        exclude: /node_modules/,
        use: [],
      },
      {
        test: /\.scss$/,
        exclude: /node_modules/,
        type: "asset/resource",
        generator: {
          filename: "bundle.css",
        },
        use: ["sass-loader"],
      },
    ],
  },
};

3. extract-loader(更简单,但专门用于 css-loader 的输出)

4. file-loader(已弃用——仅应在 webpack v4 中使用)

webpack.config.js

module.exports = {
  entry: [__dirname + "/src/scss/app.scss"],
  module: {
    rules: [
      {
        test: /\.js$/,
        exclude: /node_modules/,
        use: [],
      },
      {
        test: /\.scss$/,
        exclude: /node_modules/,
        use: [
          {
            loader: "file-loader",
            options: { outputPath: "css/", name: "[name].min.css" },
          },
          "sass-loader",
        ],
      },
    ],
  },
};

(来源:https://stackoverflow.com/a/60029923/2969615

源映射

启用/禁用源映射生成。

要启用 CSS 源映射,您需要将 sourceMap 选项传递给 sass-loader css-loader

webpack.config.js

module.exports = {
  devtool: "source-map", // any "source-map"-like devtool is possible
  module: {
    rules: [
      {
        test: /\.s[ac]ss$/i,
        use: [
          "style-loader",
          {
            loader: "css-loader",
            options: {
              sourceMap: true,
            },
          },
          {
            loader: "sass-loader",
            options: {
              sourceMap: true,
            },
          },
        ],
      },
    ],
  },
};

如果您想在 Chrome 中编辑原始 Sass 文件,这里有一篇不错的博客文章。请查看 test/sourceMap 以获取工作示例。

贡献

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

CONTRIBUTING

许可证

MIT

source-map-loader

npm node tests coverage discussion size

从现有源文件(从其 <code>sourceMappingURL</code>)中提取源映射。

入门

首先,您需要安装 source-map-loader

npm i -D source-map-loader

yarn add -D source-map-loader

pnpm add -D source-map-loader

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

file.js

import css from "file.css";

webpack.config.js

module.exports = {
  module: {
    rules: [
      {
        test: /\.js$/,
        enforce: "pre",
        use: ["source-map-loader"],
      },
    ],
  },
};

source-map-loader 从所有 JavaScript 条目中提取现有源映射。这包括内联源映射以及通过 sourceMappingURL 链接的源映射。

所有源映射数据都传递给 webpack 进行处理,根据 源映射样式 中指定的 webpack.config.jsdevtool 选项。

当使用具有自己源映射的第三方库时,此加载器特别有用。如果未提取并处理到 webpack 捆绑包的源映射中,浏览器可能会错误地解释或忽略源映射数据。

source-map-loader 允许 webpack 保持库之间源映射数据的一致性,从而保留调试的便利性。

source-map-loader 将从任何 JavaScript 文件中提取,包括 node_modules 目录中的文件。

请注意设置 includeexclude 规则条件,以最大化捆绑性能。

最后,使用你通常使用的方法运行 webpack(例如,通过 CLI 或 npm 脚本)。

选项

名称类型默认值描述
filterSourceMappingUrl{Function}undefined允许控制 SourceMappingURL 行为

filterSourceMappingUrl

类型:Function 默认值:undefined

允许您指定加载器对 SourceMappingURL 注释的行为。

函数必须返回以下值之一

  • true'consume' - 消耗源映射并移除 SourceMappingURL 注释(默认行为)
  • false'remove' - 不消耗源映射并移除 SourceMappingURL 注释
  • skip - 不消耗源映射且不移除 SourceMappingURL 注释

示例配置

webpack.config.js

module.exports = {
  module: {
    rules: [
      {
        test: /\.js$/,
        enforce: "pre",
        use: [
          {
            loader: "source-map-loader",
            options: {
              filterSourceMappingUrl: (url, resourcePath) => {
                if (/broker-source-map-url\.js$/i.test(url)) {
                  return false;
                }

                if (/keep-source-mapping-url\.js$/i.test(resourcePath)) {
                  return "skip";
                }

                return true;
              },
            },
          },
        ],
      },
    ],
  },
};

示例

忽略警告

要忽略警告,可以使用以下配置

webpack.config.js

module.exports = {
  module: {
    rules: [
      {
        test: /\.js$/,
        enforce: "pre",
        use: ["source-map-loader"],
      },
    ],
  },
  ignoreWarnings: [/Failed to parse source map/],
};

有关 ignoreWarnings 选项的更多信息,请参见此处

贡献

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

CONTRIBUTING

许可证

MIT

style-loader

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

安全警告

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

选项

injectType

类型

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

默认值:styleTag

允许您设置将样式注入 DOM 的方式。

可能的值

styleTag

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

component.js

import "./styles.css";

局部变量示例 (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> 元素附加到样式目标的末尾,除非由 insert 指定,否则样式目标是页面的 <head> 标签。

这将导致加载器创建的 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

string

允许您设置自定义函数 的绝对路径,该函数允许覆盖默认的 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 基础来防止 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 模块是有益的,例如 模块串联摇树优化

您可以通过以下方式启用 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 模块的命名导出

[!警告]

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

[!警告]

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

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),注入的代码通常会被阻止。一种解决方法是使用随机数。但是,请注意,使用随机数会显著降低 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;

贡献

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

CONTRIBUTING

许可证

MIT

stylus-loader

npm node tests cover discussion size

用于 webpack 的 Stylus 加载器。将 Stylus 文件编译为 CSS。

入门

首先,您需要安装 stylusstylus-loader

npm install stylus stylus-loader --save-dev

yarn add -D stylus stylus-loader

pnpm add -D stylus stylus-loader

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

webpack.config.js

module.exports = {
  module: {
    rules: [
      {
        test: /\.styl$/,
        loader: "stylus-loader", // compiles Styl to CSS
      },
    ],
  },
};

最后,使用你通常使用的方法运行 webpack(例如,通过 CLI 或 npm 脚本)。

选项

stylusOptions

类型

type stylusOptions =
  | {
      use: Array<string | Function>;
      include: Array<string>;
      import: Array<string>;
      define: Array;
      includeCSS: false;
      resolveURL: boolean | Object;
      lineNumbers: boolean;
      hoistAtrules: boolean;
      compress: boolean;
    }
  | (loaderContext: LoaderContext) => Array<string>;

默认值:{}

您可以通过 加载器选项 中的 stylusOptions 属性,将任何 Stylus 特定的选项传递给 stylus-loader

请参阅 Stylus 文档

短横线命名法(dash-case)的选项应以驼峰命名法(camelCase)编写。

object

使用对象将选项传递给 Stylus。

webpack.config.js

module.exports = {
  module: {
    rules: [
      {
        test: /\.styl$/,
        use: [
          {
            loader: "style-loader",
          },
          {
            loader: "css-loader",
          },
          {
            loader: "stylus-loader",
            options: {
              stylusOptions: {
                /**
                 * Specify Stylus plugins to use. Plugins may be passed as
                 * strings instead of importing them in your Webpack config.
                 *
                 * @type {(string|Function)[]}
                 * @default []
                 */
                use: ["nib"],

                /**
                 * Add path(s) to the import lookup paths.
                 *
                 * @type {string[]}
                 * @default []
                 */
                include: [path.join(__dirname, "src/styl/config")],

                /**
                 * Import the specified Stylus files/paths.
                 *
                 * @type {string[]}
                 * @default []
                 */
                import: ["nib", path.join(__dirname, "src/styl/mixins")],

                /**
                 * Define Stylus variables or functions.
                 *
                 * @type {Array|Object}
                 * @default {}
                 */
                // Array is the recommended syntax: [key, value, raw]
                define: [
                  ["$development", process.env.NODE_ENV === "development"],
                  ["rawVar", 42, true],
                ],
                // Object is deprecated syntax (there is no possibility to specify "raw')
                // define: {
                //   $development: process.env.NODE_ENV === 'development',
                //   rawVar: 42,
                // },

                /**
                 * Include regular CSS on @import.
                 *
                 * @type {boolean}
                 * @default false
                 */
                includeCSS: false,

                /**
                 * Resolve relative url()'s inside imported files.
                 *
                 * @see https://stylus.org.cn/docs/js.html#stylusresolveroptions
                 *
                 * @type {boolean|Object}
                 * @default { nocheck: true }
                 */
                resolveURL: true,
                // resolveURL: { nocheck: true },

                /**
                 * Emits comments in the generated CSS indicating the corresponding Stylus line.
                 *
                 * @see https://stylus.org.cn/docs/executable.html
                 *
                 * @type {boolean}
                 * @default false
                 */
                lineNumbers: true,

                /**
                 * Move @import and @charset to the top.
                 *
                 * @see https://stylus.org.cn/docs/executable.html
                 *
                 * @type {boolean}
                 * @default false
                 */
                hoistAtrules: true,

                /**
                 * Compress CSS output.
                 * In the "production" mode is `true` by default
                 *
                 * @see https://stylus.org.cn/docs/executable.html
                 *
                 * @type {boolean}
                 * @default false
                 */
                compress: true,
              },
            },
          },
        ],
      },
    ],
  },
};

function

允许根据加载器上下文设置传递给 Stylus 的选项。

module.exports = {
  module: {
    rules: [
      {
        test: /\.styl/,
        use: [
          "style-loader",
          "css-loader",
          {
            loader: "stylus-loader",
            options: {
              stylusOptions: (loaderContext) => {
                // More information about available properties https://webpack.js.cn/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

类型

type 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

类型

type webpackImporter = boolean;

默认值:true

启用/禁用默认的 Webpack 导入器。

这在某些情况下可以提高性能。请谨慎使用,因为别名和以 ~ 开头的 @import 规则将不起作用。

webpack.config.js

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

additionalData

类型

type additionalData =
  | string
  | (
      content: string | Buffer,
      loaderContext: LoaderContext,
      meta: any
    ) => string;

默认值:undefined

在实际入口文件前预置 Stylus 代码。在这种情况下,stylus-loader 不会覆盖源文件,而只会预置入口文件的内容。

当您的一些 Stylus 变量依赖于环境时,这尤其有用。

[!注意]

由于您正在注入代码,这将破坏入口文件中的源映射。通常有比这更简单的解决方案,例如使用多个 Stylus 入口文件。

string

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

function

同步
module.exports = {
  module: {
    rules: [
      {
        test: /\.styl/,
        use: [
          "style-loader",
          "css-loader",
          {
            loader: "stylus-loader",
            options: {
              additionalData: (content, loaderContext) => {
                // More information about available properties https://webpack.js.cn/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;
              },
            },
          },
        ],
      },
    ],
  },
};
异步
module.exports = {
  module: {
    rules: [
      {
        test: /\.styl/,
        use: [
          "style-loader",
          "css-loader",
          {
            loader: "stylus-loader",
            options: {
              additionalData: async (content, loaderContext) => {
                // More information about available properties https://webpack.js.cn/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

类型

type implementation = Function | string;

implementation 选项允许您指定要使用的 Stylus 实现。它会覆盖本地安装的 styluspeerDependency 版本。

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

示例

正常用法

stylus-loadercss-loaderstyle-loader 链式使用,以立即将所有样式应用于 DOM。

webpack.config.js

module.exports = {
  module: {
    rules: [
      {
        test: /\.styl$/,
        use: [
          {
            loader: "style-loader", // creates style nodes from JS strings
          },
          {
            loader: "css-loader", // translates CSS into CommonJS
          },
          {
            loader: "stylus-loader", // compiles Stylus to CSS
          },
        ],
      },
    ],
  },
};

源映射

要为 CSS 启用源映射,您需要在加载器选项中传递 sourceMap 属性。如果未传递此属性,加载器将遵循 devtool 中设置的 webpack 源映射设置。

webpack.config.js

module.exports = {
  devtool: "source-map", // any "source-map"-like devtool is possible
  module: {
    rules: [
      {
        test: /\.styl$/,
        use: [
          "style-loader",
          {
            loader: "css-loader",
            options: {
              sourceMap: true,
            },
          },
          {
            loader: "stylus-loader",
            options: {
              sourceMap: true,
            },
          },
        ],
      },
    ],
  },
};

将 nib 与 stylus 一起使用

webpack.config.js

module.exports = {
  module: {
    rules: [
      {
        test: /\.styl$/,
        use: [
          {
            loader: "style-loader", // creates style nodes from JS strings
          },
          {
            loader: "css-loader", // translates CSS into CommonJS
          },
          {
            loader: "stylus-loader", // compiles Stylus to CSS
            options: {
              stylusOptions: {
                use: [require("nib")()],
                import: ["nib"],
              },
            },
          },
        ],
      },
    ],
  },
};

导入 JSON 文件

Stylus 在 json() 函数中不提供解析功能。因此 webpack 解析器不适用于 .json 文件。要处理此问题,请使用 stylus 解析器

index.styl

// Suppose the file is located here `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: {
                // Specify the path. where to find files
                paths: ["node_modules/vars"],
              },
            },
          },
        ],
      },
    ],
  },
};

生产环境

通常,建议在生产环境中使用 MiniCssExtractPlugin 将样式表提取到专门的 CSS 文件中。这样,您的样式就不依赖于 JavaScript。

webpack 解析器

Webpack 提供了一种 高级文件解析机制stylus-loader 在处理查询时应用 webpack 解析器。因此,您可以直接从 node_modules 导入 Stylus 模块。

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

使用 ~ 前缀已弃用,可以从您的代码中移除(我们推荐这样做),但出于历史原因,我们仍然支持它。

为什么可以移除它?加载器将首先尝试将 @import/@require 解析为相对路径,如果无法解析,加载器将尝试在 node_modules 中解析 @import/@require

只需在它们前面加上 ~,这会告诉 webpack 查找 modules

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

重要的是只在前面加上 ~,因为 ~/ 解析到主目录,这是不同的。

Webpack 需要区分 bootstrap~bootstrap,因为 CSS 和 Stylus 文件没有特殊的语法来导入相对文件。

编写 @import "file"@import "./file"; 相同。

Stylus 解析器

如果您指定 paths 选项,模块将在给定的 paths 中搜索。这是 Stylus 的默认行为。

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

提取样式表

将 CSS 与 webpack 捆绑有一些优点,例如使用哈希 URL 引用图像和字体,或在开发中使用 热模块替换。另一方面,在生产环境中,根据 JS 执行应用样式表并不是一个好主意。渲染可能会延迟,甚至可能会出现 FOUC(无样式内容的闪烁)。因此,将它们作为单独的文件放入最终生产构建中通常仍然更好。

有两种方法可以从捆绑包中提取样式表

贡献

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

CONTRIBUTING

许可证

MIT

thread-loader

npm node tests coverage discussion size

在工作池中运行指定的加载器。

入门

npm install --save-dev thread-loader

yarn add -D thread-loader

pnpm add -D thread-loader

将此加载器放在其他加载器之前。以下加载器在工作池中运行。

在工作池中运行的加载器有局限性。示例

  • 加载器无法发出文件。
  • 加载器无法使用自定义加载器 API(即通过插件)。
  • 加载器无法访问 webpack 选项。

每个工作进程都是一个单独的 Node.js 进程,它有大约 600 毫秒的开销。此外,进程间通信也有额外的开销。

仅将此加载器用于昂贵的操作!

示例

webpack.config.js

module.exports = {
  module: {
    rules: [
      {
        test: /\.js$/,
        include: path.resolve('src'),
        use: [
          'thread-loader',
          // your expensive loader (e.g babel-loader)
        ],
      },
    ],
  },
};

带选项

use: [
  {
    loader: 'thread-loader',
    // loaders with equal options will share worker pools
    options: {
      // the number of spawned workers, defaults to (number of cpus - 1) or
      // fallback to 1 when require('os').cpus() is undefined
      workers: 2,

      // number of jobs a worker processes in parallel
      // defaults to 20
      workerParallelJobs: 50,

      // additional node.js arguments
      workerNodeArgs: ['--max-old-space-size=1024'],

      // Allow to respawn a dead worker pool
      // respawning slows down the entire compilation
      // and should be set to false for development
      poolRespawn: false,

      // timeout for killing the worker processes when idle
      // defaults to 500 (ms)
      // can be set to Infinity for watching builds to keep workers alive
      poolTimeout: 2000,

      // number of jobs the pool distributes to the workers
      // defaults to 200
      // decrease for less efficient but more fair distribution
      poolParallelJobs: 50,

      // name of the pool
      // can be used to create different pools with otherwise identical options
      name: 'my-pool',
    },
  },
  // your expensive loader (e.g babel-loader)
];

预热

为了防止启动工作进程时出现高延迟,可以预热工作池。

这会启动池中最大数量的工作进程,并将指定的模块加载到 Node.js 模块缓存中。

const threadLoader = require('thread-loader');

threadLoader.warmup(
  {
    // pool options, like passed to loader options
    // must match loader options to boot the correct pool
  },
  [
    // modules to load
    // can be any module, i.e.
    'babel-loader',
    '@babel/preset-env',
    'sass-loader',
  ],
);

贡献

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

CONTRIBUTING

许可证

MIT

val-loader

npm node tests coverage discussion size

val-loader

一个 webpack 加载器,它在构建时执行给定模块并返回执行结果,当模块在捆绑包中被 require 时。通过这种方式,加载器将模块从代码转换为结果。

另一种看待 val-loader 的方式是,它允许用户实现自定义加载器逻辑,而无需编写完整的自定义加载器。

目标模块使用两个参数调用:(options, loaderContext)

  • options:加载器选项(例如在 webpack 配置中提供。请参阅下面的示例)。
  • loaderContext加载器上下文

入门

首先,您需要安装 val-loader

npm install val-loader --save-dev
yarn add -D val-loader
pnpm add -D val-loader

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

target-file.js

module.exports = (options, loaderContext) => {
  return { code: "module.exports = 42;" };
};

webpack.config.js

module.exports = {
  module: {
    rules: [
      {
        test: /target-file.js$/,
        use: [
          {
            loader: `val-loader`,
          },
        ],
      },
    ],
  },
};

src/entry.js

const answer = require("target-file");

最后,使用你通常使用的方法运行 webpack(例如,通过 CLI 或 npm 脚本)。

选项

executableFile

类型

type executableFile = string;

默认值:undefined

允许指定可执行文件的路径。

data.json

{
  "years": "10"
}

executable-file.js

module.exports = function yearsInMs(options, loaderContext, content) {
  const { years } = JSON.parse(content);
  const value = years * 365 * 24 * 60 * 60 * 1000;

  return {
    cacheable: true,
    code: "module.exports = " + value,
  };
};

webpack.config.js

module.exports = {
  module: {
    rules: [
      {
        test: /\.(json)$/i,
        rules: [
          {
            loader: "val-loader",
            options: {
              executableFile: path.resolve(
                __dirname,
                "fixtures",
                "executableFile.js",
              ),
            },
          },
        ],
      },
      {
        test: /\.json$/i,
        type: "asset/resource",
      },
    ],
  },
};

返回对象属性

此加载器的目标模块必须导出一个返回对象的 function,或者一个解析为对象的 Promise(例如 async function),该对象至少包含一个 code 属性,但也可以包含其他属性。

code

类型

type code = string | Buffer;

默认值:undefined 必需

传递给 webpack 或下一个加载器的代码,将替换原始模块。

sourceMap

类型

type sourceMap = object;

默认值:undefined

传递给 webpack 或下一个加载器的源映射。

ast

类型

type ast = Array<object>;

默认值:undefined

一个 抽象语法树 (AST),将传递给下一个加载器。如果下一个加载器使用相同的 AST,则有助于加快构建时间。

dependencies

类型

type dependencies = Array<string>;

默认值:[]

一个包含文件依赖项的绝对原生路径数组,webpack 应该监视这些文件以检测更改。

依赖项也可以使用 loaderContext.addDependency(file: string) 添加。

contextDependencies

类型

type contextDependencies = Array<string>;

默认值:[]

一个包含目录依赖项的绝对原生路径数组,webpack 应该监视这些目录以检测更改。

上下文依赖项也可以使用 loaderContext.addContextDependency(directory: string) 添加。

buildDependencies

类型

type buildDependencies = Array<string>;

默认值:[]

一个包含目录依赖项的绝对原生路径数组,webpack 应该监视这些目录以检测更改。

构建依赖项也可以使用 loaderContext.addBuildDependency(file: string) 添加。

cacheable

类型

type cacheable = boolean;

默认值:false

如果为 true,则指定在监视模式下,如果没有 dependencies 发生变化,则可以重用代码。

示例

简单示例

在此示例中,加载器被配置为在文件名为 years-in-ms.js 的文件上操作,执行代码,并将结果作为执行结果存储在捆绑包中。此示例将 years 作为 option 传递,这对应于目标模块的导出函数中的 years 参数

years-in-ms.js

module.exports = function yearsInMs({ years }) {
  const value = years * 365 * 24 * 60 * 60 * 1000;

  // NOTE: this return value will replace the module in the bundle
  return {
    cacheable: true,
    code: "module.exports = " + value,
  };
};

webpack.config.js

module.exports = {
  module: {
    rules: [
      {
        test: require.resolve("src/years-in-ms.js"),
        use: [
          {
            loader: "val-loader",
            options: {
              years: 10,
            },
          },
        ],
      },
    ],
  },
};

在捆绑包中,requiring 模块然后返回

import tenYearsMs from "years-in-ms";

console.log(tenYearsMs); // 315360000000

Modernizr

示例展示了如何构建 modernizr

entry.js

import modenizr from "./modernizr.js";

modernizr.js

const modernizr = require("modernizr");

module.exports = function (options) {
  return new Promise(function (resolve) {
    // It is impossible to throw an error because modernizr causes the process.exit(1)
    modernizr.build(options, function (output) {
      resolve({
        cacheable: true,
        code: `var modernizr; var hadGlobal = 'Modernizr' in window; var oldGlobal = window.Modernizr; ${output} modernizr = window.Modernizr; if (hadGlobal) { window.Modernizr = oldGlobal; } else { delete window.Modernizr; } export default modernizr;`,
      });
    });
  });
};

webpack.config.js

const path = require("path");
module.exports = {
  module: {
    rules: [
      {
        test: path.resolve(__dirname, "src", "modernizr.js"),
        use: [
          {
            loader: "val-loader",
            options: {
              minify: false,
              options: ["setClasses"],
              "feature-detects": [
                "test/css/flexbox",
                "test/es6/promises",
                "test/serviceworker",
              ],
            },
          },
        ],
      },
    ],
  },
};

Figlet

示例展示了如何构建 figlet

entry.js

import { default as figlet } from "./figlet.js";

console.log(figlet);

figlet.js

const figlet = require("figlet");

function wrapOutput(output, config) {
  let figletOutput = "";

  if (config.textBefore) {
    figletOutput += encodeURI(`${config.textBefore}\n`);
  }

  output.split("\n").forEach((line) => {
    figletOutput += encodeURI(`${line}\n`);
  });

  if (config.textAfter) {
    figletOutput += encodeURI(`${config.textAfter}\n`);
  }

  return `module.exports = decodeURI("${figletOutput}");`;
}

module.exports = function (options) {
  const defaultConfig = {
    fontOptions: {
      font: "ANSI Shadow",
      horizontalLayout: "default",
      kerning: "default",
      verticalLayout: "default",
    },
    text: "FIGLET-LOADER",
    textAfter: null,
    textBefore: null,
  };

  const config = Object.assign({}, defaultConfig, options);

  return new Promise(function (resolve, reject) {
    figlet.text(config.text, config.fontOptions, (error, output) => {
      if (error) {
        return reject(error);
      }

      resolve({
        cacheable: true,
        code: "module.exports = " + wrapOutput(output, config),
      });
    });
  });
};

webpack.config.js

const path = require("path");
module.exports = {
  module: {
    rules: [
      {
        test: path.resolve(__dirname, "src", "figlet.js"),
        use: [
          {
            loader: "val-loader",
            options: {
              text: "FIGLET",
            },
          },
        ],
      },
    ],
  },
};

贡献

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

CONTRIBUTING

许可证

MIT

加载器

Webpack 允许使用 加载器 预处理文件。这使您可以将任何静态资源(远超 JavaScript)打包。您可以使用 Node.js 轻松编写自己的加载器。

加载器通过在 require() 语句中使用 loadername! 前缀激活,或通过 webpack 配置中的正则表达式自动应用——请参阅 配置

文件

  • val-loader 将代码作为模块执行,并将导出视为 JS 代码
  • ref-loader 手动在任何文件之间创建依赖项

JSON

转译

模板

样式

框架

精彩推荐

更多第三方加载器,请参阅 awesome-webpack 中的列表。

1 贡献者

webpack