buildConfig
buildConfig 是一个用来描述如何编译、生成构建产物的配置项,它包含了构建的所有配置。
TIP
在开始使用 buildConfig 之前,请先阅读以下文档来了解其作用:
alias
- 类型:Record<string, string> | Function
- 默认值:{'@': 'src',}
TIP
对于 TypeScript 项目,只需要在 tsconfig.json 中配置 compilerOptions.paths, Modern.js Module 会自动识别 tsconfig.json 里的别名,因此不需要额外配置 alias 字段。
modern.config.ts
export default defineConfig({
  buildConfig: {
    alias: {
      '@common': './src/common',
    },
  },
});
以上配置完成后,如果在代码中引用 @common/Foo.tsx, 则会映射到 <project>/src/common/Foo.tsx 路径上。
alias 的值定义为函数时,可以接受预设的 alias 对象,并对其进行修改。
modern.config.ts
export default defineConfig({
  buildConfig: {
    alias: alias => {
      alias['@common'] = './src/common';
    },
  },
});
也可以在函数中返回一个新对象作为最终结果,新对象会覆盖预设的 alias 对象。
modern.config.ts
export default defineConfig({
  buildConfig: {
    alias: alias => {
      return {
        '@common': './src/common',
      };
    },
  },
});
asset
包含静态资源相关的配置。
asset.name
静态资源输出文件名。
- 类型: string | ((assetPath) => name)
- 默认值: [name].[hash].[ext]
当 asset.name 为 string 类型时,会自动对 [name]、[ext]、[hash] 进行替换,分别替换为文件名、拓展名、文件 hash。
如果想要更高的自由度,可以把 asset.name 作为方法使用,返回值即为文件名。此时,该方法接收一个参数 assetPath,对应资源路径。
modern.config.ts
export default defineConfig({
  buildConfig: {
    asset: {
      // no hash
      name: [name].[ext],
      // any logic
      // name: (assetPath) => 'any.png',
    },
  },
});
asset.limit
用于设置静态资源被自动内联为 base64 的体积阈值。
Modern.js Module 在进行打包时,默认会内联体积小于 10KB 的图片、字体、媒体等资源,将它们通过 Base64 编码,并内联到产物中,不再会发送独立的 HTTP 请求。
你可以通过修改 limit 参数来调整这个阈值。
- 类型: number
- 默认值: 10 * 1024
例如,将 limit 设置为 0 来避免资源内联:
modern.config.ts
export default defineConfig({
  buildConfig: {
    asset: {
      limit: 0,
    },
  },
});
asset.path
静态资源输出路径,会基于 outDir 进行输出。
asset.publicPath
打包时给未内联资源的 CDN 前缀。
- 类型: string
- 默认值: undefined
modern.config.ts
export default defineConfig({
  buildConfig: {
    asset: {
      publicPath: 'https://xxx/',
    },
  },
});
此时,所有静态资源都会添加 https://xxx/ 前缀。
asset.svgr
打包时将 SVG 作为一个 React 组件处理,options 参考 svgr,另外还支持了 include 和 exclude 两个配置项,用于匹配需要处理的 SVG 文件。
- 类型: boolean | object
- 默认值: false
开启 svgr 功能后,可以使用默认导出的方式将 SVG 当做组件使用。
index.ts
// true
import Logo from './logo.svg';
export default () => <Logo />;
当开启功能后,可以新建一个类型描述文件,并在 modern-app-env.d.ts 文件中增加,修改使用 SVG 的类型:
your-app-env.d.ts
declare module '*.svg' {
  const src: React.FunctionComponent<React.SVGProps<SVGSVGElement>>;
  export default src;
}
modern-app-env.d.ts
/// <reference path='./your-app-env.d.ts' />
/// <reference types='@modern-js/module-tools/types' />
asset.svgr.include
设定匹配的 SVG 文件
- 类型: string | RegExp | (string | RegExp)[]
- 默认值: /\.svg$/
asset.svgr.exclude
设定不匹配的 SVG 文件
- 类型: string | RegExp | (string | RegExp)[]
- 默认值: undefined
asset.svgr.exportType
用于配置使用 SVGR 时 SVG 的导出形式。
- 类型: 'named' | 'default'
- 默认值: default
当此选项设置为 'named' 时,你可以使用以下语法导入组件:
index.ts
import { ReactComponent } from './logo.svg';
命名导出默认为 ReactComponent,并可以通过 asset.svgr.namedExport 进行自定义。
autoExtension
根据 format 和 type 自动添加产物里 js 文件和类型描述文件的后缀。
- 类型:boolean
- 默认值:false
- 版本:>=2.38.0
关闭时,js 产物后缀为 .js,类型描述文件后缀为 d.ts。
开启后,当 type 为 module 时,node 默认将 .js 作为 esm 加载,因此当我们要输出 cjs 产物时,js 产物后缀为 .cjs,类型描述文件后缀为 d.cts;
反之,如果缺少 type 字段或者 type 为 commonjs 时, node 默认将 .js 文件作为 cjs 加载,因此当我们要输出 esm 产物时,js 产物后缀为 .mjs,类型描述文件后缀为 d.mts。
WARNING
在 bundleless 模式下使用时,我们会有一步额外的操作,那就是处理每个文件里的 import/export 语句。我们会给相对路径加上 js 文件后缀,可能是 .mjs 或者 .cjs,这取决于你的包配置,此行为可以通过 redirect.autoExtension关闭。
注意 noUselessIndex 规则会破坏此行为,你需要禁用此规则
如果你需要在 bundleless 使用此配置,请补齐 index,例如 utils 是一个文件夹, 你需要将 import * from './utils' 改写为 import * from './utils/index'
modern.config.ts
export default defineConfig({
  buildConfig: {
    autoExtension: true,
  },
});
autoExternal
自动外置项目的 "dependencies" 和 "peerDependencies",不会将其打包到最终的 bundle 产物中。
- 类型: boolean | object
- 默认值: true
当我们希望关闭对于第三方依赖的默认处理行为时候,可以通过以下方式来实现:
modern.config.ts
export default defineConfig({
  buildConfig: {
    autoExternal: false,
  },
});
这样对于 "dependencies" 和 "peerDependencies" 下面的依赖都会进行打包处理。如果只想要关闭其中某个下面的依赖处理,则可以使用
buildConfig.autoExternal 的对象形式:
modern.config.ts
export default defineConfig({
  buildConfig: {
    autoExternal: {
      dependencies: false,
      peerDependencies: false,
    },
  },
});
autoExternal.dependencies
是否需要外置项目的 "dependencies" 依赖。
autoExternal.peerDependencies
是否需要外置项目的 "peerDependencies" 依赖。
banner
提供为每个 JS , CSS 和 DTS 文件的顶部和底部注入内容的能力。
interface BannerAndFooter {
  js?: string;
  css?: string;
  dts?: string;
}
- 类型: BannerAndFooter
- 默认值: {}
- 版本: >=2.36.0
例如你想为 JS 和 CSS 文件添加版权信息:
import { moduleTools, defineConfig } from '@modern-js/module-tools';
const copyRight = `/*
 © Copyright 2020 example.com or one of its affiliates.
 * Some Sample Copyright Text Line
 * Some Sample Copyright Text Line
*/`;
export default defineConfig({
  plugins: [moduleTools()],
  buildConfig: {
    banner: {
      js: copyRight,
      css: copyRight,
    },
  },
});
buildType
构建类型,bundle 会打包你的代码,bundleless 只做代码的转换。
- 类型: 'bundle' | 'bundleless'
- 默认值: 'bundle'
copy
将文件或目录拷贝到指定位置。
modern.config.ts
export default defineConfig({
  buildConfig: {
    copy: {
      patterns: [{ from: './src/assets', to: '' }],
    },
  },
});
copy.patterns
- 类型: CopyPattern[]
- 默认值: []
interface CopyPattern {
  from: string;
  to?: string;
  context?: string;
  globOptions?: globby.GlobbyOptions;
}
copy.options
type Options = {
  concurrency?: number;
  enableCopySync?: boolean;
};
- 
默认值: { concurrency: 100, enableCopySync: false }
 
- 
concurrency: 指定并行执行多少个复制任务。
 
- 
enableCopySync: 使用fs.copySync,默认情况下fs.copy。
 
define
定义全局变量,注入到代码中
- 类型: Record<string, string>
- 默认值: {}
由于 define 功能是由全局文本替换实现的,所以需要保证全局变量值为字符串,更为安全的做法是将每个全局变量的值转化为字符串,如下所示:
modern.config.ts
export default defineConfig({
  buildConfig: {
    define: {
      VERSION: require('./package.json').version || '0.0.0',
    },
  },
});
不过要注意:如果项目是一个 TypeScript 项目,那么你可能需要在项目源代码目录下的 .d.ts 文件里增加以下内容:
如果不存在 d.ts 文件,则可以手动创建。
env.d.ts
declare const YOUR_ADD_GLOBAL_VAR;
我们也可以进行环境变量替换:
import { defineConfig } from '@modern-js/module-tools';
export default defineConfig({
  buildConfig: {
    define: {
      'process.env.VERSION': process.env.VERSION || '0.0.0',
    },
  },
});
通过上面的配置,我们就可以将下面这段代码:
// 编译前代码
console.log(process.env.VERSION);
在执行 VERSION=1.0.0 modern build 的时候,转换为:
// 编译后代码
console.log('1.0.0');
TIP
为了防止全局替换替换过度,建议使用时遵循以下两个原则:
- 全局常量使用大写
- 自定义全局常量前缀后缀,确保独一无二
dts
类型文件生成的相关配置,默认情况会生成。
{
  abortOnError: true,
  distPath: './',
  only: false,
}
dts.abortOnError
用于控制在出现类型错误的时候,是否允许构建成功。
默认情况下,在出现类型错误的时候会导致构建失败。将 abortOnError 设置为 false 后,即使代码中出现了类型问题,构建依然会成功:
modern.config.ts
export default defineConfig({
  buildConfig: {
    dts: {
      abortOnError: false,
    },
  },
});
WARNING
当关闭该配置后,无法保证类型文件能正常生成,且不保证内容正确。在 buildType: 'bundle' 时,即打包模式下,类型文件一定不会生成。
dts.distPath
类型文件的输出路径,基于 outDir 进行输出。
比如输出到 outDir 下面的 types 目录:
modern.config.ts
export default defineConfig({
  buildConfig: {
    dts: {
      distPath: './types',
    },
  },
});
dts.enableTscBuild
开启 tsc '--build' 选项。当使用 project reference 时,
可以使用 '--build' 选项以实现项目之间的协同工作以加快构建速度。
此选项要求版本 > 2.43.0,
事实上,我们在 2.42.0 版本曾试验性地开启此选项,但其带来的许多问题使我们不得不动态开启。
当开启此选项时,为了满足构建需求,你必须显式地在 tsconfig.json 里设置 'declarationDir' 或者 'outDir',
如果你用的不是 TS >= 5.0 版本,你还需要显式地设置 'declaration' 和 'emitDeclarationOnly'。
- 类型: boolean
- 默认值: false
- 版本: >2.43.0
modern.config.ts
export default defineConfig({
  buildConfig: {
    dts: {
      enableTscBuild: true,
    },
  },
});
dts.only
是否在构建时只生成类型文件,不生成 JavaScript 产物文件。
modern.config.ts
export default defineConfig({
  buildConfig: {
    dts: {
      only: true,
    },
  },
});
dts.respectExternal
当设为 false 时,不会打包任何三方包类型,设为 true 时,会根据 externals 来决定是否需要打包三方类型。
在对类型文件进行打包时,构建工具还未对 export 进行分析,因此当你引用的任何一个三方包出现类型错误时,都可能会中断当前的构建流程,这会导致构建流程不可控,因此我们可以通过这个配置来避免该问题。
modern.config.ts
export default defineConfig({
  buildConfig: {
    dts: {
      respectExternal: false,
    },
  },
});
dts.tsconfigPath
废弃,使用 tsconfig 配置替代。
指定用于生成类型文件的 tsconfig 文件路径。
modern.config.ts
export default defineConfig({
  buildConfig: {
    dts: {
      tsconfigPath: './other-tsconfig.json',
    },
  },
});
esbuildOptions
用于修改底层的 esbuild 配置。
例如,我们需要修改生成文件的后缀:
modern.config.ts
export default defineConfig({
  buildConfig: {
    esbuildOptions: options => {
      options.outExtension = { '.js': '.mjs' };
      return options;
    },
  },
});
例如,注册一个 esbuild 插件:
modern.config.ts
import { myEsbuildPlugin } from './myEsbuildPlugin';
export default defineConfig({
  buildConfig: {
    esbuildOptions: options => {
      options.plugins = [myEsbuildPlugin, ...options.plugins];
      return options;
    },
  },
});
在增加 esbuild 插件时,请注意你需要将插件加在 plugins 数组的头部,因为 Modern.js Module 内部也是通过一个 esbuild 插件介入到整个构建流程中去的,因此需要将自定义插件优先注册。
TIP
我们在原本 esbuild 构建的基础上做了许多扩展,因此使用此配置需要注意以下几点:
- 优先使用 Modern.js Module 提供的配置,例如 esbuild 并不支持 target: 'es5',但我们内部使用 SWC 支持了此场景,此时通过esbuildOptions设置target: 'es5'会报错。
- 目前我们内部使用 enhanced-resolve替代了 esbuild 的 resolve 解析算法,所以修改 esbuild resolve 相关配置无效,计划在未来会切换回来。
externalHelpers
默认情况下,输出的 JS 代码可能会依赖一些辅助函数来支持目标环境或者输出格式,这些辅助函数会被内联在需要它的文件中。
使用此配置,将会使用 SWC 对代码进行转换,将内联的辅助函数转换为从外部模块 @swc/helpers 导入这些辅助函数。
下面是使用该配置前后的产物变化比较。
开启前:
./dist/index.js
// 辅助函数
function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) {
  // ...
}
// 辅助函数
function _async_to_generator(fn) {
  return function () {
    // use asyncGeneratorStep
    // ...
  };
}
// 你的代码
export var yourCode = function () {
  // use _async_to_generator
};
开启后:
./dist/index.js
// 从 @swc/helpers 导入的辅助函数
import { _ as _async_to_generator } from '@swc/helpers/_/_async_to_generator';
// 你的代码
export var yourCode = function () {
  // use _async_to_generator
};
externals
用于在打包时排除一些外部依赖,避免将这些依赖打包到最终的 bundle 中。
type Externals = (string | RegExp)[];
- 默认值: []
- 构建类型:仅支持 buildType: 'bundle'
- 示例:
modern.config.ts
export default defineConfig({
  buildConfig: {
    // 避免打包 React
    externals: ['react'],
  },
});
同 banner 配置,用于在输出文件末尾添加注释。
format
用于设置 JavaScript 产物输出的格式,其中 iife 和 umd 只在 buildType 为 bundle 时生效。
- 类型:'esm' | 'cjs' | 'iife' | 'umd'
- 默认值:cjs
format: esm
esm 代表 "ECMAScript 模块",它需要运行环境支持 import 和 export 语法。
modern.config.ts
export default defineConfig({
  buildConfig: {
    format: 'esm',
  },
});
format: cjs
cjs 代表 "CommonJS",它需要运行环境支持 exports、require 和 module 语法,通常为 Node.js 环境。
modern.config.ts
export default defineConfig({
  buildConfig: {
    format: 'cjs',
  },
});
format: iife
iife 代表 "立即调用函数表达式",它将代码包裹在函数表达式中,确保代码中的任何变量不会意外地与全局范围中的变量冲突,通常在浏览器环境中运行。
modern.config.ts
export default defineConfig({
  buildConfig: {
    format: 'iife',
  },
});
format: umd
umd 代表 "Universal Module Definition",用于在不同环境(浏览器、Node.js 等)中运行。umd 格式的模块可以在多种环境下使用,既可以作为全局变量访问,也可以通过模块加载器(如 RequireJS)进行模块化加载。
modern.config.ts
export default defineConfig({
  buildConfig: {
    format: 'umd',
  },
});
hooks
构建生命周期钩子,允许在构建流程的特定阶段注入自定义逻辑。
type HookList = {
  name: string;
  apply: (compiler: ICompiler) => void;
  // 是否在 buildIn 钩子之后执行
  applyAfterBuiltIn?: boolean;
};
我们可以在 apply 方法里拿到 compiler 实例,修改其属性,以及在不同阶段执行自定义逻辑,对于 Hook 的详细介绍,
参考使用 Hook 介入构建流程。
modern.config.ts
export default defineConfig({
  buildConfig: {
    buildType: 'bundle',
    hooks: [
      {
        name: 'renderChunk',
        apply: compiler => {
          // any logic for compiler
          compiler.hooks.renderChunk.tapPromise(
            { name: 'renderChunk' },
            async chunk => {
              return chunk;
            },
          );
        },
      },
    ],
  },
});
input
指定构建的入口文件,数组形式可以指定目录。
type Input =
  | string[];
  | {
      [name: string]: string;
    }
- 默认值:bundle模式下默认为['src/index.ts'],bundleless模式下默认为['src']
数组用法:
在 bundle 模式下,下面的配置会以 src/index.ts 和 src/index2.ts 为入口分别进行构建。bundle 模式不支持配置 input 为目录。
modern.config.ts
export default defineConfig({
  buildConfig: {
    buildType: 'bundle',
    input: ['src/index.ts', 'src/index2.ts'],
  },
});
在 bundleless 模式下,下面的配置会同时处理 src/a 目录下的文件和 src/index.ts 文件。
modern.config.ts
export default defineConfig({
  buildConfig: {
    buildType: 'bundleless',
    input: ['src/a', 'src/index.ts'],
  },
});
在 bundleless 模式下,数组模式还支持使用 ! 来过滤部分文件:
modern.config.ts
export default defineConfig({
  buildConfig: {
    buildType: 'bundleless',
    input: ['src', '!src/*.spec.ts'],
  },
});
上面的配置将打包 src 目录下的文件,同时会过滤以 spec.ts 为后缀的文件。这在测试文件与源码文件在同一个根目录下的情况会很有用。
对象用法:
当在 bundle 模式下需要修改产物的输出文件名称的时候,可以使用对象形式进行配置。
对象的 Key 是产物的文件名称,Value 是源码的文件路径。
modern.config.ts
export default defineConfig({
  buildConfig: {
    format: 'esm',
    input: {
      'index.esm': './src/index.ts',
    },
  },
});
jsx
指定 JSX 的编译方式,默认支持 React 17 及更高版本,自动注入 JSX 运行时代码。
- 类型: automatic | transform | preserve
- 默认值: automatic
如果你需要支持 React 16,则可以设置 jsx 为 transform:
modern.config.ts
export default defineConfig({
  buildConfig: {
    jsx: 'transform',
  },
});
TIP
如果你不需要转换 JSX ,可以设置 jsx 为 preserve, 但此时请不要使用 swc 做代码转换。
关于 JSX Transform 的更多说明,可以参考以下链接:
loader
试验性功能
此选项用来更改给定输入文件的解释方式。例如你需要将 js 文件当做 jsx 处理
modern.config.ts
export default defineConfig({
  buildConfig: {
    loader: {
      '.js': 'jsx',
    },
  },
});
metafile
这个选项用于构建分析,开启该选项后,esbuild 会以 JSON 格式生成有关构建的一些元数据。
- 类型:boolean
- 默认值:false
- 构建类型:仅支持 buildType: 'bundle'
开启 metafile 生成:
modern.config.ts
export default defineConfig({
  buildConfig: {
    buildType: 'bundle',
    metafile: true,
  },
});
在执行 build 构建后,产物目录下会生成 metafile-[xxx].json 文件,你可以通过 esbuild analyze 和 bundle-buddy 等工具进行可视化分析。
minify
使用 esbuild 或者 terser 压缩代码,也可以传入 terserOptions。
- 类型: 'terser' | 'esbuild' | false | object
- 默认值: false
modern.config.ts
export default defineConfig({
  buildConfig: {
    minify: {
      compress: {
        drop_console: true,
      },
    },
  },
});
outDir
指定构建的输出目录。
modern.config.ts
export default defineConfig({
  buildConfig: {
    outDir: './dist/esm',
  },
});
platform
默认生成用于 Node.js 环境下的代码,你也可以指定为 browser,会生成用于浏览器环境的代码。
查看esbuild.platform了解更多。
- 类型: 'browser' | 'node'
- 默认值: 'node'
modern.config.ts
export default defineConfig({
  buildConfig: {
    platform: 'browser',
  },
});
redirect
在 buildType: 'bundleless' 构建模式下,会对引用路径进行重定向,确保指向了正确的产物,例如:
- import './index.less'会被改写成- import './index.css'
- import icon from './close.svg'会被改写成- import icon from '../asset/close.svg'(依实际情况而定)
- import * from './utils'会被改写成- import * from './utils.mjs'(如果生成了 utils.mjs,视实际情况而定)
在某些场景下,你可能不需要这些功能,那么可以通过此配置关闭它,关闭后,其引用路径将不会发生改变。
modern.config.ts
export default {
  buildConfig: {
    redirect: {
      alias: false, // 关闭对别名路径的修改
      style: false, // 关闭对样式文件路径的修改
      asset: false, // 关闭对资源文件路径的修改
      autoExtension: false, // 关闭对 js 文件后缀的修改
    },
  },
};
resolve
自定义模块解析选项
resolve.alias
基本用法和 alias 一致。
alias 的问题在于我们在 bundleless 场景下错误的处理了 Module ID 的情况:
import { createElement } from 'react';
当我们配置了 alias: { react: 'react-native' } 后,结果会变成
import { createElement } from './react-native';
一个 Module ID 被错误的处理成了相对路径,显然这是不符合预期的。
我们想要修复这个问题,但是这可能会破坏已有的项目,因此我们在 2.58.0 版本提供了 resolve.alias 来解决这个问题。
并且 resolve.alias 里移除了 alias 提供的默认值 { "@": "./src"}
如果你需要此功能,请使用 resolve.alias。
在下一个大版本,resolve.alias 将会取代 alias 。
WARNING
- 注意此配置不要与 alias 混用。
- 注意此配置必须标注一个相对路径,例如 { "@": "./src" }而非{ "@": "src"}。
 resolve.mainFields
package.json 中,在解析包的入口点时尝试的字段列表。
- 类型:string[]
- 默认值:取决于platform
- node: ['module', 'main']
- browser: ['module', 'browser', 'main']
 
- 版本:>=2.36.0
例如,我们想要先加载 js:source 字段:
modern.config.ts
export default defineConfig({
  buildConfig: {
    resolve: {
      mainFields: ['js:source', 'module', 'main'],
    },
  },
});
WARNING
resolve.mainFields 比 package.json 中 exports 字段的优先级低,如果一个入口点从 exports 成功解析,resolve.mainFields 将被忽略。
resolve.jsExtentions
支持隐式文件扩展名
- 类型: string[]
- 默认值: ['.jsx', '.tsx', '.js', '.ts', '.json']
- 版本:>=2.36.0
对于 css 文件,请不要使用隐式文件扩展名,目前 Module 仅支持 ['.less', '.css', '.sass', '.scss'] 后缀。
Node 的解析算法不会将 .mjs 和 cjs 视为隐式文件扩展名,因此这里默认也不会,但是可以通过更改此配置来包含:
modern.config.ts
export default defineConfig({
  buildConfig: {
    resolve: {
      jsExtentions: ['.mts', 'ts'],
    },
  },
});
resolve.tsconfig
用于配置 enhanced-resolve 中的 tsconfig-paths-webpack-plugin,来支持解析 tsconfig.json 中的 alias 和嵌套 @ 别名冲突的问题。
type Tsconfig = {
  configFile: string;
  references?: string[] | undefined;
};
- 默认值: { configFile: config.tsconfig, references: undefined }
- 版本:>=2.61.1
modern.config.ts
export default defineConfig({
  buildConfig: {
    resolve: {
      tsConfig: {
        configFile: './tsconfig.json',
      },
    },
  },
});
shims
在构建 cjs / esm 产物时注入一些垫片代码。
例如 __dirname 只能在 commonjs 里使用,开启此选项后,当产物格式为 esm 时,会将 __dirname 编译为 path.dirname(fileURLToPath(import.meta.url))。
详细代码见 shims,
需要注意的是 esm shims 只会在 platform 为 node 时注入,因为用到了 url 模块。
- 类型: boolean
- 默认值: false
- 版本:>=2.38.0
modern.config.ts
export default defineConfig({
  buildConfig: {
    shims: true,
  },
});
sideEffects
配置模块的副作用
- 类型: RegExg[] | (filePath: string, isExternal: boolean) => boolean | boolean
- 默认值: undefined
通常情况下,我们通过 package.json 的 "sideEffects" 字段来配置模块的副作用,但是在某些情况下,三方包的 package.json 是不可靠的。
例如我们引用了一个三方包的样式文件。
import 'other-package/dist/index.css';
但是这个三方包的 package.json 里并没有将样式文件配置到 "sideEffects" 里。
other-package/package.json
{
  "sideEffects": ["dist/index.js"]
}
同时你又设置了 style.inject 为 true,在控制台可以看到类似的警告信息:
[LIBUILD:ESBUILD_WARN] Ignoring this import because "other-package/dist/index.css" was marked as having no side effects
这时候就可以使用这个配置项,手动配置模块的"sideEffects",配置支持正则和函数形式。
modern.config.ts
export default defineConfig({
  buildConfig: {
    sideEffects: [/\.css$/],
    // or
    // sideEffects: (filePath, isExternal) => /\.css$/.test(filePath),
  },
});
TIP
添加此配置后,打包时将不会再读取 package.json 里的 "sideEffects" 字段。
sourceDir
指定构建的源码目录,默认为 src,用于在 bundleless 构建时基于源码目录结构生成对应的产物目录。
等同于esbuild.outbase。
sourceMap
控制 sourceMap 如何生成。
- 类型: boolean | 'inline' | 'external'
- 默认值: false
sourceType
设置源码的格式。默认情况下,会将源码作为 EsModule 进行处理。当源码使用的是 CommonJS 的时候,需要设置 commonjs。
- 类型:'commonjs' | 'module'
- 默认值:'module'
splitting
是否开启代码分割。
仅支持 format: 'esm' 和 format: 'cjs',查看esbuild.splitting了解更多。
style
配置样式相关的配置。
style.less
less 相关配置。
style.less.lessOptions
详细配置参考 less。
- 类型: object
- 默认值: { javascriptEnabled: true }
style.less.additionalData
在入口文件起始添加 Less 代码。
- 类型: string
- 默认值: undefined
modern.config.ts
export default defineConfig({
  buildConfig: {
    style: {
      less: {
        additionalData: `@base-color: #c6538c;`,
      },
    },
  },
});
style.less.implementation
配置 Less 使用的实现库,在不指定的情况下,使用的内置版本是 4.1.3。
- 类型: string | object
- 默认值: undefined
设置 object 类型时,可以指定 Less 的实现库。
modern.config.ts
export default defineConfig({
  buildConfig: {
    style: {
      less: {
        implementation: require('less'),
      },
    },
  },
});
string 类型时,指定 Less 的实现库的路径
modern.config.ts
export default defineConfig({
  buildConfig: {
    style: {
      less: {
        implementation: require.resolve('less'),
      },
    },
  },
});
sass
Sass 相关配置。
style.sass.sassOptions
详细配置参考 node-sass
style.sass.additionalData
在入口文件起始添加 Sass 代码。
- 类型: string | Function
- 默认值: undefined
modern.config.ts
export default defineConfig({
  buildConfig: {
    style: {
      sass: {
        additionalData: `$base-color: #c6538c;
          $border-dark: rgba($base-color, 0.88);`,
      },
    },
  },
});
style.sass.implementation
配置 Sass 使用的实现库,在不指定的情况下,使用的内置版本是 1.54.4。
- 类型: string | object
- 默认值: undefined
设置为 object 类型时,可以指定 Sass 的实现库。
modern.config.ts
export default defineConfig({
  buildConfig: {
    style: {
      sass: {
        implementation: require('sass'),
      },
    },
  },
});
string 类型时,指定 Sass 的实现库的路径
modern.config.ts
export default defineConfig({
  buildConfig: {
    style: {
      sass: {
        implementation: require.resolve('sass'),
      },
    },
  },
});
style.postcss
用于配置 PostCSS 的选项,传入的值会与默认配置通过 Object.assign 合并。注意 Object.assign 是浅拷贝,因此会完全覆盖内置的 plugins 数组。
详细配置请查看 PostCSS。
type PostcssOptions = {
  processOptions?: ProcessOptions;
  plugins?: AcceptedPlugin[];
};
const defaultConfig = {
  plugins: [
    // 以下插件默认启用
    require('postcss-flexbugs-fixes'),
    require('postcss-media-minmax'),
    require('postcss-nesting'),
    // 以下插件仅在 target 为 `es5` 时启用
    require('postcss-custom-properties'),
    require('postcss-initial'),
    require('postcss-page-break'),
    require('postcss-font-variant'),
  ],
};
modern.config.ts
export default defineConfig({
  buildConfig: {
    style: {
      postcss: {
        plugins: [yourPostCSSPlugin],
      },
    },
  },
});
style.inject
配置打包模式下是否将 CSS 样式插入到 JavaScript 代码中。
将 inject 设置为 true 来开启此功能:
modern.config.ts
export default defineConfig({
  buildConfig: {
    style: {
      inject: true,
    },
  },
});
开启后,你会看到源码中引用的 CSS 代码被包含在了打包后的 JS 产物中。
例如,你在源码里写了 import './index.scss',那么在产物中你会看到以下代码:
dist/index.js
// node_modules/style-inject/dist/style-inject.es.js
function styleInject(css, ref) {
  // ...
}
var style_inject_es_default = styleInject;
// src/index.scss
var css_248z = '.body {\n  color: black;\n}';
style_inject_es_default(css_248z);
TIP
开启 inject 后,你需要注意以下几点:
- CSS 文件中的 @import不会被处理。如果你的 CSS 文件中有@import,那么你需要在 JS 文件中手动引入 CSS 文件(less,scss 文件不需要,因为它们会有预处理)。
- 需要考虑 sideEffects的影响。默认情况下,我们的构建器会认为 CSS 是有副作用的,如果你的项目中或者三方包的 package.json 设置了sideEffects字段并且没有包含此 CSS 文件,那么你将会得到一个警告:
[LIBUILD:ESBUILD_WARN] Ignoring this import because "src/index.scss" was marked as having no side effects by plugin "libuild:adapter"
此时可以通过配置 sideEffects 来解决。
 style.autoModules
根据文件名自动启用 CSS Modules。
- 类型: boolean | RegExp
- 默认值: true
true : 为以 .module.css .module.less .module.scss .module.sass 文件名结尾的样式文件启用 CSS Modules。
false : 禁用 CSS Modules.
RegExp : 为匹配正则条件的所有文件启用 CSS Modules.
style.modules
CSS Modules 配置。
一个常用的配置是 localsConvention,它可以改变 CSS Modules 的类名生成规则。
modern.config.ts
export default defineConfig({
  buildConfig: {
    style: {
      modules: {
        localsConvention: 'camelCaseOnly',
      },
    },
  },
});
对于以下样式:
.box-title {
  color: red;
}
你可以使用 styles.boxTitle 来访问。
详细配置查看 postcss-modules
style.tailwindcss
用于修改 Tailwind CSS 的配置项。
- 类型: object | Function
- 默认值:
modern.config.ts
const tailwind = {
  content: ['./src/**/*.{js,jsx,ts,tsx}', './config/html/**/*.{html,ejs,hbs}'],
};
启用 Tailwind CSS
在使用 style.tailwindcss 之前,你需要启用 Modern.js Module 的 Tailwind CSS 插件。
请阅读「使用 Tailwind CSS」 章节来了解开启方式。
类型
值为 object 类型时,与默认配置通过 Object.assign 合并。
值为 Function 类型时,函数返回的对象与默认配置通过 Object.assign 合并。
其他的使用方式和 Tailwind CSS 一致: 快速传送门。
注意事项
注意:
- 如果你同时使用了 tailwind.config.{ts,js}文件和tools.tailwindcss选项,那么tools.tailwindcss定义的配置会优先生效,并覆盖tailwind.config.{ts,js}中定义的内容。
- 如果你同时使用了 designSystem配置项,那么 Tailwind CSS 的theme配置将会被designSystem的值所覆盖。
其他配置的使用方式与 Tailwind CSS 官方用法一致,请参考 tailwindcss - Configuration。
target
target 用于为生成的 JavaScript 代码设置目标环境。它让 Modern.js Module 将目标环境无法识别的 JavaScript 语法转换为在这些环境中可用的低版本 JavaScript 语法。
type Target =
  | 'es5'
  | 'es6'
  | 'es2015'
  | 'es2016'
  | 'es2017'
  | 'es2018'
  | 'es2019'
  | 'es2020'
  | 'es2021'
  | 'es2022'
  | 'esnext';
例如,将代码编译到 es5 语法:
modern.config.ts
export default defineConfig({
  buildConfig: {
    target: 'es5',
  },
});
transformImport
提供与 babel-plugin-import 等价的能力和配置,基于 SWC 实现,使用此配置,将会使用 SWC 对代码进行转换。
数组元素为一个 babel-plugin-import 的配置对象。配置对象可以参考 options。
使用示例:
modern.config.ts
export default defineConfig({
  buildConfig: {
    transformImport: [
      // babel-plugin-import 的 options 配置
      {
        libraryName: 'foo',
        style: true,
      },
    ],
  },
});
参考「Import 插件——注意事项」
transformLodash
是否模块化 lodash 的导入,删除未使用的 lodash 模块,从而减少 lodash 代码体积。这项优化基于 babel-plugin-lodash 和 swc-plugin-lodash 实现。
使用此配置,将会使用 SWC 对代码进行转换。
当开启此选项时,Modern.js Module 会自动将 lodash 的代码引用指向子路径。
比如:
input.js
import _ from 'lodash';
import { add } from 'lodash/fp';
const addOne = add(1);
_.map([1, 2, 3], addOne);
转换后的代码:
output.js
import _add from 'lodash/fp/add';
import _map from 'lodash/map';
const addOne = _add(1);
_map([1, 2, 3], addOne);
tsconfig
TypeScript 配置文件的路径。
- 类型: string
- 默认值: tsconfig.json
- 版本: >=2.36.0
modern.config.ts
export default defineConfig({
  buildConfig: {
    tsconfig: 'tsconfig.build.json',
  },
});
umdGlobals
指定 UMD 产物外部导入的全局变量。
- 类型: Record<string, string>
- 默认值: {}
modern.config.ts
export default defineConfig({
  buildConfig: {
    umdGlobals: {
      react: 'React',
      'react-dom': 'ReactDOM',
    },
  },
});
此时,react 和 react-dom 会被看做是外部导入的全局变量,不会被打包进 UMD 产物中,而是通过 global.React 和 global.ReactDOM 的方式进行访问。
umdModuleName
指定 UMD 产物的模块名。
- 类型: string | Function
- 默认值: name => name
modern.config.ts
export default defineConfig({
  buildConfig: {
    format: 'umd',
    umdModuleName: 'myLib',
  },
});
此时 UMD 产物会去挂载到 global.myLib 上。
TIP
- 需要遵守 UMD 规范,UMD 产物的模块名不能和全局变量名冲突。
- 模块名会被转换为驼峰命名,如 my-lib会被转换为myLib,可参考toIdentifier。
 同时函数形式可以接收一个参数,为当前打包文件的输出路径
modern.config.ts
export default defineConfig({
  buildConfig: {
    format: 'umd',
    umdModuleName: path => {
      if (path.includes('index')) {
        return 'myLib';
      } else {
        return 'myLib2';
      }
    },
  },
});