Output Config

本章节描述了 Builder 中与构建产物有关的配置。

output.assetPrefix

  • 类型: string
  • 默认值: '/'

在生产环境使用 CDN 部署时,可使用该选项设置静态资源的 URL 前缀。

assetPrefix 会影响构建产物中绝大部分静态资源的 URL,包括 JavaScript 文件、CSS 文件、图片、视频等。如果指定了一个错误的值,则在加载这些资源时可能会出现 404 错误。

该配置项仅用于生产环境。在开发环境下,请使用 dev.assetPrefix 配置项进行设置。

设置后,项目的 JavaScript、CSS、图片等静态资源的 URL 都会加上 output.assetPrefix 作为前缀:

示例

export default {
  output: {
    assetPrefix: 'https://cdn.example.com/assets/',
  },
};

构建之后,可以看到 JS 文件从以下地址加载:

<script
  defer
  src="https://cdn.example.com/assets/static/js/main.ebc4ff4f.js"
></script>

与原生配置的区别

output.assetPrefix 对应以下原生配置:

它与原生配置的区别在于:

  • output.assetPrefix 仅在生产环境下生效。

  • output.assetPrefix 默认会自动补全尾部的 /

  • output.assetPrefix 的值会写入 process.env.ASSET_PREFIX 环境变量。

output.assetsRetry

  • 类型: Object

output.assetsRetry 用于配置资源加载失败时的重试逻辑。配置类型如下:

export type AssetsRetryHookContext = {
  times: number;
  domain: string;
  url: string;
  tagName: string;
};

export type AssetsRetryOptions = {
  type?: string[];
  domain?: string[];
  max?: number;
  test?: string | ((url: string) => boolean);
  crossOrigin?: boolean | 'anonymous' | 'use-credentials';
  inlineScript?: boolean;
  onRetry?: (options: AssetsRetryHookContext) => void;
  onSuccess?: (options: AssetsRetryHookContext) => void;
  onFail?: (options: AssetsRetryHookContext) => void;
};

由于该能力会往 HTML 中注入额外的一些运行时代码,因此我们默认关闭了该能力,如果需要开启该能力,你可以添加以下配置:

export default {
  output: {
    assetsRetry: {},
  },
};

当你开启该能力后,assetsRetry 的默认配置如下:

export const defaultAssetsRetryOptions: AssetsRetryOptions = {
  type: ['script', 'link', 'img'],
  domain: [],
  max: 3,
  test: '',
  crossOrigin: false,
  onRetry: () => {},
  onSuccess: () => {},
  onFail: () => {},
};

同时你也可以使用以下的配置项,来定制你的重试逻辑。

assetsRetry.domain

  • 类型: string[]
  • 默认值: []

指定资源加载失败时的重试域名列表。在 domain 数组中,第一项是当前使用的域名,后面几项为备用域名。当某个域名的资源请求失败时,Builder 会在数组中找到该域名,并替换为数组的下一个域名。

比如:

export default {
  output: {
    assetsRetry: {
      domain: ['https://cdn1.com', 'https://cdn2.com', 'https://cdn3.com'],
    },
  },
};

添加以上配置后,当 cdn1.com 域名的资源加载失败时,请求域名会自动降级到 cdn2.com

如果 cdn2.com 的资源也请求失败,则会继续请求 cdn3.com

assetsRetry.type

  • 类型: string[]
  • 默认值: ['script', 'link', 'img']

用于指定需要进行重试的 HTML 标签类型。默认会处理 script 标签、link 标签和 img 标签,对应 JS 代码、CSS 代码和图片。

比如只对 script 标签和 link 标签进行处理:

export default {
  output: {
    assetsRetry: {
      type: ['script', 'link'],
    },
  },
};

assetsRetry.max

  • 类型: number
  • 默认值: 3

单个资源的最大重试次数。比如:

export default {
  output: {
    assetsRetry: {
      max: 5,
    },
  },
};

assetsRetry.test

  • 类型: string | ((url: string) => boolean) | undefined
  • 默认值: undefined

匹配资源 URL 的正则表达式或函数,默认匹配所有资源。比如:

export default {
  output: {
    assetsRetry: {
      test: /cdn\.example\.com/,
    },
  },
};

assetsRetry.crossOrigin

  • 类型: undefined | boolean | 'anonymous' | 'use-credentials'
  • 默认值: 与 html.crossorigin 一致

在发起资源重新请求时,Builder 会重新创建 <script> 标签,此选项可以设置这些标签的 crossorigin 属性。

默认情况下,assetsRetry.crossOrigin 的值会与 html.crossorigin 配置项保持一致,无须额外配置。如果你需要对重新创建的标签进行单独配置,可以使用该选项,比如:

export default {
  output: {
    assetsRetry: {
      crossOrigin: true,
    },
  },
};

assetsRetry.onRetry

  • 类型: undefined | (options: AssetsRetryHookContext) => void

资源重试时的回调函数。比如:

export default {
  output: {
    assetsRetry: {
      onRetry: ({ times, domain, url, tagName }) => {
        console.log(
          `Retry ${times} times, domain: ${domain}, url: ${url}, tagName: ${tagName}`,
        );
      },
    },
  },
};

assetsRetry.onSuccess

  • 类型: undefined | (options: AssetsRetryHookContext) => void

资源重试成功时的回调函数。比如:

export default {
  output: {
    assetsRetry: {
      onSuccess: ({ times, domain, url, tagName }) => {
        console.log(
          `Retry ${times} times, domain: ${domain}, url: ${url}, tagName: ${tagName}`,
        );
      },
    },
  },
};

assetsRetry.onFail

  • 类型: undefined | (options: AssetsRetryHookContext) => void

资源重试超过最大重试次数时的回调函数。比如:

export default {
  output: {
    assetsRetry: {
      onFail: ({ times, domain, url, tagName }) => {
        console.log(
          `Retry ${times} times, domain: ${domain}, url: ${url}, tagName: ${tagName}`,
        );
      },
    },
  },
};

assetsRetry.inlineScript

  • 类型: boolean
  • 默认值: true

是否将 assetsRetry 的运行时 JavaScript 代码内联到 HTML 文件中。

如果你不希望在 HTML 文件中插入相关代码,可以将 assetsRetry.inlineScript 设置为 false

export default {
  output: {
    assetsRetry: {
      inlineScript: false,
    },
  },
};

添加以上配置后,assetsRetry 的运行时代码会被抽取为一个独立的 assets-retry.[version].js 文件,并输出到产物目录下。

这种方式的弊端在于,assets-retry.[version].js 自身有加载失败的可能性。如果出现这种情况,静态资源重试的逻辑就无法生效。因此,我们更推荐将运行时代码内联到 HTML 文件中。

注意事项

当你使用 assetsRetry 时,Builder 会向 HTML 中注入一段运行时代码,并将 assetsRetry 配置的内容序列化,插入到这段代码中,因此你需要注意:

  • 避免在 assetsRetry 中配置敏感信息,比如内部使用的 token。
  • 避免在 onRetryonSuccessonFail 中引用函数外部的变量或方法。
  • 避免在 onRetryonSuccessonFail 中使用有兼容性问题的语法,因为这些函数会被直接内联到 HTML 中。

以下是一个错误示例:

import { someMethod } from 'utils';

export default {
  output: {
    assetsRetry: {
      onRetry() {
        // 错误用法,包含了敏感信息
        const privateToken = 'a-private-token';

        // 错误用法,使用了外部的方法
        someMethod(privateToken);
      },
    },
  },
};

使用限制

以下场景 assetsRetry 可能无法生效:

微前端应用

如果你的工程是微前端应用(比如 Garfish 子应用),那么 assetsRetry 可能无法生效,因为微前端子应用通常不是基于 <script> 标签直接加载的。

如果你需要对微前端场景的资源加载进行重试,请联系微前端框架的开发者,以寻找相应的解决方案。

动态 import 资源

目前 assetsRetry 无法对动态 import 资源生效,该功能正在支持中。

自定义模版中的资源

assetsRetry 通过监听页面 error 事件来获悉当前资源是否加载失败需要重试。因此,如果自定义模版中的资源执行早于 assetsRetry,那 assetsRetry 无法监听到该资源加载失败的事件,故无法 retry。

如果想要 assetsRetry 对自定义模版中的资源生效,可参考 自定义插入示例 来修改 html.inject 配置和自定义模版。

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>custom template</title>
+   <%= htmlWebpackPlugin.tags.headTags %>
    <script src="//example.com/assets/a.js"></script>
  </head>
  <body>
    <div id="root" />
+    <%= htmlWebpackPlugin.tags.bodyTags %>
  </body>
</html>

output.charset

  • 类型: 'ascii' | 'utf8'
  • 默认值: 'ascii'

默认情况下,Builder 的产物内容是纯 ASCII 的,并且会转义所有非 ASCII 字符。

如果不希望进行转义,而是输出所有原始字符,可以将 output.charset 设置为 utf8

export default {
  output: {
    charset: 'utf8',
  },
};

output.charsetutf8 时,Builder 会自动将 <meta charset="utf-8"> 添加到生成的 HTML 文件中。

output.cleanDistPath

  • 类型: boolean
  • 默认值: true

是否在构建开始前清理 dist 目录下的所有文件。

默认情况下,Builder 会自动清理 dist 目录下的文件,你可以把 cleanDistPath 设置为 false 来禁用该行为。

export default {
  output: {
    cleanDistPath: false,
  },
};

output.convertToRem

  • 类型: boolean | object
  • 默认值: false

通过设置 output.convertToRem,Builder 可进行如下处理:

  • 将 CSS 中的 px 转成 rem
  • 在 HTML 模版中插入运行时代码,对根元素 fontSize 进行设置

Boolean 类型

当设置 output.convertToRemtrue,将开启 rem 处理能力。

export default {
  output: {
    convertToRem: true,
  },
};

此时,rem 配置默认如下:

{
  enableRuntime: true,
  rootFontSize: 50,
  screenWidth: 375,
  rootFontSize: 50,
  maxRootFontSize: 64,
  widthQueryKey: '',
  excludeEntries: [],
  supportLandscape: false,
  useRootFontSizeBeyondMax: false,
  pxtorem: {
    rootValue: 50,
    unitPrecision: 5,
    propList: ['*'],
  }
}

Object 类型

output.convertToRem 的值为 object 类型时,Builder 会根据当前配置进行 rem 处理。

选项:

名称 类型 默认值 描述
enableRuntime boolean true 是否自动生成 runtime 代码来动态计算根元素字体大小
inlineRuntime boolean true 是否将 runtime 代码内联到 HTML 文件中。如果设置为 false,运行时代码会被抽取为一个独立的 convert-rem.[version].js 文件,并输出到产物目录下
rootFontSize number 50 根元素字体值
maxRootFontSize number 64 最大根元素字体值
widthQueryKey string '' 根据 widthQueryKey 的值去 url query 中取 client width
screenWidth number 375 UI 设计图宽度
excludeEntries string[] [] 设置不注入 runtime 代码的页面入口,通常需要配合 pxtorem.exclude 使用
supportLandscape boolean false 横屏时使用 height 计算 rem
useRootFontSizeBeyondMax boolean false 超过 maxRootFontSize 时,是否使用 rootFontSize
pxtorem object
  • rootValue。默认与 rootFontSize 相同
  • unitPrecision: 5。精确位数
  • propList: ['*']。支持转换的 CSS 属性
postcss-pxtorem 插件属性

示例

export default {
  output: {
    convertToRem: {
      rootFontSize: 30,
      excludeEntries: ['404', 'page2'],
      pxtorem: {
        propList: ['font-size'],
      },
    },
  },
};

output.copy

  • 类型: CopyPluginOptions | CopyPluginOptions['patterns']
  • 默认值: undefined

将指定的文件或目录拷贝到构建输出目录中。

例如,将 src/assets 下的文件直接拷贝到 dist 目录:

export default {
  output: {
    copy: [{ from: './src/assets', to: '' }],
  },
};

更详细的配置项请参考:copy-webpack-plugin 文档。

output.cssModules

  • 类型:
type CssModuleLocalsConvention =
  | 'asIs'
  | 'camelCase'
  | 'camelCaseOnly'
  | 'dashes'
  | 'dashesOnly';

type CssModules = {
  auto?: boolean | RegExp | ((resourcePath: string) => boolean);
  exportLocalsConvention?: CssModuleLocalsConvention;
};
  • 默认值:
const defaultCssModules = {
  exportLocalsConvention: 'camelCase',
};

自定义 CSS 模块配置。

cssModules.auto

auto 配置项允许基于文件名自动启用 CSS 模块。

  • 类型: boolean | RegExp | ((resourcePath: string) => boolean)

  • 默认值: undefined

类型说明:

  • undefined: 根据 output.disableCssModuleExtension 配置项决定为哪些样式文件启用 CSS 模块。
  • true: 为所有匹配 /\.module\.\w+$/i.test(filename) 正则表达式的文件启用 CSS 模块。
  • false: 禁用 CSS 模块。
  • RegExp: 为所有匹配 /RegExp/i.test(filename) 正则表达式的文件禁用 CSS 模块。
  • function: 为所有通过基于文件名的过滤函数校验的文件启用 CSS 模块。
export default {
  output: {
    cssModules: {
      auto: resource => {
        return resource.includes('.module.') || resource.includes('shared/');
      },
    },
  },
};

cssModules.exportLocalsConvention

导出的类名称的样式。

  • 类型: 'asIs' | 'camelCase' | 'camelCaseOnly' | 'dashes' | 'dashesOnly'

  • 默认值: 'camelCase'

类型说明:

  • asIs 类名将按原样导出。
  • camelCase 类名将被驼峰化,原始类名仍然可用。
  • camelCaseOnly 类名将被驼峰化,原始类名不可用。
  • dashes 只有类名中的破折号会被驼峰化,原始类名仍然可用。
  • dashesOnly 只有类名中的破折号会被驼峰化,原始类名不可用。
export default {
  output: {
    cssModules: {
      exportLocalsConvention: 'camelCaseOnly',
    },
  },
};

output.cssModuleLocalIdentName

  • 类型: string
  • 默认值:
// isProd 表示生产环境构建
const localIdentName = isProd
  ? '[local]-[hash:base64:6]'
  : '[path][name]__[local]-[hash:base64:6]';

设置 CSS Modules 编译后生成的 className 格式。

默认值

cssModuleLocalIdentName 在开发环境和生产环境有不同的默认值。

在生产环境,Builder 会生成更简短的类名,从而减少构建产物的体积。

import styles from './index.module.scss';

// 在开发环境下,值为 `.src-index-module__header--xxxxx`
// 在生产环境下,值为 `.xxxxx`
console.log(styles.header);

模板字符串

cssModuleLocalIdentName 中,你可以使用以下模板字符串:

  • [name] - 源文件名称。
  • [local] - 原始类名。
  • [hash] - 字符串的哈希值。
  • [folder] - 文件夹的相对路径。
  • [path] - 源文件的相对路径。
  • [file] - 文件名和路径。
  • [ext] - 文件后缀名,包含点号。
  • [hash:<hashDigest>:<hashDigestLength>] - 带有哈希设置的哈希。
TIP

在使用 Rspack 作为打包工具时, 暂不支持配置 <hashDigest>

示例

cssModuleLocalIdentName 设置为其他值:

export default {
  output: {
    cssModuleLocalIdentName: '[hash:base64:4]',
  },
};

output.dataUriLimit

  • 类型:
type DataUriLimitConfig = {
  svg?: number;
  font?: number;
  image?: number;
  media?: number;
};
  • 默认值:
const defaultDatUriLimit = {
  svg: 10000,
  font: 10000,
  image: 10000,
  media: 10000,
};

设置图片、字体、媒体等静态资源被自动内联为 base64 的体积阈值。

默认情况下,体积小于 10KB 的图片、字体、媒体等文件,会自动经过 Base64 编码,内联到页面中,不再会发送独立的 HTTP 请求。

你可以通过修改 dataUriLimit 参数来调整这个阈值。

其中:

  • svg:表示 SVG 图片的体积阈值。
  • font:表示字体文件的体积阈值。
  • image:表示非 SVG 图片的体积阈值。
  • media:表示视频等媒体资源的体积阈值。

示例

修改图片资源的阈值为 5000 Bytes,设置视频资源不内联:

export default {
  output: {
    dataUriLimit: {
      image: 5000,
      media: 0,
    },
  },
};

output.disableCssExtract

  • 类型: boolean
  • 默认值: false

是否禁用 CSS 提取逻辑,并将 CSS 文件内联到 JS 文件中。

默认情况下,Builder 会把 CSS 提取为独立的 .css 文件,并输出到构建产物目录。设置该选项为 true 后,CSS 文件会被内联到 JS 文件中,并在运行时通过 <style> 标签插入到页面上。

示例

export default {
  output: {
    disableCssExtract: true,
  },
};

output.disableCssModuleExtension

  • 类型: boolean
  • 默认值: false

是否将源码目录下的所有样式文件当做 CSS Modules 模块进行处理。

在默认情况下,只有 *.module.css 结尾的文件才被视为 CSS Modules 模块。开启该配置项之后,会将源码目录下的所有 *.css 样式文件当做 CSS Modules 模块。

.sass.scss.less 文件的处理规则与 .css 文件一致,也会受到 disableCssModuleExtension 的影响。

TIP

我们不推荐开启此配置项,因为开启 disableCssModuleExtension 后,CSS Modules 文件和普通 CSS 文件无法得到明确的区分,不利于长期维护。

示例

export default {
  output: {
    disableCssModuleExtension: true,
  },
};

规则

以下是对 CSS Modules 判断规则的详细解释:

未开启 disableCssModuleExtension(默认)

以下文件会视为 CSS Modules:

  • 所有 *.module.css 文件

以下文件会视为普通 CSS:

  • 所有 *.css 文件(不含 .module
  • 所有 *.global.css 文件

开启 disableCssModuleExtension

以下文件会视为 CSS Modules:

  • 源码目录下的 *.css*.module.css 文件
  • node_modules 下的 *.module.css 文件

以下文件会视为普通 CSS:

  • 所有 *.global.css 文件
  • node_modules 下的 *.css 文件(不含 .module
TIP

对于 node_modules 中的 CSS Modules 文件,请始终使用 *.module.css 后缀。

output.distPath

  • 类型:
type DistPathConfig = {
  root?: string;
  html?: string;
  js?: string;
  css?: string;
  svg?: string;
  font?: string;
  wasm?: string;
  image?: string;
  media?: string;
  server?: string;
  worker?: string;
};
  • 默认值:
const defaultDistPath = {
  root: 'dist',
  html: 'html',
  js: 'static/js',
  css: 'static/css',
  svg: 'static/svg',
  font: 'static/font',
  wasm: 'static/wasm',
  image: 'static/image',
  media: 'static/media',
  server: 'bundles',
  worker: 'worker',
};

设置构建产物的输出目录,Builder 会根据产物的类型输出到对应的子目录下。

其中:

  • root: 表示所有构建产物输出的根目录。
  • html:表示 HTML 文件的输出目录。
  • js:表示 JavaScript 文件的输出目录。
  • css:表示 CSS 样式文件的输出目录。
  • svg:表示 SVG 图片的输出目录。
  • font:表示字体文件的输出目录。
  • wasm:表示 WebAssembly 文件的输出目录。
  • image:表示非 SVG 图片的输出目录。
  • media:表示视频等媒体资源的输出目录。
  • server: 表示服务端产物的输出目录,仅在 target 为 node 时有效。
  • worker: 表示 worker 产物的输出目录,仅在 target 为 service-worker 时有效。

根目录

root 是构建产物的根目录,可以为相对路径或绝对路径。如果 root 的值为相对路径,则会基于当前项目的根目录拼接为绝对路径。

其他目录只能为相对路径,并且会相对于 root 进行输出。

示例

以 JavaScript 文件为例,会输出到 distPath.root + distPath.js 目录,即为 dist/static/js

如果需要将 JavaScript 文件输出到 build/resource/js 目录,可以这样设置:

export default {
  output: {
    distPath: {
      root: 'build',
      js: 'resource/js',
    },
  },
};

output.disableMinimize

  • 类型: boolean
  • 默认值: false

是否禁用生产环境下的代码压缩。

默认情况下,JS 代码和 CSS 代码会在生产环境构建时被自动压缩,从而提升页面性能。如果你不希望执行代码压缩,可以将 disableMinimize 设置为 true

export default {
  output: {
    disableMinimize: true,
  },
};
TIP

该配置项通常用于代码调试和问题排查,不建议在生产环境禁用代码压缩,否则会导致页面性能显著下降。

output.disableSourceMap

  • 类型:
type DisableSourceMap =
  | boolean
  | {
      js?: boolean;
      css?: boolean;
    };
  • 默认值:
const defaultDisableSourceMap = {
  js: false,
  css: process.env.NODE_ENV === 'production',
};

是否禁用 Source Map 生成。

什么是 Source Map

Source Map 是保存源代码映射关系的信息文件,它记录了编译后的代码的每一个位置,以及所对应的编译前的位置。通过 Source Map,可以在调试编译后的代码时,直接查看对应的源代码。

默认情况下,Builder 的 Source Map 生成规则如下:

  • 在开发环境构建时,会生成 JS 文件和 CSS 文件的 SourceMap,便于进行开发调试。
  • 在生产环境构建时,会生成 JS 文件的 Source Map,用于调试和排查线上问题;不会生成 CSS 文件的 Source Map。

如果项目不需要 Source Map,可以关闭该功能,从而提升构建的速度。

export default {
  output: {
    disableSourceMap: true,
  },
};

如果需要开启开发环境的 Source Map,并在生产环境禁用,可以设置为:

export default {
  output: {
    disableSourceMap: process.env.NODE_ENV === 'production',
  },
};

如果需要单独控制 JS 文件或 CSS 文件的 Source Map,可以参考下方设置:

export default {
  output: {
    disableSourceMap: {
      js: false,
      css: true,
    },
  },
};

output.disableSvgr

  • 类型: boolean
  • 默认值: false

是否调用 SVGR 将 SVG 转化为 React 组件。如果设置为 true,将把所有的.svg 文件视为资源处理。

默认情况下,在 JS 文件中引用 SVG 资源时,Builder 会调用 SVGR,将 SVG 图片转换为一个 React 组件。 如果你确定项目内的所有 SVG 资源都没有当成 React 组件使用时,可以通过将 disableSvgr 设置为 true 来关闭此项转换,以提升构建性能。

export default {
  output: {
    disableSvgr: true,
  },
};

output.disableTsChecker

  • 类型: boolean
  • 默认值: false

是否禁用编译过程中的 TypeScript 类型检查。

默认情况下,Builder 执行构建的过程中,会在一个独立的进程里运行 TypeScript 类型检查工具,它的检查逻辑与 TypeScript 原生的 tsc 命令一致,你可以通过 tsconfig.json 或是 Builder 的 tools.tsChecker 配置项来自定义检查行为。

阻塞编译

  • 在开发环境构建时,类型错误不会阻塞编译流程。
  • 在生产环境构建时,类型错误会导致构建失败,以保证生产环境代码的稳定性。

示例

禁用 TypeScript 类型检查:

export default {
  output: {
    disableTsChecker: true,
  },
};

禁用开发环境构建时的类型检查:

export default {
  output: {
    disableTsChecker: process.env.NODE_ENV === 'development',
  },
};

禁用生产环境构建时的类型检查:

export default {
  output: {
    disableTsChecker: process.env.NODE_ENV === 'production',
  },
};
TIP

不建议在生产环境构建时禁用类型检查,这会导致线上代码的稳定性下降,请谨慎使用。

output.disableFilenameHash

  • 类型: boolean
  • 默认值: false

移除生产环境的构建产物名称中的 hash 值。

在生产环境构建后,会自动在文件名中间添加 hash 值,如果不需要添加,可以通过 output.disableFilenameHash 配置来禁用该行为。

WARNING

Deprecated:该配置已废弃,请使用 output.filenameHash 的布尔用法代替。

示例

默认情况下,构建后的产物名称为:

File                                     Size         Gzipped
dist/static/css/187.7879e19d.css         126.99 KB    9.17 KB
dist/static/js/main.18a568e5.js          2.24 KB      922 B

添加 output.disableFilenameHash 配置:

export default {
  output: {
    disableFilenameHash: true,
  },
};

重新构建,产物的名称变为:

File                            Size         Gzipped
dist/static/css/187.css         126.99 KB    9.17 KB
dist/static/js/main.js          2.24 KB      922 B

output.disableInlineRuntimeChunk

  • 类型: boolean
  • 默认值: false

用于控制是否将打包工具的 runtime 代码内联到 HTML 中。

什么是 runtimeChunk

当 Builder 构建完成后,会在 dist 目录生成 builder-runtime.js 文件,该文件为 webpack 或 Rspack 的 runtime 代码,即 runtimeChunk。

runtimeChunk 是一段运行时代码,它由 webpack 或 Rspack 提供,包含必要的模块处理逻辑,比如模块加载、模块解析等,具体可参考 Runtime

在生产环境下,Builder 默认会将 runtimeChunk 文件内联到 HTML 文件中,而不是写到产物目录中,这样做是为了减少文件请求的数量。

禁用内联

如果你不希望 runtimeChunk 文件被内联到 HTML 文件里,可以把 disableInlineRuntimeChunk 设置为 true,此时会生成一个独立的 builder-runtime.js 文件。

export default {
  output: {
    disableInlineRuntimeChunk: true,
  },
};

合并到页面文件中

如果你不希望生成独立的 runtimeChunk 文件,而是想让 runtimeChunk 代码被打包到页面的 JS 文件里,可以这样设置:

export default {
  tools: {
    bundlerChain(chain) {
      chain.optimization.runtimeChunk(false);
    },
  },
};

output.enableAssetManifest

  • 类型: boolean
  • 默认值: false

是否生成 manifest 文件,该文件包含所有构建产物的信息。

示例

添加以下配置来开启:

export default {
  output: {
    enableAssetManifest: true,
  },
};

开启后,当编译完成时,会自动生成 dist/asset-manifest.json 文件:

{
  "files": {
    "main.css": "/static/css/main.45b01211.css",
    "main.js": "/static/js/main.52fd298f.js",
    "html/main/index.html": "/html/main/index.html"
  },
  "entrypoints": ["static/css/main.45b01211.css", "static/js/main.52fd298f.js"]
}

如果当前项目有多种类型构建产物,比如包含了 SSR 构建产物,那么会生成多份 manifest.json 文件。

  • web 产物:asset-manifest.json

  • node 产物:asset-manifest-node.json

output.enableAssetFallback

  • 类型: boolean
  • 默认值: false

开启该选项后,当编译过程中遇到无法识别的文件类型时,会直接将该文件直接输出到产物目录;否则会抛出一个异常。

示例

开启配置项:

export default {
  output: {
    enableAssetFallback: true,
  },
};

在代码中引用一个未知类型的模块:

import './foo.xxx';

编译后,foo.xxx 会被自动输出到 dist/static/media 目录下。

你可以通过 output.distPath.mediaoutput.filename.media 配置项来控制 fallback 后的输出路径和文件名称。

TIP

开启该配置会导致 webpack 配置中的 rules 结构变化,增加一层额外的 oneOf 嵌套结构。大多数情况下,我们不推荐你使用此配置。

output.enableLatestDecorators

  • 类型: boolean
  • 默认值: false

是否要使用 新版 decorator 提案 进行编译。

默认情况下,Builder 在编译装饰器时采用 旧版 decorator 提案

output.enableLatestDecorators 设置为 true 时,Builder 会采用新版 decorator 提案 (2018-09 版本) 进行编译。

WARNING

Deprecated:该配置已废弃,请使用 source.decorators 配置项代替。

export default {
  output: {
    enableLatestDecorators: true,
  },
};

output.enableCssModuleTSDeclaration

  • 类型: boolean
  • 默认值: false

是否生成 CSS Modules 的 TypeScript 声明文件。

Example

启用 CSS Module TypeScript 声明,比如:

export default {
  output: {
    enableCssModuleTSDeclaration: true,
  },
};

项目构建完成后,每个 CSS Module 文件都会生成一个 .d.ts 文件。例如:

interface CssExports {
  title: string;
}
export const cssExports: CssExports;
export default cssExports;

output.enableInlineScripts

  • 类型:
type EnableInlineScripts =
  | boolean
  | RegExp
  | ((params: { size: number; name: string }) => boolean);
  • 默认值: false

用来控制生产环境中是否用 <script> 标签将产物中的 script 文件(.js 文件)inline 到 HTML 中。

注意,如果开启了这个选项,那么 script 文件将不会被写入产物目录中,而只会以 inline 脚本的形式存在于 HTML 文件中。

TIP

当使用约定式路由时,如果开启了这个选项,需要将 output.splitRouteChunks 设置为 false。

示例

默认情况下,我们有这样的产物文件:

dist/html/main/index.html
dist/static/css/style.css
dist/static/js/main.js

开启 output.enableInlineScripts 选项后:

export default {
  output: {
    enableInlineScripts: true,
  },
};

产物文件将变成:

dist/html/main/index.html
dist/static/css/style.css

同时,dist/static/js/main.js 文件将被 inline 到 index.html 中:

<html>
  <body>
    <script>
      // content of dist/static/js/main.js
    </script>
  </body>
</html>

通过正则匹配

当你需要内联产物中的一部分 JS 文件时,你可以将 enableInlineScripts 设置为一个正则表达式,匹配需要内联的 JS 文件的 URL。

比如,将产物中的 main.js 内联到 HTML 中,你可以添加如下配置:

export default {
  output: {
    enableInlineScripts: /\/main\.\w+\.js$/,
  },
};
TIP

生产环境的文件名中默认包含了一个 hash 值,比如 static/js/main.18a568e5.js。因此,在正则表达式中需要通过 \w+ 来匹配 hash。

通过函数匹配

你也可以将 output.enableInlineScripts 设置为一个函数,函数接收以下参数:

  • name:文件名,比如 static/js/main.18a568e5.js
  • size:文件大小,单位为 byte。

比如,我们希望内联小于 10KB 的资源,可以添加如下配置:

export default {
  output: {
    enableInlineScripts({ size }) {
      return size < 10 * 1000;
    },
  },
};

output.enableInlineStyles

  • 类型:
type EnableInlineStyles =
  | boolean
  | RegExp
  | ((params: { size: number; name: string }) => boolean);
  • 默认值: false

用来控制生产环境中是否用 <style> 标签将产物中的 style 文件(.css 文件)inline 到 HTML 中。

注意,如果开启了这个选项,那么 style 文件将不会被写入产物目录中,而只会以 inline 样式的形式存在于 HTML 文件中。

TIP

当使用约定式路由时,如果开启了这个选项,需要将 output.splitRouteChunks 设置为 false。

示例

默认情况下,我们有这样的产物文件:

dist/html/main/index.html
dist/static/css/style.css
dist/static/js/main.js

开启 output.enableInlineStyles 选项后:

export default {
  output: {
    enableInlineStyles: true,
  },
};

产物文件将变成:

dist/html/main/index.html
dist/static/js/main.js

同时,dist/static/css/style.css 文件将被 inline 到 index.html 中:

<html>
  <head>
    <style>
      /* content of dist/static/css/style.css */
    </style>
  </head>
  <body></body>
</html>

通过正则匹配

当你需要内联产物中的一部分 CSS 文件时,你可以将 enableInlineStyles 设置为一个正则表达式,匹配需要内联的 CSS 文件的 URL。

比如,将产物中的 main.css 内联到 HTML 中,你可以添加如下配置:

export default {
  output: {
    enableInlineStyles: /\/main\.\w+\.css$/,
  },
};
TIP

生产环境的文件名中默认包含了一个 hash 值,比如 static/css/main.18a568e5.css。因此,在正则表达式中需要通过 \w+ 来匹配 hash。

通过函数匹配

你也可以将 output.enableInlineStyles 设置为一个函数,函数接收以下参数:

  • name:文件名,比如 static/css/main.18a568e5.css
  • size:文件大小,单位为 byte。

比如,我们希望内联小于 10KB 的资源,可以添加如下配置:

export default {
  output: {
    enableInlineStyles({ size }) {
      return size < 10 * 1000;
    },
  },
};

output.externals

  • 类型: string | object | function | RegExp
  • 默认值: undefined

在构建时,防止将代码中某些 import 的依赖包打包到 bundle 中,而是在运行时再去从外部获取这些依赖。

详情请见: webpack 外部扩展 (Externals)

示例

react-dom 依赖从构建产物中剔除。为了在运行时获取这个模块, react-dom 的值将全局检索 ReactDOM 变量。

export default {
  output: {
    externals: {
      'react-dom': 'ReactDOM',
    },
  },
};
TIP

当构建 Web Worker 产物时,externals 将不会生效。这是因为 Worker 环境不支持通过访问全局变量。

output.filename

  • 类型:
type FilenameConfig = {
  js?: string;
  css?: string;
  svg?: string;
  font?: string;
  image?: string;
  media?: string;
};
  • 默认值:
// 开发环境
const devDefaultFilename = {
  js: '[name].js',
  css: '[name].css',
  svg: '[name].[contenthash:8].svg',
  font: '[name].[contenthash:8][ext]',
  image: '[name].[contenthash:8][ext]',
  media: '[name].[contenthash:8][ext]',
};

// 生产环境
const prodDefaultFilename = {
  js: '[name].[contenthash:8].js',
  css: '[name].[contenthash:8].css',
  svg: '[name].[contenthash:8].svg',
  font: '[name].[contenthash:8][ext]',
  image: '[name].[contenthash:8][ext]',
  media: '[name].[contenthash:8][ext]',
};

设置构建产物的名称。

在生产环境构建后,会自动在文件名中间添加 hash 值,如果不需要添加,可以通过 output.disableFilenameHash 配置来禁用该行为。

下面是各个文件类型的说明:

  • js:表示 JavaScript 文件的名称。
  • css:表示 CSS 样式文件的名称。
  • svg:表示 SVG 图片的名称。
  • font:表示字体文件的名称。
  • image:表示非 SVG 图片的名称。
  • media:表示视频等媒体资源的名称。

示例

修改 JavaScript 文件的名称为 [name]_script.js

export default {
  output: {
    filename: {
      js:
        process.env.NODE_ENV === 'production'
          ? '[name]_script.[contenthash:8].js'
          : '[name]_script.js',
    },
  },
};
文件名中的 hash 值

通常来说,我们只会在生产环境下设置文件名的 hash 值(即 process.env.NODE_ENV === 'production' 时)。

如果你在开发环境下设置了文件名的 hash,那么可能会导致热更新不生效(尤其是 CSS 文件)。这是因为每次文件内容变化时,都会引起 hash 变化,导致 mini-css-extract-plugin 等工具无法读取到最新的文件内容。

异步模块的文件名

当你在代码中通过 dynamic import 的方式引入模块时,该模块会被单独打包成一个文件,它默认的命名规则如下:

  • 在开发环境下会基于模块路径生成名称,比如 dist/static/js/async/src_add_ts.js
  • 在生产环境下会是一个随机的数字 id,比如 dist/static/js/async/798.27e3083e.js,这是为了避免在生产环境中泄露源代码的路径,同时字符数也更少。
src/index.ts
const { add } = await import('./add.ts');

如果你希望为异步模块指定一个固定的名称,可以通过打包工具提供的 magic comments 来实现,通过 webpackChunkName 指定模块名称:

src/index.ts
const { add } = await import(
  /* webpackChunkName: "my-chunk-name" */ './add.ts'
);

通过以上写法指定模块名称后,生成的文件会是 dist/static/js/async/my-chunk-name.js

output.legalComments

  • 类型: 'linked' | 'inline' | 'none'
  • 默认值: 'linked'

配置 legal comment 的处理方式。

legal comment 是 JS 或 CSS 文件中的一些特殊注释,这些注释包含 @license@preserve,或是以 //! 开头。默认情况下,这些注释保留在输出文件中,因为这遵循了代码原作者的意图。

你可以通过 legalComments 来配置相关行为:

  • linked:将所有 legal comments 移至 .LEGAL.txt 文件并通过注释链接到它们。
  • inline:保留所有 legal comments。
  • none:移除所有 legal comments。

示例

移除所有 legal comments。

export default {
  output: {
    legalComments: 'none',
  },
};

output.overrideBrowserslist

  • 类型: string[] | Record<BuilderTarget, string[]>
  • 默认值: undefined

指定项目兼容的目标浏览器范围。该值会被 @babel/preset-envautoprefixer 用来确定需要转换的 JavaScript 语法特性和需要添加的 CSS 浏览器前缀。

优先级

overrideBrowserslist 配置的优先级高于项目中的 .browserslistrc 配置文件和 package.json 中的 browserslist 字段。

大多数场景下,推荐优先使用 .browserslistrc 文件,而不是使用 overrideBrowserslist 配置。因为 .browserslistrc 文件是官方定义的配置文件,通用性更强,可以被社区中的其他库识别。

默认值

如果项目中没有定义任何 browserslist 相关的配置,也没有定义 overrideBrowserslist,那么 Builder 会设置默认值为:

['> 0.01%', 'not dead', 'not op_mini all'];

示例

下面是兼容移动端 H5 场景的示例:

export default {
  output: {
    overrideBrowserslist: [
      'iOS >= 9',
      'Android >= 4.4',
      'last 2 versions',
      '> 0.2%',
      'not dead',
    ],
  },
};

可以查看 browserslist 文档 来了解如何自定义浏览器范围。

根据产物类型设置

当你同时构建多种类型的产物时,你可以为不同的产物类型设置不同的目标浏览器范围。此时,你需要把 overrideBrowserslist 设置为一个对象,对象的 key 为对应的产物类型。

比如为 webnode 设置不同的范围:

export default {
  output: {
    overrideBrowserslist: {
      web: [
        'iOS >= 9',
        'Android >= 4.4',
        'last 2 versions',
        '> 0.2%',
        'not dead',
      ],
      node: ['node >= 14'],
    },
  },
};

output.polyfill

  • 类型: 'entry' | 'usage' | 'ua' | 'off'
  • 默认值: 'entry'

通过 output.polyfill 你可以配置 Polyfill 的注入方式。

配置项

entry

output.polyfill 配置为 'entry' 时,会在每个入口文件中注入 Polyfill。

等价于 @babel/preset-envuseBuiltIns: 'entry' 配置。

usage

output.polyfill 配置为 'usage' 时,会在每个文件中根据代码中使用的 API 注入 Polyfill。

等价于 @babel/preset-envuseBuiltIns: 'usage' 配置。

ua

根据当前请求的 UA 信息,动态下发 Polyfill 代码。

动态下发能力需要与上层框架结合使用,详情可参考 Modern.js - 运行时按需 Polyfill

off

不注入 Polyfill。使用此选项时,需要自行保证代码的兼容性。

output.svgDefaultExport

  • 类型: 'url' | 'component'
  • 默认值: 'url'

output.svgDefaultExport 可以用来配置 SVG 文件的默认导出。

output.svgDefaultExport 配置为 url 时,SVG 文件的默认导出是文件的 URL。例如:

import logo from './logo.svg';

console.log(logo); // => 资源 url

output.svgDefaultExport 配置为 component 时,SVG 文件的默认导出是文件的 React 组件。例如:

import Logo from './logo.svg';

console.log(Logo); // => React 组件

此时,你也可以通过指定 ?url 的 query 来导入 url,比如:

import logo from './logo.svg?url';

console.log(logo); // => 资源 url