Loader 系统
概述
ncc 使用一组自定义 Webpack Loader 来处理模块加载过程中的各种边界情况。大部分 Loader 是轻量级的包装器或简单的文本处理器。
Loader 执行顺序
Webpack Loader 从配置数组的最后一个开始执行(从下往上)。ncc 的规则及其实际执行顺序:
实际一个 .ts 文件会经过:shebang-loader → uncacheable → ts-loader → relocate-loader → empty-loader
各 Loader 详解
relocate-loader (src/loaders/relocate-loader.js)
职责:这是 ncc 最核心的 Loader,负责静态分析和重定位文件系统引用。
实际实现在 @vercel/webpack-asset-relocator-loader 包中,ncc 只是简单地 re-export。它的功能包括:
- 分析
__dirname、__filename、require.resolve()等路径引用 - 将引用的文件/目录作为 asset 输出
- 处理动态
require()表达式 - 提供
initAssetCache()、getAssetMeta()、getSymlinks()API 供后处理使用
配置选项(传入 src/index.js:349-355):
ts-loader (src/loaders/ts-loader.js)
职责:TypeScript → JavaScript 转换。
设计要点:
- 猴子补丁
ts-loader的 logger,过滤 TypeScript 版本兼容性警告 - 导出内置的
typescript模块,供 ts-loader 内部使用 - 配合
src/typescript.js实现用户本地 TypeScript 优先加载
Webpack 配置中的选项(src/index.js:364-376):
empty-loader (src/loaders/empty-loader.js)
职责:将不可静态分析的包替换为空模块。
当前被过滤的包:uglify-js、uglify-es — 这些包的动态特性会导致 Webpack 分析失败。
shebang-loader (src/loaders/shebang-loader.js)
职责:移除文件开头的 shebang 行(#!/usr/bin/env node),防止 JavaScript 解析器报错。原始 shebang 在 finalizeHandler 中恢复。
notfound-loader (src/loaders/notfound-loader.js)
职责:将 @@notfound.js 中的 'UNKNOWN' 占位符替换为实际的模块名称。
配合 src/@@notfound.js:
最终输出:module.exports = __non_webpack_require__('actual-module-name')
这使得无法在构建时解析的模块在运行时通过 Node.js 原生的 require() 加载。
stringify-loader (src/loaders/stringify-loader.js)
职责:将文件内容转为字符串模块导出(module.exports = "...")。用于处理非 JavaScript 资源文件。
uncacheable (src/loaders/uncacheable.js)
职责:标记模块为不可缓存。这确保 TypeScript 文件在 tsconfig 变更时总是重新编译,而不是使用 Webpack 缓存的版本。
@@notfound.js 机制
完整流程:
- Webpack resolve 插件检测到模块无法解析
- 将请求重定向到
src/@@notfound.js?actual-module-name notfound-loader处理该文件,将'UNKNOWN'替换为真实名称- 最终输出
module.exports = __non_webpack_require__('actual-module-name') - 运行时通过 Node.js 原生 require 加载
设计意图:让 ncc 对缺失依赖保持宽容。某些包有条件性依赖(如数据库驱动),在构建环境中可能不存在但运行时可用。