release: v12.0.0 major release (approx. Q3 2026)#3280
Conversation
|
A current version of this PR has been published under the |
There was a problem hiding this comment.
Pull request overview
This PR prepares the Nest CLI v12 major release by migrating the codebase to ESM/NodeNext, switching the test runner from Jest to Vitest, and introducing rspack support (with webpack deprecated) alongside expanded e2e coverage.
Changes:
- Add Vitest configuration (unit + e2e) and migrate existing unit tests from Jest to Vitest.
- Migrate CLI/runtime code to ESM (
"type": "module",.jsimport specifiers, NodeNext TS config) and refactor commands/actions to use typed context objects. - Add rspack compiler + defaults and add e2e tests across core CLI commands.
Reviewed changes
Copilot reviewed 128 out of 131 changed files in this pull request and generated 8 comments.
Show a summary per file
| File | Description |
|---|---|
| vitest.e2e.config.ts | Adds Vitest config for e2e suite (timeouts, includes). |
| vitest.config.ts | Adds Vitest config for unit tests and excludes e2e. |
| tsconfig.json | Switches TS compilation to NodeNext/ES2022 and removes Jest types. |
| tools/postinstall.cjs | Post-install helper for test fixtures + vitest timeout patching. |
| tools/clean.js | Replaces gulp-based clean with a Node script to remove build artifacts. |
| test/lib/utils/get-default-tsconfig-path.spec.ts | Migrates test from Jest to Vitest + ESM import specifiers. |
| test/lib/schematics/schematic.option.spec.ts | Updates tests for boolean flag serialization changes + Vitest migration. |
| test/lib/schematics/nest.collection.spec.ts | Migrates to Vitest and updates ESM import paths. |
| test/lib/schematics/custom.collection.spec.ts | Migrates to Vitest and adds an ESM-safe mock for schematics tools. |
| test/lib/runners/schematic.runner.spec.ts | Updates module-path resolution expectations for ESM. |
| test/lib/readers/file-system.reader.spec.ts | Migrates to Vitest and updates reader imports. |
| test/lib/questions/questions.spec.ts | Migrates to Vitest and updates ESM import paths/types usage. |
| test/lib/package-managers/yarn.package-manager.spec.ts | Migrates to Vitest and updates ESM import paths/mocks. |
| test/lib/package-managers/pnpm.package-manager.spec.ts | Migrates to Vitest and updates ESM import paths/mocks. |
| test/lib/package-managers/package-manager.factory.spec.ts | Migrates to Vitest and updates typings for mock casting. |
| test/lib/package-managers/npm.package-manager.spec.ts | Migrates to Vitest and updates ESM import paths/mocks. |
| test/lib/configuration/nest-configuration.loader.spec.ts | Migrates to Vitest and updates ESM import paths. |
| test/lib/compiler/webpack/webpack-compiler.spec.ts | Adds coverage for webpack compiler deprecation + ESM rejection behavior. |
| test/lib/compiler/swc/swc-compiler.spec.ts | Updates SWC compiler unit tests for ESM module layout and Vitest mocks. |
| test/lib/compiler/rspack/rspack-defaults.spec.ts | Adds tests for new rspack defaults factory (incl. ESM mode). |
| test/lib/compiler/rspack/rspack-compiler.spec.ts | Adds unit tests for new rspack compiler behavior (watch, config merging). |
| test/lib/compiler/hooks/tsconfig-paths.hook.spec.ts | Reworks hook tests to assert both CJS and ESM output (drops snapshots). |
| test/lib/compiler/hooks/fixtures/unused-imports/src/main.ts | Updates fixture imports to include .js extension for ESM. |
| test/lib/compiler/hooks/fixtures/type-imports/src/main.ts | Updates fixture relative imports to include .js extension for ESM. |
| test/lib/compiler/hooks/snapshots/tsconfig-paths.hook.spec.ts.snap | Removes Jest snapshots now that assertions are explicit. |
| test/lib/compiler/helpers/get-value-or-default.spec.ts | Migrates helper test to Vitest and ESM import specifiers. |
| test/lib/compiler/helpers/get-rspack-config-path.spec.ts | Adds tests for new rspack config-path helper. |
| test/jest-config.json | Removes Jest test configuration. |
| test/e2e/new.command.e2e-spec.ts | Adds e2e coverage for nest new behaviors (language, strict, flags). |
| test/e2e/jest-e2e.json | Adds fixture Jest config used by generated projects in e2e scenarios. |
| test/e2e/info.command.e2e-spec.ts | Adds e2e coverage for nest info with/without deps installed. |
| test/e2e/helpers.ts | Adds shared e2e utilities for running/spawning CLI and scaffolding projects. |
| test/e2e/generate.command.e2e-spec.ts | Adds e2e coverage for nest generate across many schematic types/flags. |
| test/e2e/build.command.e2e-spec.ts | Adds e2e coverage for nest build (tsc/swc + monorepo webpack cases). |
| test/e2e/add.command.e2e-spec.ts | Adds e2e coverage for nest add (install + dry-run/skip-install). |
| test/actions/info.action.spec.ts | Migrates action tests to Vitest and adapts to private method access. |
| test/actions/build.action.spec.ts | Adds unit tests for builder dispatch behavior (webpack vs rspack). |
| package.json | Marks package as ESM, switches to Vitest scripts, updates deps/peers, replaces clean step. |
| lib/utils/tree-kill.ts | Renames internals to clearer “children” naming. |
| lib/utils/remaining-flags.ts | Updates commander integration to use Command + getOptionValue(). |
| lib/utils/project-utils.ts | Removes hasValidOptionFlag and updates imports for ESM layout. |
| lib/utils/local-binaries.ts | Converts local command loader to async ESM import of local CLI commands. |
| lib/utils/load-configuration.ts | Updates imports for ESM layout. |
| lib/utils/is-module-available.ts | Uses createRequire for ESM-safe module resolution. |
| lib/utils/is-esm-project.ts | Adds helper to detect ESM projects via package.json "type": "module". |
| lib/ui/messages.ts | Updates ESM import specifier for emojis module. |
| lib/ui/index.ts | Updates barrel exports to explicit .js specifiers. |
| lib/schematics/schematic.option.ts | Changes boolean option rendering to --flag=false for false. |
| lib/schematics/nest.collection.ts | Updates imports for ESM layout. |
| lib/schematics/index.ts | Updates barrel exports to explicit .js specifiers. |
| lib/schematics/custom.collection.ts | Updates NodeWorkflow import to explicit /index.js for ESM. |
| lib/schematics/collection.factory.ts | Updates imports for ESM layout. |
| lib/schematics/abstract.collection.ts | Updates imports for ESM layout. |
| lib/runners/yarn.runner.ts | Updates import specifier for ESM layout. |
| lib/runners/schematic.runner.ts | Reworks module-path resolution to be ESM-safe via createRequire. |
| lib/runners/runner.factory.ts | Changes unsupported runner behavior from warn+continue to throwing an Error. |
| lib/runners/pnpm.runner.ts | Updates import specifier for ESM layout. |
| lib/runners/npm.runner.ts | Updates import specifier for ESM layout. |
| lib/runners/index.ts | Updates barrel exports to explicit .js specifiers. |
| lib/runners/git.runner.ts | Updates import specifier for ESM layout. |
| lib/runners/abstract.runner.ts | Updates UI import for ESM layout and aligns variable naming with lint config. |
| lib/readers/index.ts | Updates barrel exports to explicit .js specifiers. |
| lib/readers/file-system.reader.ts | Updates reader import specifier for ESM layout. |
| lib/questions/questions.ts | Removes any return annotation from generateInput factory. |
| lib/package-managers/yarn.package-manager.ts | Updates imports for ESM layout. |
| lib/package-managers/pnpm.package-manager.ts | Updates imports for ESM layout. |
| lib/package-managers/package-manager.factory.ts | Updates imports for ESM layout and simplifies catch handling. |
| lib/package-managers/npm.package-manager.ts | Updates imports for ESM layout. |
| lib/package-managers/index.ts | Updates barrel exports to explicit .js specifiers. |
| lib/package-managers/abstract.package-manager.ts | Migrates to fs/promises, ESM ora import, and tightens typing for package.json reads. |
| lib/configuration/nest-configuration.loader.ts | Updates imports, fixes a typo in comment, and simplifies defaulting logic. |
| lib/configuration/index.ts | Updates barrel exports to explicit .js specifiers. |
| lib/configuration/defaults.ts | Updates imports and adds default rspack config filename constant. |
| lib/configuration/configuration.ts | Extends builder types to include rspack and tightens several type definitions. |
| lib/configuration/configuration.loader.ts | Updates import specifier for ESM layout. |
| lib/compiler/webpack-compiler.ts | Adds webpack deprecation messaging, ESM project guard, and lazy-loads webpack deps. |
| lib/compiler/watch-compiler.ts | Updates imports for ESM layout. |
| lib/compiler/typescript-loader.ts | Reworks TS binary resolution for ESM (no module.paths reliance). |
| lib/compiler/swc/type-checker-host.ts | Updates imports and logs type-check errors to stderr. |
| lib/compiler/swc/swc-compiler.ts | ESM migration (createRequire/dirname), better error handling, and safer deep-merge own-property checks. |
| lib/compiler/swc/forked-type-checker.ts | Updates imports and sends errors to stderr. |
| lib/compiler/swc/constants.ts | Removes unused constant. |
| lib/compiler/rspack-compiler.ts | Introduces new Rspack compiler implementation with watch/build flows. |
| lib/compiler/plugins/plugins-loader.ts | ESM-safe plugin resolution via createRequire, fixes PluginAndOptions typing, improves error causes. |
| lib/compiler/plugins/plugin-metadata-printer.ts | Updates import specifier for ESM layout. |
| lib/compiler/plugins/plugin-metadata-generator.ts | Updates imports for ESM layout. |
| lib/compiler/hooks/tsconfig-paths.hook.ts | ESM-safe resolution updates and removes os.platform() dependency. |
| lib/compiler/helpers/tsconfig-provider.ts | Updates imports for ESM layout. |
| lib/compiler/helpers/get-webpack-config-path.ts | Updates signature to accept option records instead of Input[] arrays. |
| lib/compiler/helpers/get-value-or-default.ts | Changes option handling from Input[] to Record-based access for context objects. |
| lib/compiler/helpers/get-tsc-config.path.ts | Updates signature to accept option records instead of Input[] arrays. |
| lib/compiler/helpers/get-rspack-config-path.ts | Adds helper for rspack config path resolution from builder config. |
| lib/compiler/helpers/get-builder.ts | Updates signature to accept option records instead of Input[] arrays. |
| lib/compiler/helpers/delete-out-dir.ts | Updates imports for ESM layout. |
| lib/compiler/defaults/webpack-defaults.ts | Lazy-loads webpack-related deps and improves missing-dep errors for optional installation. |
| lib/compiler/defaults/swc-defaults.ts | Updates imports for ESM layout. |
| lib/compiler/defaults/rspack-defaults.ts | Adds rspack defaults factory with ESM/CJS support and optional plugin integration. |
| lib/compiler/compiler.ts | Updates imports and tightens extra arg typing. |
| lib/compiler/base-compiler.ts | Refines abstract method return types and restricts some methods to protected. |
| lib/compiler/assets-manager.ts | Updates imports and improves error message typing with cause. |
| gulpfile.js | Removes legacy gulp entrypoint for cleaning/build tooling. |
| eslint.config.js | Adds new flat-config ESLint setup for TS/ESM repo layout. |
| commands/start.command.ts | Migrates to context-based action invocation and updates commander types. |
| commands/new.command.ts | Migrates to context-based action invocation and updates language normalization logic. |
| commands/info.command.ts | Updates commander types and ESM imports. |
| commands/index.ts | Updates exports and adds context exports. |
| commands/generate.command.ts | Migrates to context-based invocation and updates --spec option default semantics. |
| commands/context/start.context.ts | Adds typed context interface for start command. |
| commands/context/new.context.ts | Adds typed context interface for new command. |
| commands/context/index.ts | Adds context barrel exports. |
| commands/context/generate.context.ts | Adds typed context interface for generate command. |
| commands/context/build.context.ts | Adds typed context interface for build command. |
| commands/context/add.context.ts | Adds typed context interface for add command. |
| commands/command.loader.ts | Adds ESM compatibility guard for global/local CLI mismatches and improves invalid command handling. |
| commands/build.command.ts | Migrates to context-based action invocation and adds rspack to builder help text. |
| commands/add.command.ts | Migrates to context-based action invocation and passes through remaining flags. |
| commands/abstract.command.ts | Updates commander type usage for ESM migration. |
| bin/nest.ts | Switches to new Command() for ESM, marks program as ESM-compatible, awaits local loader import. |
| actions/start.action.ts | Refactors to accept StartCommandContext and adapts runBuild/start lifecycle to ESM. |
| actions/new.action.ts | Refactors to accept NewCommandContext and updates prompting + schematic option mapping. |
| actions/info.action.ts | Refactors internal methods to private, uses padEnd, and updates ESM imports. |
| actions/index.ts | Updates exports to explicit .js specifiers. |
| actions/generate.action.ts | Refactors to accept GenerateCommandContext and updates schematic-option mapping. |
| actions/build.action.ts | Refactors to context-based inputs, adds rspack builder support, and updates ESM imports/dynamic imports. |
| actions/add.action.ts | Refactors to AddCommandContext and removes reliance on Input[] option scanning. |
| actions/abstract.action.ts | Simplifies AbstractAction API to a single context parameter. |
| .eslintrc.js | Removes legacy ESLint RC config in favor of flat config. |
| .eslintignore | Removes legacy ignore file (handled in flat config). |
| .circleci/config.yml | Updates CI to run Vitest and adds separate e2e job. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
|
@kamilmysliwiec I've opened a new pull request, #3282, to work on those changes. Once the pull request is ready, I'll request review from you. |
|
@kamilmysliwiec I've opened a new pull request, #3283, to work on those changes. Once the pull request is ready, I'll request review from you. |
|
@kamilmysliwiec I've opened a new pull request, #3284, to work on those changes. Once the pull request is ready, I'll request review from you. |
|
@kamilmysliwiec I've opened a new pull request, #3285, to work on those changes. Once the pull request is ready, I'll request review from you. |
The build and start commands print an error when --builder receives an unknown value, but then return from the action handler so the process still exits 0. CI pipelines and shell scripts cannot detect the failure and silently keep going on a misconfigured invocation. Replace the bare return with process.exit(1) so the validation error surfaces with the same exit code as other CLI input errors (see extra-args-warning, invalid command). Apply the same fix to the already-validated --parallel option in build. Add unit tests under test/commands/ that drive each command through commander's parseAsync and assert process.exit(1) on invalid input, that valid builder values are forwarded to the action context, and that omitting --builder skips validation.
The watch-mode branch in `TypeCheckerHost.run` started the ora spinner but never wrapped `runInWatchMode` in try/catch. If watch setup threw (invalid tsconfig path, parse failure, `createWatchProgram` rejection), the error propagated out while the spinner was left spinning forever on stdout — masking the real failure with a frozen UI element. Mirror the non-watch branch: wrap the watch setup in try/catch so `spinner.fail()` is called before the error is rethrown. The non-watch branch already does this, so this aligns behavior across the two paths. Adds three tests: - happy-path watch setup still calls `spinner.succeed` - tsconfig parsing error in watch mode -> `spinner.fail` + rethrow - `createWatchProgram` error in watch mode -> `spinner.fail` + rethrow
`closeWatchers` was declared without a return, but its body kicked off `Promise.all(readyPromises).then(...)` and dropped the chain on the floor. Two callers — `actions/build.action.ts` and `lib/compiler/swc/swc-compiler.ts` — already do `await assetsManager.closeWatchers()`, expecting to wait until every chokidar watcher has actually been closed. Awaiting `undefined` resolves on the next microtask, so the build process raced ahead while the watchers were still open, leaving file handles dangling and (in swc + watchAssets configs) sometimes preventing the build from exiting cleanly. Make `closeWatchers` async, return a real `Promise<void>`, and await `watcher.close()` (chokidar v3+ returns a promise from `close()`) so the build only proceeds once every watcher has fully released. Adds two regression tests covering the new contract: callers don't see resolution until every `watcher.close()` settles, and a rejected `close()` propagates instead of being silently swallowed.
…ager-coverage test(package-managers): cover abstract.package-manager flows
test(runners): cover bun runner in factory and implementations
…code fix(cli): exit with non-zero code on invalid --builder option
…h-spinner-cleanup fix(swc): stop spinner when watch-mode type checker setup throws
…watchers-await fix(assets-manager): await watcher close so build waits properly
test(utils): cover local-binaries exists check and command loader
test(ui): cover banner, emojis, errors, messages, and prefixes exports
test(new): cover language normalization and option forwarding
test(utils): cover tree-kill platform paths and esrch tolerance
…ter-coverage test(plugins): cover plugin-metadata-printer output and filename options
It was already included in the dependency tree through glob, but we shouldn't use it if it isn't a direct dependency. We need minimatch for upcoming changes
feat: respect tsconfig excludes when using swc
PR Checklist
Please check if your PR fulfills the following requirements:
PR Type
What kind of change does this PR introduce?
Description
Approximate release window: early Q3 2026
A brief list of changes:
nest newwill now prompt users asking whether they want to use ESM or CJS for their project (ESM is the new default withvitestinstead ofjest)jest->vitestfor testswebpackbuilder has been deprecatedrspackis the new default for monoreposeslinttooxlintbunadded as a supported package managerDoes this PR introduce a breaking change?
Other information