ncc 是一个由 Vercel 开发的简单命令行工具,ncc 受启发于 Go 语言的 build 功能(导出一个静态 ELF 可执行文件),旨在将 Node.js 模块及其所有依赖项编译成单个文件,类似于 GCC 的风格。这个工具非常适合希望将最小化包发布到 npm 的开发者,以及那些希望将相关应用代码仅发送到无服务器环境的开发者。
举例来说,如果在服务器上部署一个 Nest.JS 开发的服务,传统的方式是拷贝源代码 + npm i + 运行 node,这种部署方式即便是一个 hello word 都至少带来上百 MB 的空间占用。 而使用 ncc 打包,然后在服务器端直接执行 node build.js 。整个空间占用不到 10MB (因为去除+压缩了 node_modules 里面无用的依赖),额外带来的好处也有启动速度提升(例如 require 依然有可观的 file IO 开销)。
优势
- 零配置:无需复杂的设置,开箱即用。
- 内置 TypeScript 支持:直接处理 .ts 和 .tsx 文件,简化 TypeScript 项目的构建流程。
- 单文件输出:将整个模块及其依赖打包成单个文件,便于分发和管理。
- 支持动态模块加载:通过外部模块选项,灵活处理不需要打包的依赖。
- 丰富的命令和选项:提供多种命令和选项,满足不同场景的需求,如构建、运行、缓存管理等。
ncc
打包 JS 文件的基本流程:
ncc 本身是基于 webpack 开发的,所以整个流程与webpack 是一致的
分析依赖树
ncc
开始时会读取项目的入口文件(通常是 index.js
或者某个主模块)。然后它会递归地分析这个入口文件所依赖的所有其他模块,构建一个完整的依赖树。在这个过程中,ncc
会识别出哪些模块是需要被包含进最终输出文件中的。
代码转换
对于每个被识别出来的模块,ncc
会进行必要的转换。这些转换可能包括但不限于:
- ES6+语法转ES5:如果目标环境不支持最新的JavaScript特性,那么
ncc
会将代码转换为向后兼容的形式。 - 模块系统统一:将 CommonJS 规范的
require
调用转换为 ES 模块的import
语句,或者反之,以便所有代码使用一致的模块加载机制。(通过webpack 的 resolve.byDependency 配置实现)
代码合并
一旦所有依赖项都被正确地转换和准备好了,ncc
就会将它们合并成一个单一的文件。在这个过程中,ncc
会尝试最小化冗余代码,即相同的代码片段只包含一次,而不是在每个依赖模块中重复出现。
压缩与优化
合并完成后,ncc
会对最终的文件进行压缩,移除空白字符、注释等,使文件体积尽可能小。此外,还可能执行其他优化措施来提高性能,如内联某些函数或变量。
为了便于调试,ncc
会生成 source map 文件,这样在部署后的代码中出现的问题可以映射回原始源代码的位置,方便开发者定位问题。
输出
最后,ncc
会将这个单一的文件输出到指定的位置,通常是一个构建目录,如 dist
或 .vercel/output/functions
。此外,相关的辅助文件(如 source map)也会一并生成。