知海

实验特性配置

webpackjsorg-main配置参考

title: 实验特性配置
sort: 19
contributors:

  • EugeneHlushko
  • wizardofhogwarts
  • chenxsan
  • anshumanv
  • snitin315
  • burhanuday

experiments

boolean: false

experiments 选项在 webpack 5 中引入,用于让用户能够启用和尝试实验性功能。

W> 由于实验性功能具有宽松的语义化版本控制,并且可能包含破坏性变更,请确保将 webpack 版本固定到 minor 版本,例如 webpack: ~5.4.3 而不是 webpack: ^5.4.3,或者在使用 experiments 时使用 lockfile。

可用选项:

  • asyncWebAssembly:根据更新后的规范支持新的 WebAssembly,它将 WebAssembly 模块变为异步模块。自 webpack 5.109.0 起默认为 'auto',即除非为 WebAssembly 文件注册了 loader,否则启用内置支持。
  • backCompat
  • buildHttp
  • cacheUnaffected
  • css
  • deferImport
  • futureDefaults
  • html
  • lazyCompilation
  • outputModule
  • typescript
  • sourceImport
  • syncWebAssembly:像 webpack 4 那样支持旧的 WebAssembly。
  • layers:启用模块和 chunk 层级,自 5.102.0 起已移除并且无需额外选项即可工作。
  • topLevelAwait:当在顶层使用 await 时,将模块转换为 async 模块。从 webpack 版本 5.83.0 开始(但在之前的版本中,可以通过将 experiments.topLevelAwait 设置为 true 来启用),此功能默认启用,自 5.102.0 起已移除并且无需额外选项即可工作。

webpack.config.js

js 复制代码
export default {
  // ...
  experiments: {
    asyncWebAssembly: true,
    buildHttp: true,
    lazyCompilation: true,
    outputModule: true,
    sourceImport: true,
    syncWebAssembly: true,
    topLevelAwait: true,
  },
};

experiments.backCompat

启用向后兼容层,并对许多 webpack 4 API 发出弃用警告。

  • 类型:boolean
js 复制代码
export default {
  // ...
  experiments: {
    backCompat: true,
  },
};

experiments.buildHttp

启用后,webpack 可以构建以 http(s): 协议开头的远程资源。

  • 类型:

    • (string | RegExp | ((uri: string) => boolean))[]

      experiments.buildHttp.allowedUris 的简写形式。

    • HttpUriOptions

      ts 复制代码
      {
        allowedUris: (string|RegExp|(uri: string) => boolean)[],
        cacheLocation?: false | string,
        frozen?: boolean,
        lockfileLocation?: string,
        upgrade?: boolean
      }
  • 可用版本:5.49.0+

  • 示例

    webpack.config.js

    js 复制代码
    export default {
      // ...
      experiments: {
        buildHttp: true,
      },
    };
    js 复制代码
    // src/index.js
    import pMap1 from "https://cdn.skypack.dev/p-map";
    
    // 启用 `buildHttp` 后,webpack 会像处理普通本地模块一样构建 pMap1
    console.log(pMap1);

experiments.buildHttp.allowedUris

允许的 URI 列表。

  • 类型:(string|RegExp|(uri: string) => boolean)[]

  • 示例

    webpack.config.js

    js 复制代码
    export default {
      // ...
      experiments: {
        buildHttp: {
          allowedUris: [
            "http://localhost:9990/",
            "https://raw.githubusercontent.com/",
          ],
        },
      },
    };

experiments.buildHttp.cacheLocation

定义缓存远程资源的位置。

  • 类型

    • string
    • false
  • 示例

    webpack.config.js

    js 复制代码
    export default {
      // ...
      experiments: {
        buildHttp: {
          cacheLocation: false,
        },
      },
    };

默认情况下,webpack 会使用 <compiler-name.>webpack.lock.data/ 进行缓存,但你可以通过将其值设置为 false 来禁用缓存。

请注意,你应该将 experiments.buildHttp.cacheLocation 下的文件提交到版本控制系统中,因为在 production 构建期间不会发起任何网络请求。

experiments.buildHttp.frozen

冻结远程资源和 lockfile。对 lockfile 或资源内容的任何修改都将导致错误。

  • 类型:boolean

experiments.buildHttp.lockfileLocation

定义存储 lockfile 的位置。

  • 类型:string

默认情况下,webpack 会生成一个 <compiler-name.>webpack.lock 文件。请确保将其提交到版本控制系统中。在 production 构建期间,webpack 将根据 lockfile 和 experiments.buildHttp.cacheLocation 下的缓存来构建以 http(s): 协议开头的模块。

experiments.buildHttp.proxy

指定用于获取远程资源的代理服务器。

  • 类型:string

默认情况下,webpack 会从 http_proxy(不区分大小写)环境变量中推断用于获取远程资源的代理服务器。不过,你也可以通过 proxy 选项指定代理。

experiments.buildHttp.upgrade

检测远程资源的变化并自动升级它们。

  • 类型:boolean

experiments.css

启用原生 CSS 支持。请注意,这仍然是一个正在开发中的实验性功能,将在 webpack v6 中默认启用,但你可以在 GitHub 上跟踪进展。

  • 类型:boolean | 'auto'
  • 默认值:'auto'

自 webpack 5.109.0 起,该选项默认为 'auto':除非 module.rules 中已有带 loader(或显式模块类型)的规则匹配 .css.module.css 文件,否则启用内置 CSS 支持,因此现有的 css-loader/mini-css-extract-plugin 配置可以保持不变。将其设置为 true 以强制使用原生支持,或设置为 false 以完全禁用。experiments.futureDefaults 会将其解析为 true

实验性功能:

  • CSS Modules 支持:webpack 会为每个 CSS 类生成唯一的名称。使用 .module.css 扩展名来启用 CSS Modules。

    webpack 原生支持 CSS Modules 的 composes 属性,允许你从同一文件、其他 CSS 模块或全局类中组合类:

    css 复制代码
    /* styles.module.css */
    .base {
      color: blue;
    }
    
    .button {
      composes: base;
      padding: 10px;
    }
    
    .primary {
      composes: button;
      background: blue;
    }
    
    /* 从另一个 CSS 模块中组合 */
    .composed {
      composes: className from "./other.module.css";
    }
    
    /* 从全局类中组合 */
    .globalComposed {
      composes: global-class from global;
    }
  • 解析 package.json 文件中的样式特定字段:webpack 会查找 package.json 文件中的 style 字段,如果在 CSS 文件内部有导入,则使用该字段。

    例如,如果你在 CSS 文件中添加 @import 'bootstrap';,webpack 会在 node_modules 中查找 bootstrap,并使用其 package.json 中的 style 字段。如果找不到 style 字段,webpack 将使用 main 字段以保持向后兼容。

  • CSS 文件的内容哈希:webpack 会为 CSS 文件生成内容哈希,并将其用于文件名中。这对于长期缓存非常有用。

  • CSS 提取:webpack 会将 CSS 提取到单独的文件中。此功能替代了 mini-css-extract-plugincss-loader 的需求,因为它提供了原生支持。

  • CSS 导入:webpack 会将 CSS 导入内联到生成的 CSS 文件中。

  • 热模块替换(HMR):webpack 支持 CSS 文件的 HMR。这意味着对 CSS 文件所做的更改将无需完全重新加载页面即可反映在浏览器中。

  • CSS Modules 的作用域提升(模块拼接)。当
    optimization.concatenateModules
    启用时,exportTypetextcss-style-sheet
    stylelink 的 CSS Modules 会被拼接为单个模块实例,而不是作为独立的运行时实例存在。这减少了开销,并为 CSS 密集型打包产物生成更小的输出。

  • @value 标识符可以用作 @import 的路径参数以及 url() 引用中,因此共享路径和资源可以定义一次并在多个样式表中复用。带引号("./x"'./x')和不带引号(./x)的形式都被接受,并会通过 webpack 常规的资源管线进行解析。

    css 复制代码
    @value path: "./other.module.css";
    @import path;
    
    @value bg: "./image.png";
    
    .a {
      background: url(bg);
    }

experiments.cacheUnaffected

启用对未更改且仅引用未更改模块的模块进行额外的内存缓存。

  • 类型:boolean

默认值为 futureDefaults 的值。

experiments.deferImport

启用 tc39 提案 the import defer proposal 的支持。这允许将模块的求值延迟到首次使用时。这对于在由于 import() 的异步特性而无法使用时,需要同步延迟代码执行的情况非常有用。

  • 类型:boolean

此功能要求运行时环境支持 Proxy(ES6)。

启用以下语法:

{/* eslint-skip */}

js 复制代码
import defer * as module from "module-name";
import * as module2 from /* webpackDefer: true */ "module-name2";

// 或者使用动态导入
import.defer("module-name3");
import(/* webpackDefer: true */ "module-name4");

export function f() {
  // module-name 被同步求值,然后对其调用 doSomething()。
  module.doSomething();
}

魔术注释(/* webpackDefer: true */)的限制

建议将魔术注释放在 from 关键字之后。其他位置可能有效,但尚未经过测试。

将魔术注释放在 import 关键字之后与文件系统缓存不兼容。

{/* eslint-skip */}

js 复制代码
import /* webpackDefer: true */ * as ns from "..."; // 已知不可用
import * as ns from /* webpackDefer: true */ "..."; // 推荐写法

你应该确保你的 loader 不会移除魔术注释。

TypeScript、Babel、SWC 和 Flow.js 可以配置为保留魔术注释。

Esbuild 兼容此功能(参见 evanw/esbuild#1439evanw/esbuild#309),但它可能会在将来支持此功能。

import.defer() 现在支持 ContextModule(导入路径是动态表达式)。参见懒加载指南中的示例。

experiments.sourceImport

启用 tc39 提案 Source Phase Imports 的支持。

该提案引入了一种在_源阶段_导入模块而不是立即对其求值的方式。在 webpack 中,此实验性支持目前针对 WebAssembly 模块实现:你首先获得一个已编译的 WebAssembly.Module,然后使用你自己的导入稍后对其进行实例化。对 JavaScript 源导入的支持计划在将来的版本中提供。

  • 类型:boolean

asyncWebAssembly 一起启用:

js 复制代码
// webpack.config.js
export default {
  // ...
  experiments: {
    asyncWebAssembly: true,
    sourceImport: true,
  },
};

然后使用静态或动态源阶段语法导入 .wasm

text 复制代码
// 静态形式
import source wasmModule from "./module.wasm";

// 动态形式
const wasmModule2 = await import.source("./module.wasm");

const instance = await WebAssembly.instantiate(wasmModule);

webpack 仓库中提供了完整示例:examples/wasm-simple-source-phase

experiments.futureDefaults

使用下一个主要版本的 webpack 默认值,并在有问题的位置显示警告。

webpack.config.js

js 复制代码
export default {
  // ...
  experiments: {
    futureDefaults: true,
  },
};

experiments.html

启用原生 HTML 模块支持。从 JavaScript 导入 .html 文件会将其标签引用经过常规的 webpack 管线处理,取代了 html-loader 多年来的角色。该标志在 NormalModuleFactory 上注册了 html 模块类型,并解锁了下面描述的 HTML 行为。

  • 类型:boolean | 'auto'
  • 默认值:false,自 webpack 5.109.0 起为 'auto'

自 webpack 5.109.0 起,该选项默认为 'auto':除非 module.rules 中已有带 loader(或显式模块类型)的规则匹配 .html 文件,否则启用内置 HTML 支持,因此现有的 html-loader 配置可以保持不变。experiments.futureDefaults 会将其解析为 true

webpack.config.js

js 复制代码
export default {
  // ...
  experiments: {
    html: true,
  },
};

然后从 JavaScript 导入 HTML 文件。默认导出是处理后的 HTML 字符串,所有资源引用都通过 webpack 解析:

js 复制代码
// src/index.js
import page from "./page.html";

document.documentElement.innerHTML = page;

W> 此功能是实验性的且不完整。 Webpack 5.107 实现了 html-loader 的角色:从 JS 导入 HTML 文件会将其标签引用经过 webpack 管线处理。自 5.108 起,.html 文件也可以用作入口,当启用此实验特性时,默认的 ./src 入口会解析到 index.html(参见下面的 HTML 作为默认入口)。与 html-webpack-plugin 的完全对等仍在进行中;整体工作跟踪在 issue #536 中。

T> HTML 解析器可以通过 module.parser.html 进行调优:使用 sources 禁用或自定义 URL 属性提取,使用 template 在解析之前转换 HTML 源。

内联 <style> 标签

HTML 模块中的内联 <style> 块会作为虚拟 CSS 模块(exportType: "text")经过 webpack 的 CSS 管线处理。url()@import 引用相对于 HTML 文件进行解析,处理后的 CSS 文本会写回生成的 HTML 字符串中原始的 <style> 标签内。

html 复制代码
<!-- src/page.html -->
<!doctype html>
<html>
  <head>
    <style>
      @import "./reset.css";

      body {
        background: url("./bg.png");
      }
    </style>
  </head>
  <body>
    ...
  </body>
</html>

<style type="text/css"> 和没有 type 属性的 <style> 会被处理。任何非 CSS 的 type 都会原样传递。

内联 <script> 标签

内联 <script> 主体会经过与 <script src> 相同的入口管线处理。每个 <script> 主体都会成为自己的 webpack 入口:经典的内部脚本以 CommonJS 形式打包,而 <script type="module"> 主体以 ESM 形式打包。生成的 HTML 中的标签会被重写为指向生成 chunk 的 <script src="…">,主体被清空。

html 复制代码
<!-- src/page.html -->
<!doctype html>
<html>
  <body>
    <script type="module">
      import { greet } from "./lib.js";
      greet("world");
    </script>

    <script>
      console.log("classic inline script");
    </script>
  </body>
</html>

适用于外部 <script src> 的相同行为在这里同样适用:

  • output.module 启用时,经典的内联 <script> 标签会自动升级为 type="module",与 <script src> 的自动升级行为一致。
  • webpackIgnore 也适用于内联 <script> 标签,会保留原始主体不变。
  • 非 JS 的 type 值(如 application/ld+jsonimportmap)会原样传递。

HTML 模块中的 <script src><link rel="modulepreload"> 引用会成为真正的 webpack 入口。生成的 chunk URL 会被重写回 HTML 字符串中,因此带哈希的文件名的工作方式与 JavaScript 导入相同。

html 复制代码
<!-- src/page.html -->
<!doctype html>
<html>
  <head>
    <link rel="modulepreload" href="./preloaded.js" />
  </head>
  <body>
    <script src="./entry.js"></script>
    <script src="./second.js"></script>
  </body>
</html>

需要注意的一些行为:

  • 同一页面上的多个 <script src> 标签共享同一个 runtime。在每个组(经典或 type="module")内,领头者持有 runtime,其余的声明在其上 dependOn
  • <link rel="modulepreload"> 入口保持独立,永远不会被兄弟脚本导入,从而保留"预加载但不执行"的语义。
  • output.module 启用时,经典的 <script src> 标签会自动升级为 <script type="module" src>,以便生成的 ES-module chunk 以正确的模式加载。
  • 非 JS 的脚本类型(application/ld+jsonimportmap 等)和数据 URI 会原样传递,不会作为 JS 打包。

webpackIgnore 魔术注释

在标签之前放置 HTML <!-- webpackIgnore: true --> 注释,会告诉 webpack 跳过对该标签的 srchrefsrcset 及类似属性的 URL 解析。完整的描述参见魔术注释

HTML 作为默认入口

当启用 experiments.html 时,.html 会被添加到默认的 resolve.extensions 中,排在 JavaScript 扩展名之前,因此像 entry: "./src" 这样的目录入口会解析到 ./src/index.html,即使 ./src/index.js 也存在。这使构建以 HTML 为先,类似于 Vite 或 Parcel。

js 复制代码
export default {
  experiments: { html: true },
  entry: "./src", // 解析到 ./src/index.html
};

experiments.css 启用时,.css 也会被追加到默认扩展名中,因此当没有匹配的 HTML 或 JS 时,默认入口可以回退到 ./src/index.css。只有在相应的实验特性开启时才会添加这些扩展名,因此默认构建保持不变。

热模块替换

HTML 模块支持热模块替换。无需额外配置。当 HMR 启用时(例如通过 devServer.hot),它会自动激活。

对于提取为真实 .html 文件的页面,每次热更新会在原地修补 document.body.innerHTMLdocument.title,而不是触发完全重新加载。对 <head> 中除 <title> 之外的更改(新的 <meta>、替换的 <link rel="icon"> 等)无法安全地进行 DOM 修补,因此 shim 会回退到完全重新加载页面。

T> 当 HMR 激活时,HTML 模块会禁用模块拼接,因为每个模块都需要自己的 module.hot 作用域来接受更新。

HtmlModulesPlugin 钩子

插件可以通过 webpack.html.HtmlModulesPlugin 注入和转换生成的 HTML,该插件暴露了 injectTagstransformTagstransformHtmlhtmlEmitted 编译钩子。参见 API 文档中的 HtmlModulesPlugin.getCompilationHooks

experiments.lazyCompilation

仅在入口点和动态 import 被使用时才编译它们。它既可以用于 Web,也可以用于 Node.js。

  • 类型

    • boolean

    • object

      ts 复制代码
      {
        // 定义自定义后端
        backend?: ((
          compiler: Compiler,
          callback: (err?: Error, api?: BackendApi) => void
        ) => void)
          | ((compiler: Compiler) => Promise<BackendApi>)
          | {
            /**
             * 自定义客户端。
             */
            client?: string;
      
            /**
             * 指定服务器监听的位置。
             */
            listen?: number | ListenOptions | ((server: Server) => void);
      
            /**
             * 指定客户端用于连接服务器的协议。
             */
            protocol?: "http" | "https";
      
            /**
             * 指定如何处理 EventSource 请求的服务器。
             */
            server?: ServerOptionsImport | ServerOptionsHttps | (() => Server);
          },
        entries?: boolean,
        imports?: boolean,
        test?: string | RegExp | ((module: Module) => boolean)
      }
      • backend:自定义后端。
      • entries:为入口启用懒编译。
      • imports :为动态导入启用懒编译。
      • test :指定哪些导入的模块应该被懒编译。
  • 可用版本:5.17.0+

  • 示例 1:

    js 复制代码
    export default {
      // …
      experiments: {
        lazyCompilation: true,
      },
    };
  • 示例 2:

    js 复制代码
    export default {
      // …
      experiments: {
        lazyCompilation: {
          // 为动态导入禁用懒编译
          imports: false,
    
          // 为入口禁用懒编译
          entries: false,
    
          // 不懒编译 moduleB
          test: (module) => !/moduleB/.test(module.nameForCondition()),
        },
      },
    };

experiments.outputModule

boolean

启用后,webpack 将尽可能输出 ECMAScript 模块语法。例如,使用 import() 加载 chunk,使用 ESM 导出暴露 chunk 数据等。

js 复制代码
export default {
  experiments: {
    outputModule: true,
  },
};

experiments.typescript

启用原生 TypeScript 支持。开启该标志后,webpack 可以直接编译 .ts.cts.mts 文件(以及匹配的 data:text/typescriptdata:application/typescript 数据 URI),无需任何外部 loader。在底层,它调用 Node.js 内置的 module.stripTypeScriptTypes

  • 类型:boolean | 'auto'
  • 默认值:false,自 webpack 5.109.0 起为 'auto'

自 webpack 5.109.0 起,该选项默认为 'auto':当运行的 Node.js 提供 module.stripTypeScriptTypes(>= 22.6)且 module.rules 中没有带 loader(例如 ts-loaderswc-loader)的规则匹配 .ts/.mts/.cts 文件时,启用内置 TypeScript 支持。experiments.futureDefaults 会将其解析为 true

W> 需要 Node.js >= 22.6 才能使用稳定的 module.stripTypeScriptTypes API。

js 复制代码
export default {
  experiments: {
    typescript: true,
  },
  entry: "./src/index.ts",
};

启用该标志还会配置一些合理的默认值:.ts / .cts / .mts 的默认规则、将 .ts 添加到扩展名解析中(在 .js 之前)、extensionAlias 使得 import "./foo.js" 也会尝试 ./foo.ts(以及 .cjs / .mjs.cts / .mts)、tsconfig.json 解析,以及 "typescript" 条件导出键,以便 monorepo 包可以通过 package.json#exports 发布 .ts 源码。

W> 该转换仅执行类型擦除。它不会进行类型检查,也不处理 JSX / .tsx 或不可擦除的 TypeScript 语法(enum、带有运行时成员的 namespace、参数属性构造函数、export =、装饰器元数据)。这些与 TypeScript 在 erasableSyntaxOnly tsconfig 选项中强制执行的约束相同。

对于类型检查,请将该标志与 tsc --noEmitfork-ts-checker-webpack-plugin 配合使用。对于 JSX 或不可擦除的 TypeScript 语法,请继续使用 ts-loaderswc-loader

webpack 仓库提供了两个参考示例:

帮助我们改进文档

发现翻译问题或内容错误?请告诉我们。