核心编译引擎
文件位置
src/index.js — ncc 的核心模块,负责 Webpack 配置生成、编译执行和输出后处理。
模块接口
参数
返回值
- 非 watch 模式:
Promise<{ code, map, assets, symlinks, stats }> - Watch 模式:
{ handler(cb), rebuild(cb), close() }
核心流程
1. 选项解析与默认值
esm 的自动检测逻辑:
.mjs扩展名 → ESM- 非
.cjs且位于"type": "module"包边界内 → ESM - 其他 → CJS
2. TSConfig 解析
从入口文件所在目录向上搜索 tsconfig.json,加载后用于:
- 配置
TsconfigPathsPlugin(路径别名) - 配置 ts-loader 的
compilerOptions - 处理
.d.ts文件的输出路径
整个 TSConfig 加载包裹在 try-catch 中:如果没有 tsconfig,纯 JavaScript 项目仍可正常工作。
3. 自定义 Resolve 插件
这个插件实现了两个关键行为:
- TypeScript
.js导入回退:TS 文件中import './foo.js'会尝试解析./foo.ts或./foo.tsx - 宽容的模块解析:任何找不到的模块都不会导致构建失败,而是转为运行时
require
4. ExternalMap
externalMap 是一个带正则匹配的映射结构:
set(key, value):key 可以是字符串或 RegExpget(key):先精确匹配,再遍历正则表达式,匹配结果缓存在regexCache
正则表达式支持捕获组替换:/caniuse-lite(.*)/ → caniuse-lite$1
5. Webpack 编译
编译完成后进入 finalizeHandler(详见 输出处理流程)。
6. compilationStack
compilationStack 跟踪当前活跃的 Webpack compilation 对象。由于 assetBuilds 可能触发嵌套编译,需要栈来跟踪层级关系。每次编译开始时 push,完成时 pop。
辅助函数
getFlatFiles
递归遍历 memory-fs 的内部数据结构(嵌套对象),将文件展平为路径→内容的映射。对 .d.ts 文件做特殊路径处理。
walkParentDirs
从 start 目录向上搜索指定文件名,直到 base 目录。用于查找 tsconfig.json。
hashOf
生成缓存名称的短哈希。
依赖关系
线程安全与并发
ncc 是单线程运行的,不支持同时进行多个编译。compilationStack 虽然看起来支持嵌套,但实际上嵌套调用(assetBuilds)是通过 await 串行执行的。