Compile a Node.js project into a single file. Supports TypeScript, binary addons, dynamic requires.
by vercelJavaScript
Last 12 weeks · 17 commits
3 of 6 standards met
Bumps from 1.7.3 to 1.10.2 (latest). What's in the bump Because 1.10.0 publishes rather than an ncc-built , the loader's previously bundled dependencies are now real transitive dependencies — that accounts for the lockfile growth. The build emits no new assets, and actually shrinks slightly (499.37KB → 492.11KB). Why the unit fixtures change The loader now registers the asset base through a webpack instead of the deprecated . Two consequences show up in : 1. The block is labelled instead of , and is emitted earlier in the runtime. 2. Bundles that never reference no longer carry the dead assignment — the runtime module is only added when is actually in the tree. The guard was always false in those bundles, so this is dead-code removal, not a behaviour change. I specifically checked that the second point is not a regression. is still emitted wherever it is referenced, verified by hand for CJS, ESM, and concatenated-TypeScript builds that relocate an asset, and by the asset-heavy integration tests (, , , , , ), which all pass. Windows fix (second commit) The first push was green on Linux and macOS but failed on all three Windows jobs: The relocator derives the ESM asset base from , which is percent-encoded. The Windows runner's temp dir is an 8.3 short name (), so became . This is not platform-specific — paths containing spaces break identically everywhere: That expression is byte-identical in 1.7.3 and 1.10.2, so the bug is pre-existing. It was simply unreachable for this fixture before: 1.7.3 had no specifier support, so was not statically analyzable and was never relocated. 1.8.0 added as an alias of , so the reference is now resolved, emitted as an asset, and rewritten to — which is where the latent bug surfaces. Fixed by wrapping the pathname in . Slicing still happens after decoding, and it only trims a leading on Windows drive paths and the trailing , neither of which decoding can alter. The CJS branch uses and is untouched. This goes through pnpm's , as the repo already does for . It should be dropped once the fix ships upstream in — happy to open that PR if you'd like. Also fixed invoked for the coverage pass. Under pnpm that path is a shell shim rather than a JS entry point, so the step crashed with and never regenerated any . Switched both invocations to , matching the script in . That broken step is why two fixtures had drifted on before this PR ( and ). Their regenerated output here therefore contains one small change each that is unrelated to the relocator. The drift went unnoticed because calls in under coverage, so exits 0 even when fails. Testing Run on Linux / Node 22.22.2: — 122 passed, 4 suites, matching the pre-bump baseline — 28 passed — exits 0 ESM asset builds into both a plain output dir and one containing a space and a — both load their assets correctly Two pre-existing quirks I ran into and confirmed also reproduce on , so they are not introduced here and are left alone: Under , if runs before in the same process, a unit test fails with inside webpack's . Reproduced at 1.7.3. The stale coverage fixtures described above. One thing to flag 1.10.2 was published roughly an hour before this PR was opened, and sets (48h), so a fresh resolution of this version is blocked today. I generated the lockfile with a one-off and deliberately did not add a entry, so the repo's supply-chain policy is unchanged. CI is unaffected: skips resolution and installs 1.10.2 from the lockfile (verified locally). Once 1.10.2 is 48h old the constraint stops mattering entirely — hold this PR until then if you'd rather the policy not be bypassed at all. Related Fixes https://github.com/vercel/ncc/issues/1307 Confirmed this bump does address it. That originates in the relocator's static evaluator (), whose handler is unguarded in 1.7.3. 1.10.2 wraps it in a , with a comment naming that exact error, and adds the matching guard for the BigInt case.
Summary allow ncc to bundle TypeScript composite projects that import referenced sibling sources keep composite build artifacts out of ncc's single-bundle compilation add a regression fixture matching the app/lib workspace reported in the issue run the regression through the standard unit golden-output runner in normal and coverage modes Root cause When composite is enabled, TypeScript implicitly scopes rootDir to the directory containing the project tsconfig. ncc compiles the entry point and its imported sources as one webpack compilation, so a referenced sibling project was rejected with TS6059. ncc already controls emit-related compiler options for its internal compilation. Disabling composite there preserves the single-bundle model while leaving the user's tsconfig unchanged. Tests pnpm build-test-binary pnpm build pnpm test (119 passed) pnpm test-coverage pnpm test test/unit.test.js --runInBand --testNamePattern=ts-project-references pnpm test-coverage test/unit.test.js --testNamePattern=ts-project-references Fixes #1212
Fixes #1238 Adds TypeScript declarations for the programmatic API and points at them. The declarations cover the documented build options, watch-mode overloads ( / / ), and the real return shape (, , , , ). copies into so the published package ships the types next to . Verified with (strict check over a small consumer fixture), (confirms is emitted), and (29 passed). Full hits two environment-only flakes on this host (socket.io needs free ; the CLI case finds typescript under ); both fail the same way without this change.
Problem Issue #1311 reports when ncc bundles a TypeScript entry that imports an ESM-only package such as . exposes its package root through the condition, but not through . In a TypeScript project with and set to , ncc selects ESM output, but ts-loader lowers the entry import to . Webpack then resolves the dependency through CommonJS conditions and misses the package's export. Change preserve TypeScript ES imports when ncc has selected ESM output but asks TypeScript to emit CommonJS leave user TypeScript module settings alone for non-ESM builds and other module modes add a regression test for an ESM package that exposes only an condition The fixture sets explicitly so the test focuses on ncc's ESM output path while keeping the TypeScript setting that triggers the regression. This patch keeps TypeScript imports intact only for that ESM-output/CommonJS-emit mismatch, so webpack can resolve import-only packages through their condition without broadening the behavior for CJS ncc builds or other TypeScript module modes. Research / Repro Confirmed exposes package root through only via . Confirmed the fixture keeps while ncc receives , which is the mismatch covered here. Ran the new repro against in a detached worktree: it fails with for an import-only package. Ran the same repro against this branch: it passes and the bundled code contains the import-only package value. Checked open PR overlap for #1311; only this PR currently targets it. Validation Risk The behavior change is limited to ncc ESM builds where TypeScript would otherwise emit CommonJS. CJS ncc builds and other TypeScript module modes are left unchanged. The new fixture includes a small package under to model an import-only package export map; it is static test data, not a new dependency. Out of scope changing TypeScript module settings for non-ESM ncc builds adding a general compatibility layer for direct execution of this fixture shape changing dependency resolution behavior outside this ESM-output/CommonJS-emit mismatch Issue linkage Addresses https://github.com/vercel/ncc/issues/1311.
Repository: vercel/ncc. Description: Compile a Node.js project into a single file. Supports TypeScript, binary addons, dynamic requires. Stars: 9830, Forks: 323. Primary language: JavaScript. Languages: JavaScript (98%), TypeScript (1.1%), Shell (0.3%), Python (0.3%), C++ (0.3%). License: MIT. Homepage: https://npmjs.com/@vercel/ncc Latest release: 0.44.1 (1mo ago). Open PRs: 23, open issues: 198. Last activity: 8h ago. Community health: 75%. Top contributors: guybedford, dependabot[bot], rauchg, styfle, timneutkens, sokra, huozhi, ijjk, TooTallNate, igorklopov and others.