Webpack 配置与打包流程
配置生成
ncc 在 src/index.js 中动态构建完整的 Webpack 配置对象。配置的每个部分都由用户选项和文件特征驱动。
Webpack 配置结构
入口与输出
输出文件名的 .cjs 扩展名有特殊处理:由于 Webpack 只为 .js 文件生成 source map,.cjs 输入会临时加 .js 后缀编译,后处理时再处理。
缓存配置
缓存目录默认为 $XDG_CACHE_HOME/ncc/<project-sha1> 或 ~/.cache/ncc/<project-sha1>。
模块解析
关键设计决策:mainFields 只包含 main,不包含 module。这是因为 ncc 的目标是 Node.js,而 Node.js 本身不会使用 module 字段。
优化配置
minimize: false 是因为 ncc 使用自己的 Terser 后处理,不走 Webpack 的压缩插件。
实验性特性
Loader 管道
Webpack 的 Loader 按配置顺序从下到上执行。ncc 的 Loader 管道按实际执行顺序:
对 .js/.mjs/.tsx?/.node 文件
relocate-loader:分析和重定位资源引用(文件路径、__dirname、__filename等)empty-loader:过滤不可静态分析的包
对 .tsx? 文件(额外)
ts-loader:TypeScript → JavaScript 转换uncacheable:标记为不可缓存(确保 TypeScript 配置变更时重新编译)
对所有非 .node/.json 文件
shebang-loader:移除 shebang 行
对 @@notfound.js 匹配文件
notfound-loader:将占位模块转为目标模块名称的运行时require
插件系统
ncc 注册了几个自定义 Webpack 插件:
核心插件(src/index.js:213-246)
第三个钩子的作用是:某些代码中 require 被重新赋值(如 require = createRequire(import.meta.url)),Webpack 的 CommonJsPlugin 会尝试处理这种模式,但 ncc 需要保留原始行为。
条件插件
LicenseWebpackPlugin:当--license选项指定时,收集所有依赖的许可信息DefinePlugin:CJS 模式下将import.meta.url替换为等效的require("url").pathToFileURL(__filename).href
Externals 处理
externals 支持三种形式:
- 字符串数组:
["fs", "path"]→ 保留为require("fs") - 对象映射:
{ "original": "replacement" }→ 别名 - 正则表达式:
{ "/caniuse-lite(/.*)/" : "caniuse-lite$1" }→ 模式匹配,支持捕获组替换
externalMap 是一个自定义的类 Map 对象,支持正则匹配和缓存(src/index.js:164-201)。
Watch 模式
当 watch: true 时,compiler.watch() 替代 compiler.run()。返回一个包含 handler、rebuild、close 方法的对象。
watch 模式的文件监视可以通过传入自定义 WatchFileSystem 类来覆盖(src/index.js:415-419)。