@nx/vitest 24.0.0-beta.2 → 24.0.0-beta.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (37) hide show
  1. package/dist/executors.d.ts +0 -1
  2. package/dist/executors.js +0 -3
  3. package/dist/internal.d.ts +1 -0
  4. package/dist/internal.js +3 -1
  5. package/dist/src/generators/configuration/configuration.js +1 -2
  6. package/dist/src/generators/configuration/schema.d.ts +0 -1
  7. package/dist/src/generators/init/init.js +4 -24
  8. package/dist/src/generators/init/schema.d.ts +0 -1
  9. package/dist/src/generators/init/schema.json +0 -5
  10. package/dist/src/migrations/update-24-0-0/finish-inferred-conversion.md +12 -0
  11. package/dist/src/migrations/update-24-0-0/remove-deprecated-executors.d.ts +6 -0
  12. package/dist/src/migrations/update-24-0-0/remove-deprecated-executors.js +10 -0
  13. package/dist/src/migrations/update-24-0-0/remove-deprecated-executors.md +52 -0
  14. package/dist/src/utils/executor-utils.d.ts +0 -1
  15. package/dist/src/utils/executor-utils.js +0 -4
  16. package/dist/src/utils/generator-utils.d.ts +0 -1
  17. package/dist/src/utils/generator-utils.js +54 -42
  18. package/dist/src/utils/versions.d.ts +2 -0
  19. package/dist/src/utils/versions.js +3 -1
  20. package/dist/src/utils/vite-config-edit-utils.d.ts +7 -1
  21. package/dist/src/utils/vite-config-edit-utils.js +90 -1
  22. package/executors.json +1 -7
  23. package/migrations.json +7 -0
  24. package/package.json +5 -5
  25. package/dist/src/executors/test/compat.d.ts +0 -2
  26. package/dist/src/executors/test/compat.js +0 -6
  27. package/dist/src/executors/test/lib/nx-reporter.d.ts +0 -18
  28. package/dist/src/executors/test/lib/nx-reporter.js +0 -39
  29. package/dist/src/executors/test/lib/utils.d.ts +0 -11
  30. package/dist/src/executors/test/lib/utils.js +0 -120
  31. package/dist/src/executors/test/schema.json +0 -42
  32. package/dist/src/executors/test/vitest.impl.d.ts +0 -6
  33. package/dist/src/executors/test/vitest.impl.js +0 -63
  34. package/dist/src/utils/deprecation.d.ts +0 -3
  35. package/dist/src/utils/deprecation.js +0 -19
  36. package/dist/src/utils/options-utils.d.ts +0 -7
  37. package/dist/src/utils/options-utils.js +0 -41
@@ -1,2 +1 @@
1
1
  export { VitestExecutorOptions } from './src/executors/test/schema';
2
- export { vitestExecutor } from './src/executors/test/vitest.impl';
package/dist/executors.js CHANGED
@@ -1,5 +1,2 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.vitestExecutor = void 0;
4
- var vitest_impl_1 = require("./src/executors/test/vitest.impl");
5
- Object.defineProperty(exports, "vitestExecutor", { enumerable: true, get: function () { return vitest_impl_1.vitestExecutor; } });
@@ -5,3 +5,4 @@
5
5
  */
6
6
  export declare const oxlintPlugins: string[];
7
7
  export { createOrEditViteConfig, ViteConfigFileOptions, } from './src/utils/generator-utils';
8
+ export { convertToInferred as convertVitestToInferred } from './src/generators/convert-to-inferred/convert-to-inferred';
package/dist/internal.js CHANGED
@@ -5,7 +5,7 @@
5
5
  // internal consumers and may change without semver protection. Mirrors
6
6
  // `@nx/devkit/internal`.
7
7
  Object.defineProperty(exports, "__esModule", { value: true });
8
- exports.createOrEditViteConfig = exports.oxlintPlugins = void 0;
8
+ exports.convertVitestToInferred = exports.createOrEditViteConfig = exports.oxlintPlugins = void 0;
9
9
  /**
10
10
  * The Oxlint plugins a Vitest-tested project needs. Declared here so the linter
11
11
  * does not have to know what a test runner requires; `@nx/js`'s
@@ -14,3 +14,5 @@ exports.createOrEditViteConfig = exports.oxlintPlugins = void 0;
14
14
  exports.oxlintPlugins = ['vitest'];
15
15
  var generator_utils_1 = require("./src/utils/generator-utils");
16
16
  Object.defineProperty(exports, "createOrEditViteConfig", { enumerable: true, get: function () { return generator_utils_1.createOrEditViteConfig; } });
17
+ var convert_to_inferred_1 = require("./src/generators/convert-to-inferred/convert-to-inferred");
18
+ Object.defineProperty(exports, "convertVitestToInferred", { enumerable: true, get: function () { return convert_to_inferred_1.convertToInferred; } });
@@ -50,7 +50,7 @@ function shouldUseVitestConfig(tree, projectRoot, uiFramework) {
50
50
  * @param hasPlugin some frameworks (e.g. Nuxt) provide their own plugin. Their generators handle the plugin detection.
51
51
  */
52
52
  function configurationGenerator(tree, schema, hasPlugin = false) {
53
- return configurationGeneratorInternal(tree, { addPlugin: false, ...schema }, hasPlugin);
53
+ return configurationGeneratorInternal(tree, schema, hasPlugin);
54
54
  }
55
55
  async function configurationGeneratorInternal(tree, schema, hasPlugin = false) {
56
56
  (0, assert_supported_vitest_version_1.assertSupportedVitestVersion)(tree);
@@ -76,7 +76,6 @@ async function configurationGeneratorInternal(tree, schema, hasPlugin = false) {
76
76
  }
77
77
  const initTask = await (0, init_1.default)(tree, {
78
78
  skipFormat: true,
79
- addPlugin: schema.addPlugin,
80
79
  projectRoot: root,
81
80
  viteVersion: schema.viteVersion,
82
81
  skipPackageJson: schema.skipPackageJson,
@@ -8,7 +8,6 @@ export interface VitestGeneratorSchema {
8
8
  skipFormat?: boolean;
9
9
  skipPackageJson?: boolean;
10
10
  testEnvironment?: 'node' | 'jsdom' | 'happy-dom' | 'edge-runtime' | string;
11
- addPlugin?: boolean;
12
11
  runtimeTsconfigFileName?: string;
13
12
  compiler?: 'babel' | 'swc'; // default: babel
14
13
  passWithNoTests?: boolean;
@@ -47,34 +47,14 @@ function updateNxJsonSettings(tree) {
47
47
  productionFileSet.push('!{projectRoot}/**/?(*.)+(spec|test).[jt]s?(x)?(.snap)', '!{projectRoot}/tsconfig.spec.json');
48
48
  nxJson.namedInputs.production = Array.from(new Set(productionFileSet));
49
49
  }
50
- const hasPlugin = nxJson.plugins?.some((p) => typeof p === 'string' ? p === '@nx/vitest' : p.plugin === '@nx/vitest');
51
- if (!hasPlugin) {
52
- const existing = (0, internal_1.findTargetDefault)(nxJson.targetDefaults, {
53
- executor: '@nx/vitest:test',
54
- });
55
- (0, internal_1.upsertTargetDefault)(tree, nxJson, {
56
- executor: '@nx/vitest:test',
57
- cache: existing?.cache ?? true,
58
- inputs: existing?.inputs ?? [
59
- 'default',
60
- productionFileSet ? '^production' : '^default',
61
- ],
62
- });
63
- }
64
50
  (0, devkit_1.updateNxJson)(tree, nxJson);
65
51
  }
66
52
  async function initGenerator(tree, schema) {
67
53
  (0, assert_supported_vitest_version_1.assertSupportedVitestVersion)(tree);
68
- const nxJson = (0, devkit_1.readNxJson)(tree);
69
- const addPluginDefault = process.env.NX_ADD_PLUGINS !== 'false' &&
70
- nxJson.useInferencePlugins !== false;
71
- schema.addPlugin ??= addPluginDefault;
72
- if (schema.addPlugin) {
73
- await (0, internal_1.addPlugin)(tree, await (0, devkit_1.createProjectGraphAsync)(), '@nx/vitest', plugin_1.createNodesV2, {
74
- testTargetName: ['test', 'vitest:test', 'vitest-test'],
75
- ciTargetName: ['test-ci', 'vitest:test-ci', 'vitest-test-ci'],
76
- }, schema.updatePackageScripts);
77
- }
54
+ await (0, internal_1.addPlugin)(tree, await (0, devkit_1.createProjectGraphAsync)(), '@nx/vitest', plugin_1.createNodesV2, {
55
+ testTargetName: ['test', 'vitest:test', 'vitest-test'],
56
+ ciTargetName: ['test-ci', 'vitest:test-ci', 'vitest-test-ci'],
57
+ }, schema.updatePackageScripts);
78
58
  updateNxJsonSettings(tree);
79
59
  await (0, ignore_vitest_temp_files_1.ignoreVitestTempFiles)(tree, schema.projectRoot);
80
60
  const tasks = [];
@@ -1,5 +1,4 @@
1
1
  export interface InitGeneratorSchema {
2
- addPlugin?: boolean;
3
2
  rootProject?: boolean;
4
3
  keepExistingVersions?: boolean;
5
4
  projectRoot?: string;
@@ -5,11 +5,6 @@
5
5
  "type": "object",
6
6
  "description": "Vitest init generator.",
7
7
  "properties": {
8
- "addPlugin": {
9
- "type": "boolean",
10
- "x-priority": "internal",
11
- "description": "Add plugin to nx.json. Defaults to true for new workspaces."
12
- },
13
8
  "rootProject": {
14
9
  "type": "boolean",
15
10
  "x-priority": "internal"
@@ -0,0 +1,12 @@
1
+ # Replace removed @nx/vitest executors with inferred tasks
2
+
3
+ Nx 24 removed `@nx/vitest:test` (including old `@nrwl` aliases).
4
+
5
+ Before changing anything, check for leftover work: a project target, a package.json target or a `targetDefaults` entry still uses a removed executor, or the advisory context reports a conversion error. If none applies, make no changes and stop. Treat each advisory-context item as pending work.
6
+
7
+ 1. Inspect all affected projects and workspace defaults. Repair config-loading errors first. Do not restore executor registrations or install older Nx packages.
8
+ 2. Preserve Vitest config paths, environments, setup files, coverage and watch/CI behavior.
9
+ 3. Register `@nx/vitest` with options/includes that preserve custom target names and mixed inferred/explicit projects. Replace remaining removed-executor targets, including those in package.json and filtered targetDefaults. Transfer their behavior before removing obsolete defaults. Preserve configurations, dependencies, cache inputs/outputs and environment behavior. Do not silently delete unsupported options or unrelated targets. Migrate old @nrwl aliases too.
10
+ 4. Run project graph creation with the daemon and graph cache disabled (`NX_DAEMON=false NX_CACHE_PROJECT_GRAPH=false`), using the workspace package manager. Inspect resolved project targets and verify each migrated entrypoint exists and is inferred (a thin alias to an inferred target is acceptable). Resolve graph errors before completing this migration, even if task validation was skipped. Configs must load for subsequent migrations.
11
+ 5. By default run relevant real builds/tests with task cache disabled, including alternate configurations. Honor an existing preference to skip expensive task validation; otherwise offer that option when validation is slow. Skipping expensive tasks never skips conversion or the graph check. Report each skipped task as unverified. Never weaken assertions or change application behavior to make checks pass.
12
+ 6. Report converted projects, graph validation, task results and any skipped checks. Unconverted targets or a broken graph mean the migration is incomplete. Investigate task failures and distinguish missing environment prerequisites from conversion regressions; do not claim a working workspace with unresolved regressions.
@@ -0,0 +1,6 @@
1
+ import type { Tree } from '@nx/devkit';
2
+ export default function update(tree: Tree): Promise<{
3
+ nextSteps?: string[];
4
+ agentContext?: string[];
5
+ skipAgentic?: boolean;
6
+ }>;
@@ -0,0 +1,10 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.default = update;
4
+ const internal_1 = require("@nx/devkit/internal");
5
+ function update(tree) {
6
+ return (0, internal_1.migrateRemovedExecutors)(tree, ['@nx/vitest:test', '@nrwl/vitest:test'], async (tree, options) => {
7
+ const { convertToInferred } = require('../../generators/convert-to-inferred/convert-to-inferred');
8
+ return convertToInferred(tree, options);
9
+ });
10
+ }
@@ -0,0 +1,52 @@
1
+ #### Convert `@nx/vitest:test` targets to inferred tasks
2
+
3
+ Nx 24 removes the `@nx/vitest:test` executor. The migration registers `@nx/vitest` in `nx.json` and converts the targets that use those executors to inferred tasks. Options the plugin does not infer stay on the target. A target with nothing left to override is removed from project configuration. When several projects share the same remaining options, those options move to a `targetDefaults` entry scoped to the plugin. `targetDefaults` entries keyed by a removed executor are removed once no target uses that executor.
4
+
5
+ The migration lists the targets the converter cannot convert safely. In agentic runs, an AI prompt finishes them and validates the project graph.
6
+
7
+ #### Sample code changes
8
+
9
+ ##### Before
10
+
11
+ ```json title="myapp/project.json"
12
+ {
13
+ "name": "myapp",
14
+ "targets": {
15
+ "test": {
16
+ "executor": "@nx/vitest:test",
17
+ "options": {
18
+ "configFile": "myapp/vite.config.ts"
19
+ }
20
+ }
21
+ }
22
+ }
23
+ ```
24
+
25
+ ##### After
26
+
27
+ ```json title="myapp/project.json"
28
+ {
29
+ "name": "myapp",
30
+ "targets": {
31
+ "test": {
32
+ "options": {
33
+ "config": "./vite.config.ts"
34
+ }
35
+ }
36
+ }
37
+ }
38
+ ```
39
+
40
+ ```json title="nx.json"
41
+ {
42
+ "plugins": [
43
+ {
44
+ "plugin": "@nx/vitest",
45
+ "options": {
46
+ "testMode": "watch",
47
+ "testTargetName": "test"
48
+ }
49
+ }
50
+ ]
51
+ }
52
+ ```
@@ -1,3 +1,2 @@
1
1
  export declare function loadViteDynamicImport(): Promise<typeof import('vite')>;
2
- export declare function loadVitestDynamicImport(): Promise<typeof import('vitest/node')>;
3
2
  export declare function loadVitestConfigDynamicImport(): Promise<typeof import('vitest/config')>;
@@ -1,14 +1,10 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.loadViteDynamicImport = loadViteDynamicImport;
4
- exports.loadVitestDynamicImport = loadVitestDynamicImport;
5
4
  exports.loadVitestConfigDynamicImport = loadVitestConfigDynamicImport;
6
5
  function loadViteDynamicImport() {
7
6
  return Function('return import("vite")')();
8
7
  }
9
- function loadVitestDynamicImport() {
10
- return Function('return import("vitest/node")')();
11
- }
12
8
  function loadVitestConfigDynamicImport() {
13
9
  return Function('return import("vitest/config")')();
14
10
  }
@@ -10,7 +10,6 @@ export interface VitestGeneratorSchema {
10
10
  testTarget?: string;
11
11
  skipFormat?: boolean;
12
12
  testEnvironment?: 'node' | 'jsdom' | 'happy-dom' | 'edge-runtime' | string;
13
- addPlugin?: boolean;
14
13
  runtimeTsconfigFileName?: string;
15
14
  compiler?: 'babel' | 'swc';
16
15
  projectType?: 'application' | 'library';
@@ -5,13 +5,13 @@ exports.createOrEditViteConfig = createOrEditViteConfig;
5
5
  const devkit_1 = require("@nx/devkit");
6
6
  const internal_1 = require("@nx/js/internal");
7
7
  const vite_config_edit_utils_1 = require("./vite-config-edit-utils");
8
- const deprecation_1 = require("./deprecation");
8
+ const version_utils_1 = require("./version-utils");
9
9
  const versions_1 = require("./versions");
10
10
  function addOrChangeTestTarget(tree, options, hasPlugin) {
11
11
  const nxJson = (0, devkit_1.readNxJson)(tree);
12
12
  const target = options.testTarget ?? 'test';
13
- // The plugin only infers the target names it is registered for, so a request
14
- // for any other name still needs an explicit target.
13
+ // The plugin only infers the target names it is registered for, so any other
14
+ // name gets its own project-scoped plugin registration below.
15
15
  hasPlugin ||=
16
16
  nxJson.plugins?.some((p) => {
17
17
  if (typeof p === 'string') {
@@ -28,23 +28,16 @@ function addOrChangeTestTarget(tree, options, hasPlugin) {
28
28
  return;
29
29
  }
30
30
  const project = (0, devkit_1.readProjectConfiguration)(tree, options.project);
31
- const reportsDirectory = (0, devkit_1.joinPathFragments)('coverage', project.root === '.' ? options.project : project.root);
32
- const testOptions = {
33
- reportsDirectory,
34
- };
35
- project.targets ??= {};
36
- if (project.targets[target]) {
31
+ if (project.targets?.[target]) {
37
32
  throw new Error(`Target "${target}" already exists in the project.`);
38
33
  }
39
- else {
40
- (0, deprecation_1.warnVitestExecutorGenerating)();
41
- project.targets[target] = {
42
- executor: '@nx/vitest:test',
43
- outputs: ['{options.reportsDirectory}'],
44
- options: testOptions,
45
- };
46
- }
47
- (0, devkit_1.updateProjectConfiguration)(tree, options.project, project);
34
+ nxJson.plugins ??= [];
35
+ nxJson.plugins.push({
36
+ plugin: '@nx/vitest',
37
+ include: [project.root === '.' ? '**/*' : `${project.root}/**/*`],
38
+ options: { testTargetName: target },
39
+ });
40
+ (0, devkit_1.updateNxJson)(tree, nxJson);
48
41
  }
49
42
  // Escape a value for emission inside a single-quoted source literal.
50
43
  function escapeLiteral(value) {
@@ -102,15 +95,29 @@ function createOrEditViteConfig(tree, options, onlyVitest, extraOptions = {}) {
102
95
  },`;
103
96
  const imports = options.imports ? [...options.imports] : [];
104
97
  const plugins = options.plugins ? [...options.plugins] : [];
98
+ const needsPaths = !isTsSolutionSetup && !extraOptions.skipNxPlugins;
99
+ const useNativePaths = needsPaths && ((0, version_utils_1.getInstalledViteMajorVersion)(tree) ?? 8) >= 8;
100
+ const dependencies = {};
101
+ if (needsPaths && !useNativePaths) {
102
+ imports.push(`import tsconfigPaths from 'vite-tsconfig-paths'`);
103
+ plugins.push('tsconfigPaths({ loose: true })');
104
+ dependencies['vite-tsconfig-paths'] = versions_1.viteTsconfigPathsVersion;
105
+ }
105
106
  if (!onlyVitest && options.includeLib && !isTsSolutionSetup) {
106
- imports.push(`import dts from 'vite-plugin-dts'`, `import * as path from 'path'`);
107
+ plugins.push(`import('vite-plugin-static-copy').then(({ viteStaticCopy }) => viteStaticCopy({
108
+ targets: [
109
+ { src: '*.md', dest: '.' },
110
+ { src: 'package.json', dest: '.', overwrite: false },
111
+ ],
112
+ silent: true,
113
+ }))`);
114
+ dependencies['vite-plugin-static-copy'] = versions_1.viteStaticCopyVersion;
107
115
  }
108
- if (!isTsSolutionSetup && !extraOptions.skipNxPlugins) {
109
- imports.push(`import { nxViteTsPaths } from '@nx/vite/plugins/nx-tsconfig-paths.plugin'`, `import { nxCopyAssetsPlugin } from '@nx/vite/plugins/nx-copy-assets.plugin'`);
110
- plugins.push(`nxViteTsPaths()`, `nxCopyAssetsPlugin(['*.md'])`);
111
- if (!extraOptions.skipPackageJson) {
112
- (0, devkit_1.addDependenciesToPackageJson)(tree, {}, { '@nx/vite': versions_1.nxVersion });
113
- }
116
+ if (!extraOptions.skipPackageJson && Object.keys(dependencies).length) {
117
+ (0, devkit_1.addDependenciesToPackageJson)(tree, {}, dependencies, undefined, true);
118
+ }
119
+ if (!onlyVitest && options.includeLib && !isTsSolutionSetup) {
120
+ imports.push(`import dts from 'vite-plugin-dts'`, `import * as path from 'path'`);
114
121
  }
115
122
  if (!onlyVitest && options.includeLib) {
116
123
  plugins.push(`dts({ entryRoot: 'src', tsconfigPath: path.join(import.meta.dirname, 'tsconfig.lib.json')${!isTsSolutionSetup ? ', pathsToAliases: false' : ''} })`);
@@ -169,23 +176,28 @@ ${options.inSourceTests
169
176
  port: ${options.previewPort ?? 4300},
170
177
  host: 'localhost',
171
178
  },`;
172
- const workerOption = isTsSolutionSetup
173
- ? ` // Uncomment this if you are using workers.
179
+ const workerOption = ` // Uncomment this if you are using workers.
174
180
  // worker: {
175
181
  // plugins: [],
176
- // },`
177
- : ` // Uncomment this if you are using workers.
178
- // worker: {
179
- // plugins: () => [ nxViteTsPaths() ],
180
182
  // },`;
181
183
  const aliasEntries = Object.entries(options.resolveAlias ?? {});
182
- const resolveOption = aliasEntries.length
183
- ? ` resolve: {
184
- alias: {
184
+ // Path-based workspace libraries need Vite's native tsconfig paths
185
+ // resolution, which is off by default. Workspaces on project references
186
+ // resolve through package.json instead.
187
+ const resolveTsconfigPaths = useNativePaths;
188
+ const resolveEntries = [
189
+ resolveTsconfigPaths ? ` tsconfigPaths: true,` : '',
190
+ aliasEntries.length
191
+ ? ` alias: {
185
192
  ${aliasEntries
186
- .map(([alias, target]) => ` '${escapeLiteral(alias)}': join(import.meta.dirname, '${escapeLiteral(target)}'),`)
187
- .join('\n')}
188
- },
193
+ .map(([alias, target]) => ` '${escapeLiteral(alias)}': join(import.meta.dirname, '${escapeLiteral(target)}'),`)
194
+ .join('\n')}
195
+ },`
196
+ : '',
197
+ ].filter(Boolean);
198
+ const resolveOption = resolveEntries.length
199
+ ? ` resolve: {
200
+ ${resolveEntries.join('\n')}
189
201
  },`
190
202
  : '';
191
203
  const cacheDir = `cacheDir: '${normalizedJoinPaths((0, devkit_1.offsetFromRoot)(projectRoot), 'node_modules', '.vite', projectRoot === '.' ? options.project : projectRoot)}',`;
@@ -193,7 +205,7 @@ ${aliasEntries
193
205
  if (aliasEntries.length) {
194
206
  devkit_1.logger.warn(`${viteConfigPath} already exists; the requested resolve.alias entries were not added to it.`);
195
207
  }
196
- handleViteConfigFileExists(tree, viteConfigPath, options, buildOption, buildOutDir, imports, plugins, testOption, reportsDirectory, cacheDir, projectRoot, (0, devkit_1.offsetFromRoot)(projectRoot), extraOptions.projectAlreadyHasViteTargets);
208
+ handleViteConfigFileExists(tree, viteConfigPath, options, buildOption, buildOutDir, imports, plugins, testOption, reportsDirectory, cacheDir, projectRoot, (0, devkit_1.offsetFromRoot)(projectRoot), extraOptions.projectAlreadyHasViteTargets, resolveTsconfigPaths);
197
209
  return;
198
210
  }
199
211
  if (aliasEntries.length) {
@@ -205,7 +217,7 @@ ${imports.join(';\n')}${imports.length ? ';' : ''}
205
217
 
206
218
  export default defineConfig(() => ({
207
219
  root: import.meta.dirname,
208
- ${printOptions(cacheDir, plugins.length ? ` plugins: [${plugins.join(', ')}],` : '', resolveOption, defineOption, testOption)}
220
+ ${printOptions(cacheDir, resolveOption, plugins.length ? ` plugins: [${plugins.join(', ')}],` : '', defineOption, testOption)}
209
221
  }));
210
222
  `.replace(/\s+(?=(\n|$))/gm, '\n')
211
223
  : `/// <reference types='vitest' />
@@ -214,7 +226,7 @@ ${imports.join(';\n')}${imports.length ? ';' : ''}
214
226
 
215
227
  export default defineConfig(() => ({
216
228
  root: import.meta.dirname,
217
- ${printOptions(cacheDir, devServerOption, previewServerOption, ` plugins: [${plugins.join(', ')}],`, resolveOption, workerOption, buildOption, defineOption, testOption)}
229
+ ${printOptions(cacheDir, devServerOption, previewServerOption, resolveOption, plugins.length ? ` plugins: [${plugins.join(', ')}],` : '', workerOption, buildOption, defineOption, testOption)}
218
230
  }));
219
231
  `.replace(/\s+(?=(\n|$))/gm, '\n');
220
232
  tree.write(viteConfigPath, viteConfigContent);
@@ -222,7 +234,7 @@ export default defineConfig(() => ({
222
234
  function printOptions(...options) {
223
235
  return options.filter(Boolean).join('\n');
224
236
  }
225
- function handleViteConfigFileExists(tree, viteConfigPath, options, buildOption, buildOutDir, imports, plugins, testOption, reportsDirectory, cacheDir, projectRoot, offsetFromRoot, projectAlreadyHasViteTargets) {
237
+ function handleViteConfigFileExists(tree, viteConfigPath, options, buildOption, buildOutDir, imports, plugins, testOption, reportsDirectory, cacheDir, projectRoot, offsetFromRoot, projectAlreadyHasViteTargets, resolveTsconfigPaths) {
226
238
  if (projectAlreadyHasViteTargets?.build &&
227
239
  projectAlreadyHasViteTargets?.test) {
228
240
  return;
@@ -267,7 +279,7 @@ function handleViteConfigFileExists(tree, viteConfigPath, options, buildOption,
267
279
  provider: `'${options.coverageProvider ?? 'v8'}'`,
268
280
  },
269
281
  };
270
- const changed = (0, vite_config_edit_utils_1.ensureViteConfigIsCorrect)(tree, viteConfigPath, buildOption, buildOptionObject, imports, plugins, testOption, testOptionObject, cacheDir, projectAlreadyHasViteTargets ?? {});
282
+ const changed = (0, vite_config_edit_utils_1.ensureViteConfigIsCorrect)(tree, viteConfigPath, buildOption, buildOptionObject, imports, plugins, testOption, testOptionObject, cacheDir, projectAlreadyHasViteTargets ?? {}, resolveTsconfigPaths);
271
283
  if (!changed) {
272
284
  devkit_1.logger.warn(`Make sure the following setting exists in your Vite configuration file (${viteConfigPath}):
273
285
 
@@ -30,4 +30,6 @@ type VitestVersions = {
30
30
  export declare function versions(tree: Tree, options?: VersionSelectionOptions): VitestVersions;
31
31
  export declare function getInstalledVitestVersion(tree?: Tree): string | null;
32
32
  export declare function getInstalledVitestMajorVersion(tree?: Tree): number | null;
33
+ export declare const viteTsconfigPathsVersion = "~4.3.2";
34
+ export declare const viteStaticCopyVersion = "^3.3.0";
33
35
  export {};
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.analogVitestAngular = exports.jitiVersion = exports.edgeRuntimeVmVersion = exports.happyDomVersion = exports.ajvVersion = exports.vitePluginDtsVersion = exports.jsdomVersion = exports.vitePluginReactSwcVersion = exports.vitePluginReactV4Version = exports.vitePluginReactVersion = exports.viteV5Version = exports.viteV6Version = exports.viteV7Version = exports.viteVersion = exports.vitestCoverageIstanbulVersion = exports.vitestCoverageV8Version = exports.vitestVersion = exports.minSupportedVitestVersion = exports.nxVersion = void 0;
3
+ exports.viteStaticCopyVersion = exports.viteTsconfigPathsVersion = exports.analogVitestAngular = exports.jitiVersion = exports.edgeRuntimeVmVersion = exports.happyDomVersion = exports.ajvVersion = exports.vitePluginDtsVersion = exports.jsdomVersion = exports.vitePluginReactSwcVersion = exports.vitePluginReactV4Version = exports.vitePluginReactVersion = exports.viteV5Version = exports.viteV6Version = exports.viteV7Version = exports.viteVersion = exports.vitestCoverageIstanbulVersion = exports.vitestCoverageV8Version = exports.vitestVersion = exports.minSupportedVitestVersion = exports.nxVersion = void 0;
4
4
  exports.versions = versions;
5
5
  exports.getInstalledVitestVersion = getInstalledVitestVersion;
6
6
  exports.getInstalledVitestMajorVersion = getInstalledVitestMajorVersion;
@@ -134,3 +134,5 @@ function getInstalledVitestMajorVersion(tree) {
134
134
  const installedVitestVersion = getInstalledVitestVersion(tree);
135
135
  return installedVitestVersion ? (0, semver_1.major)(installedVitestVersion) : null;
136
136
  }
137
+ exports.viteTsconfigPathsVersion = '~4.3.2';
138
+ exports.viteStaticCopyVersion = '^3.3.0';
@@ -1,3 +1,9 @@
1
1
  import { Tree } from '@nx/devkit';
2
2
  import { TargetFlags } from './generator-utils';
3
- export declare function ensureViteConfigIsCorrect(tree: Tree, path: string, buildConfigString: string, buildConfigObject: {}, imports: string[], plugins: string[], testConfigString: string, testConfigObject: {}, cacheDir: string, projectAlreadyHasViteTargets?: TargetFlags): boolean;
3
+ export declare function ensureViteConfigIsCorrect(tree: Tree, path: string, buildConfigString: string, buildConfigObject: {}, imports: string[], plugins: string[], testConfigString: string, testConfigObject: {}, cacheDir: string, projectAlreadyHasViteTargets?: TargetFlags, resolveTsconfigPaths?: boolean): boolean;
4
+ /**
5
+ * Enables Vite's native `resolve.tsconfigPaths`, which replaced the removed
6
+ * `nxViteTsPaths` plugin. Returns the file unchanged when it is already set or
7
+ * when the config's shape hides the object we would have to edit.
8
+ */
9
+ export declare function addTsconfigPathsResolution(appFileContent: string): string;
@@ -1,9 +1,10 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.ensureViteConfigIsCorrect = ensureViteConfigIsCorrect;
4
+ exports.addTsconfigPathsResolution = addTsconfigPathsResolution;
4
5
  const devkit_1 = require("@nx/devkit");
5
6
  const js_1 = require("@nx/js");
6
- function ensureViteConfigIsCorrect(tree, path, buildConfigString, buildConfigObject, imports, plugins, testConfigString, testConfigObject, cacheDir, projectAlreadyHasViteTargets) {
7
+ function ensureViteConfigIsCorrect(tree, path, buildConfigString, buildConfigObject, imports, plugins, testConfigString, testConfigObject, cacheDir, projectAlreadyHasViteTargets, resolveTsconfigPaths) {
7
8
  const fileContent = tree.read(path, 'utf-8');
8
9
  let updatedContent = undefined;
9
10
  if (!projectAlreadyHasViteTargets?.test && testConfigString?.length) {
@@ -18,6 +19,9 @@ function ensureViteConfigIsCorrect(tree, path, buildConfigString, buildConfigObj
18
19
  if (cacheDir?.length) {
19
20
  updatedContent = handleCacheDirNode(updatedContent ?? fileContent, cacheDir);
20
21
  }
22
+ if (resolveTsconfigPaths) {
23
+ updatedContent = addTsconfigPathsResolution(updatedContent ?? fileContent);
24
+ }
21
25
  if (updatedContent) {
22
26
  tree.write(path, updatedContent);
23
27
  return true;
@@ -301,6 +305,91 @@ function filterImport(appFileContent, imports) {
301
305
  return !importsArrayExisting?.includes(importString);
302
306
  });
303
307
  }
308
+ /**
309
+ * Enables Vite's native `resolve.tsconfigPaths`, which replaced the removed
310
+ * `nxViteTsPaths` plugin. Returns the file unchanged when it is already set or
311
+ * when the config's shape hides the object we would have to edit.
312
+ */
313
+ function addTsconfigPathsResolution(appFileContent) {
314
+ const { tsquery } = require('@phenomnomnominal/tsquery');
315
+ const tsModule = require('typescript');
316
+ const file = tsquery.ast(appFileContent);
317
+ const config = findConfigObject(tsModule, tsquery, file);
318
+ if (!config || config.properties.some(tsModule.isSpreadAssignment))
319
+ return appFileContent;
320
+ const existingResolve = config.properties.find((prop) => tsModule.isPropertyAssignment(prop) &&
321
+ stripQuotes(prop.name.getText()) === 'resolve');
322
+ if (existingResolve) {
323
+ const target = existingResolve.initializer;
324
+ if (!tsModule.isObjectLiteralExpression(target) ||
325
+ target.properties.some(tsModule.isSpreadAssignment))
326
+ return appFileContent;
327
+ if (target.properties.some((prop) => prop.name && stripQuotes(prop.name.getText()) === 'tsconfigPaths')) {
328
+ return appFileContent;
329
+ }
330
+ return (0, devkit_1.applyChangesToString)(appFileContent, [
331
+ {
332
+ type: devkit_1.ChangeType.Insert,
333
+ index: target.getStart() + 1,
334
+ text: `\n tsconfigPaths: true,`,
335
+ },
336
+ ]);
337
+ }
338
+ return (0, devkit_1.applyChangesToString)(appFileContent, [
339
+ {
340
+ type: devkit_1.ChangeType.Insert,
341
+ index: config.getStart() + 1,
342
+ text: `\n resolve: {\n tsconfigPaths: true,\n },`,
343
+ },
344
+ ]);
345
+ }
346
+ /**
347
+ * The object literal a Vite config ultimately exports. Handles `defineConfig`
348
+ * called with an object or with a factory, and a bare default export. Returns
349
+ * undefined when the config is assembled somewhere we cannot follow.
350
+ */
351
+ function findConfigObject(tsModule, tsquery, file) {
352
+ const exportAssignment = tsquery.query(file, 'ExportAssignment')[0];
353
+ if (exportAssignment) {
354
+ return unwrapConfigExpression(tsModule, exportAssignment.expression);
355
+ }
356
+ const moduleExports = tsquery.query(file, 'BinaryExpression').find((node) => node.left.getText() === 'module.exports' &&
357
+ node.operatorToken.kind === tsModule.SyntaxKind.EqualsToken);
358
+ return moduleExports
359
+ ? unwrapConfigExpression(tsModule, moduleExports.right)
360
+ : undefined;
361
+ }
362
+ function unwrapConfigExpression(tsModule, node) {
363
+ if (!node)
364
+ return undefined;
365
+ if (tsModule.isParenthesizedExpression(node)) {
366
+ return unwrapConfigExpression(tsModule, node.expression);
367
+ }
368
+ if (tsModule.isObjectLiteralExpression(node))
369
+ return node;
370
+ if (tsModule.isCallExpression(node) &&
371
+ node.expression.getText() === 'defineConfig') {
372
+ return unwrapConfigExpression(tsModule, node.arguments[0]);
373
+ }
374
+ if (tsModule.isArrowFunction(node) || tsModule.isFunctionExpression(node)) {
375
+ if (!tsModule.isBlock(node.body)) {
376
+ return unwrapConfigExpression(tsModule, node.body);
377
+ }
378
+ // Only a single, unconditional return is safe to edit.
379
+ if (node.body.statements.some((statement) => !tsModule.isReturnStatement(statement) &&
380
+ !tsModule.isVariableStatement(statement) &&
381
+ !tsModule.isExpressionStatement(statement)))
382
+ return undefined;
383
+ const returns = node.body.statements.filter(tsModule.isReturnStatement);
384
+ return returns.length === 1
385
+ ? unwrapConfigExpression(tsModule, returns[0].expression)
386
+ : undefined;
387
+ }
388
+ return undefined;
389
+ }
390
+ function stripQuotes(text) {
391
+ return text.replace(/^['"`]|['"`]$/g, '');
392
+ }
304
393
  function handleCacheDirNode(appFileContent, cacheDir) {
305
394
  const { tsquery } = require('@phenomnomnominal/tsquery');
306
395
  const file = tsquery.ast(appFileContent);
package/executors.json CHANGED
@@ -1,10 +1,4 @@
1
1
  {
2
2
  "$schema": "https://json-schema.org/schema",
3
- "executors": {
4
- "test": {
5
- "implementation": "./dist/src/executors/test/vitest.impl",
6
- "schema": "./dist/src/executors/test/schema.json",
7
- "description": "Test using Vitest"
8
- }
9
- }
3
+ "executors": {}
10
4
  }
package/migrations.json CHANGED
@@ -43,6 +43,13 @@
43
43
  "description": "Migrate workspaces past breaking changes for Vitest 5.",
44
44
  "implementation": "./dist/src/migrations/update-23-3-0/migrate-to-vitest-5",
45
45
  "prompt": "./dist/src/migrations/update-23-3-0/ai-instructions-for-vitest-5.md"
46
+ },
47
+ "remove-deprecated-executors": {
48
+ "version": "24.0.0-beta.3",
49
+ "description": "Converts targets using the removed `@nx/vitest` executors to inferred tasks; an AI prompt finishes the targets the converter cannot convert safely and validates the project graph.",
50
+ "implementation": "./dist/src/migrations/update-24-0-0/remove-deprecated-executors",
51
+ "prompt": "./dist/src/migrations/update-24-0-0/finish-inferred-conversion.md",
52
+ "documentation": "./dist/src/migrations/update-24-0-0/remove-deprecated-executors.md"
46
53
  }
47
54
  },
48
55
  "packageJsonUpdates": {
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@nx/vitest",
3
3
  "description": "The Nx Plugin for Vitest to enable fast unit testing with Vitest.",
4
- "version": "24.0.0-beta.2",
4
+ "version": "24.0.0-beta.3",
5
5
  "type": "commonjs",
6
6
  "files": [
7
7
  "dist",
@@ -78,14 +78,14 @@
78
78
  "executors": "./executors.json",
79
79
  "generators": "./generators.json",
80
80
  "dependencies": {
81
- "@nx/devkit": "24.0.0-beta.2",
82
- "@nx/js": "24.0.0-beta.2",
81
+ "@nx/devkit": "24.0.0-beta.3",
82
+ "@nx/js": "24.0.0-beta.3",
83
83
  "tslib": "^2.3.0",
84
84
  "semver": "^7.6.3",
85
85
  "@phenomnomnominal/tsquery": "~6.2.0"
86
86
  },
87
87
  "peerDependencies": {
88
- "@nx/eslint": "24.0.0-beta.2",
88
+ "@nx/eslint": "24.0.0-beta.3",
89
89
  "vitest": "^3.0.0 || ^4.0.0 || ^5.0.0",
90
90
  "vite": "^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0"
91
91
  },
@@ -101,6 +101,6 @@
101
101
  }
102
102
  },
103
103
  "devDependencies": {
104
- "nx": "24.0.0-beta.2"
104
+ "nx": "24.0.0-beta.3"
105
105
  }
106
106
  }
@@ -1,2 +0,0 @@
1
- declare const _default: any;
2
- export default _default;
@@ -1,6 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- const tslib_1 = require("tslib");
4
- const devkit_1 = require("@nx/devkit");
5
- const vitest_impl_1 = tslib_1.__importDefault(require("./vitest.impl"));
6
- exports.default = (0, devkit_1.convertNxExecutor)(vitest_impl_1.default);
@@ -1,18 +0,0 @@
1
- import type { Reporter, RunnerTestFile } from 'vitest/node';
2
- export declare class NxReporter implements Reporter {
3
- private watch;
4
- deferred: {
5
- promise: Promise<boolean>;
6
- resolve: (val: boolean) => void;
7
- };
8
- constructor(watch: boolean);
9
- [Symbol.asyncIterator](): AsyncGenerator<{
10
- hasErrors: boolean;
11
- }, void, unknown>;
12
- private setupDeferred;
13
- /** Vitest ≥ 0.29 */
14
- onTestRunEnd(files: any[], errors?: any): void;
15
- /** Vitest ≤ 0.28 */
16
- onFinished(files: RunnerTestFile[], errors?: unknown[]): void;
17
- private _handleFinished;
18
- }
@@ -1,39 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.NxReporter = void 0;
4
- class NxReporter {
5
- constructor(watch) {
6
- this.watch = watch;
7
- this.setupDeferred();
8
- }
9
- async *[Symbol.asyncIterator]() {
10
- do {
11
- const hasErrors = await this.deferred.promise;
12
- yield { hasErrors };
13
- this.setupDeferred();
14
- } while (this.watch);
15
- }
16
- setupDeferred() {
17
- let resolve;
18
- this.deferred = {
19
- promise: new Promise((res) => {
20
- resolve = res;
21
- }),
22
- resolve,
23
- };
24
- }
25
- /** Vitest ≥ 0.29 */
26
- onTestRunEnd(files, errors) {
27
- this._handleFinished(files, errors);
28
- }
29
- /** Vitest ≤ 0.28 */
30
- onFinished(files, errors) {
31
- this._handleFinished(files, errors);
32
- }
33
- // --- private ----------------------------------------------------------
34
- _handleFinished(files, errors) {
35
- const hasErrors = files.some((f) => f.result?.state === 'fail') || errors?.length > 0;
36
- this.deferred.resolve(hasErrors);
37
- }
38
- }
39
- exports.NxReporter = NxReporter;
@@ -1,11 +0,0 @@
1
- import { ExecutorContext } from '@nx/devkit';
2
- import { VitestExecutorOptions } from '../schema';
3
- export declare function getOptions(options: VitestExecutorOptions, context: ExecutorContext, projectRoot: string): Promise<Record<string, any>>;
4
- /**
5
- * Nx's resolveNxTokensInOptions strips {workspaceRoot}/ from option values,
6
- * leaving a workspace-root-relative path. However, vitest resolves
7
- * reportsDirectory relative to the project root. This function converts
8
- * the path to absolute so vitest resolves it correctly.
9
- */
10
- export declare function resolveReportsDirectory(reportsDirectory: string): string;
11
- export declare function getOptionsAsArgv(obj: Record<string, any>): string[];
@@ -1,120 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.getOptions = getOptions;
4
- exports.resolveReportsDirectory = resolveReportsDirectory;
5
- exports.getOptionsAsArgv = getOptionsAsArgv;
6
- const devkit_1 = require("@nx/devkit");
7
- const options_utils_1 = require("../../../utils/options-utils");
8
- const path_1 = require("path");
9
- const executor_utils_1 = require("../../../utils/executor-utils");
10
- const internal_1 = require("@nx/devkit/internal");
11
- async function getOptions(options, context, projectRoot) {
12
- // Allows ESM to be required in CJS modules. Vite will be published as ESM in the future.
13
- const { loadConfigFromFile } = await (0, executor_utils_1.loadViteDynamicImport)();
14
- const viteConfigPath = (0, options_utils_1.normalizeViteConfigFilePath)(context.root, projectRoot, options.configFile);
15
- if (!viteConfigPath) {
16
- throw new Error((0, devkit_1.stripIndents) `
17
- Unable to load test config from config file ${viteConfigPath}.
18
-
19
- Please make sure that vitest is configured correctly,
20
- or use the @nx/vitest:configuration generator to configure it for you.
21
- You can read more here: https://nx.dev/nx-api/vitest/generators/configuration
22
- `);
23
- }
24
- // Vitest derives the Vite config mode as `options.mode || runMode`, where
25
- // runMode defaults to 'test' (or 'benchmark'). Resolve it once and reuse it
26
- // for both this pre-load and the value forwarded to vitest below, so the
27
- // config file resolves its mode-based branches identically on both loads.
28
- const mode = options.mode ?? options.runMode ?? 'test';
29
- const resolved = await loadConfigFromFile({
30
- mode,
31
- command: 'serve',
32
- }, viteConfigPath);
33
- if (!resolved?.config?.['test']) {
34
- devkit_1.logger.warn((0, devkit_1.stripIndents) `Unable to load test config from config file ${resolved?.path ?? viteConfigPath}
35
- Some settings may not be applied as expected.
36
- You can manually set the config in the project, ${context.projectName}, configuration.
37
- `);
38
- }
39
- const root = projectRoot === '.'
40
- ? process.cwd()
41
- : (0, path_1.relative)(context.cwd, (0, devkit_1.joinPathFragments)(context.root, projectRoot));
42
- const { parseCLI } = await (0, executor_utils_1.loadVitestDynamicImport)();
43
- // Use parseCLI for Vitest-specific normalization/validation
44
- const { options: { watch, ...normalizedExtraArgs }, } = parseCLI(['vitest', ...getOptionsAsArgv(options)]);
45
- // Filter out options that are handled specially or are parseCLI artifacts
46
- const {
47
- // Handled specially by executor
48
- testFiles: _testFiles, configFile: _configFile, mode: _mode, runMode: _runMode, reportsDirectory, coverage, reporter, reporters,
49
- // parseCLI artifacts
50
- '--': _dashdash, color: _color, w: _w,
51
- // Pass through any additional Vitest options
52
- ...passThroughOptions } = normalizedExtraArgs;
53
- // Vitest keeps the UI/browser server alive only in watch mode and has no
54
- // --ui -> watch link, so a run-once `nx test --ui` tears the UI down right
55
- // after the run. When --ui is requested from an interactive, non-CI terminal,
56
- // default watch on so the UI stays open; bare runs and CI stay run-once so
57
- // `nx run-many`/`affected` don't hang. An explicit CLI --watch/--no-watch or a
58
- // config `test.watch` still takes precedence.
59
- const uiRequested = passThroughOptions.ui === true;
60
- const watchForUi = uiRequested && !!process.stdin.isTTY && !(0, internal_1.isCI)();
61
- return {
62
- watch: watch ??
63
- resolved?.config?.['test']?.watch ??
64
- watchForUi,
65
- // Pass through any additional Vitest options
66
- ...passThroughOptions,
67
- // This should not be needed as it's going to be set in vite.config.ts
68
- // but leaving it here in case someone did not migrate correctly
69
- root: resolved?.config?.root ?? root,
70
- config: viteConfigPath,
71
- // Forward the resolved mode so vitest reloads the config file with it;
72
- // otherwise it falls back to its run-mode default and drops mode-based
73
- // settings the pre-load above resolved (e.g. outputFile, coverage.reporter).
74
- mode,
75
- // Vitest's resolveConfig processes reporters in two steps:
76
- // 1. options.reporters (plural) sets resolved.reporters
77
- // 2. resolved.reporter (singular, from config) overwrites resolved.reporters
78
- // Setting reporter to [] prevents config's reporter from overriding NxReporter
79
- // (which is pushed onto reporters in vitest.impl.ts).
80
- reporter: [],
81
- reporters: reporter ??
82
- reporters ??
83
- // reporter (singular) has higher priority in vitest but is not declared in InlineConfig
84
- resolved?.config?.['test']?.reporter ??
85
- resolved?.config?.['test']?.reporters,
86
- coverage: {
87
- ...(coverage ?? {}),
88
- ...(reportsDirectory && {
89
- reportsDirectory: resolveReportsDirectory(reportsDirectory),
90
- }),
91
- },
92
- };
93
- }
94
- /**
95
- * Nx's resolveNxTokensInOptions strips {workspaceRoot}/ from option values,
96
- * leaving a workspace-root-relative path. However, vitest resolves
97
- * reportsDirectory relative to the project root. This function converts
98
- * the path to absolute so vitest resolves it correctly.
99
- */
100
- function resolveReportsDirectory(reportsDirectory) {
101
- if ((0, path_1.isAbsolute)(reportsDirectory)) {
102
- return reportsDirectory;
103
- }
104
- return (0, path_1.resolve)(devkit_1.workspaceRoot, reportsDirectory);
105
- }
106
- function getOptionsAsArgv(obj) {
107
- const argv = [];
108
- for (const [key, value] of Object.entries(obj)) {
109
- if (Array.isArray(value)) {
110
- value.forEach((item) => argv.push(`--${key}=${item}`));
111
- }
112
- else if (typeof value === 'object' && value !== null) {
113
- argv.push(`--${key}='${JSON.stringify(value)}'`);
114
- }
115
- else {
116
- argv.push(`--${key}=${value}`);
117
- }
118
- }
119
- return argv;
120
- }
@@ -1,42 +0,0 @@
1
- {
2
- "$schema": "https://json-schema.org/schema",
3
- "version": 2,
4
- "cli": "nx",
5
- "title": "Vitest executor",
6
- "description": "Test using Vitest.",
7
- "type": "object",
8
- "x-deprecated": "The `@nx/vitest:test` executor is deprecated and will be removed in Nx v24. Run `nx g @nx/vitest:convert-to-inferred` to migrate to the `@nx/vitest/plugin` inferred plugin. See https://nx.dev/docs/guides/tasks--caching/convert-to-inferred for details.",
9
- "properties": {
10
- "configFile": {
11
- "type": "string",
12
- "description": "The path to the local vitest config, relative to the workspace root.",
13
- "x-completion-type": "file",
14
- "x-completion-glob": "@(vitest|vite).config@(.js|.ts)",
15
- "aliases": ["config"]
16
- },
17
- "reportsDirectory": {
18
- "type": "string",
19
- "description": "Directory to write coverage report to."
20
- },
21
- "mode": {
22
- "type": "string",
23
- "description": "Vite mode for loading configuration."
24
- },
25
- "runMode": {
26
- "type": "string",
27
- "description": "Vitest execution mode.",
28
- "enum": ["test", "benchmark"],
29
- "default": "test"
30
- },
31
- "testFiles": {
32
- "aliases": ["testFile"],
33
- "type": "array",
34
- "items": { "type": "string" }
35
- },
36
- "watch": {
37
- "description": "Watch files for changes and rerun tests related to changed files.",
38
- "type": "boolean"
39
- }
40
- },
41
- "required": []
42
- }
@@ -1,6 +0,0 @@
1
- import { ExecutorContext } from '@nx/devkit';
2
- import { VitestExecutorOptions } from './schema';
3
- export declare function vitestExecutor(options: VitestExecutorOptions, context: ExecutorContext): AsyncGenerator<never, {
4
- success: boolean;
5
- }, unknown>;
6
- export default vitestExecutor;
@@ -1,63 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.vitestExecutor = vitestExecutor;
4
- const devkit_1 = require("@nx/devkit");
5
- const path_1 = require("path");
6
- const internal_1 = require("@nx/js/internal");
7
- const nx_reporter_1 = require("./lib/nx-reporter");
8
- const utils_1 = require("./lib/utils");
9
- const executor_utils_1 = require("../../utils/executor-utils");
10
- const deprecation_1 = require("../../utils/deprecation");
11
- async function* vitestExecutor(options, context) {
12
- (0, deprecation_1.warnVitestTestExecutorDeprecation)();
13
- const projectRoot = context.projectsConfigurations.projects[context.projectName].root;
14
- (0, internal_1.registerTsConfigPaths)((0, path_1.resolve)(devkit_1.workspaceRoot, projectRoot, 'tsconfig.json'));
15
- process.env.VITE_CJS_IGNORE_WARNING = 'true';
16
- // Allows ESM to be required in CJS modules. Vite will be published as ESM in the future.
17
- const { startVitest } = await (0, executor_utils_1.loadVitestDynamicImport)();
18
- const resolvedOptions = (await (0, utils_1.getOptions)(options, context, projectRoot)) ?? {};
19
- const watch = resolvedOptions['watch'] === true;
20
- const nxReporter = new nx_reporter_1.NxReporter(watch);
21
- if (resolvedOptions['reporters'] === undefined) {
22
- resolvedOptions['reporters'] = [];
23
- }
24
- else if (typeof resolvedOptions['reporters'] === 'string') {
25
- resolvedOptions['reporters'] = [resolvedOptions['reporters']];
26
- }
27
- resolvedOptions['reporters'].push(nxReporter);
28
- const cliFilters = options.testFiles ?? [];
29
- const ctx = await startVitest(options.runMode ?? 'test', cliFilters, resolvedOptions, {
30
- mode: options.mode ?? 'test',
31
- });
32
- let hasErrors = false;
33
- const processExit = () => {
34
- ctx.exit();
35
- if (hasErrors) {
36
- process.exit(1);
37
- }
38
- else {
39
- process.exit(0);
40
- }
41
- };
42
- if (watch) {
43
- process.on('SIGINT', processExit);
44
- process.on('SIGTERM', processExit);
45
- process.on('exit', processExit);
46
- }
47
- // vitest sets the exitCode in case of exception without notifying reporters
48
- if (process.exitCode === undefined ||
49
- (watch && ctx.state.getFiles().length > 0)) {
50
- for await (const report of nxReporter) {
51
- // vitest sets the exitCode = 1 when code coverage isn't met
52
- hasErrors =
53
- report.hasErrors || (process.exitCode && process.exitCode !== 0);
54
- }
55
- }
56
- else {
57
- hasErrors = process.exitCode !== 0;
58
- }
59
- return {
60
- success: !hasErrors,
61
- };
62
- }
63
- exports.default = vitestExecutor;
@@ -1,3 +0,0 @@
1
- export declare const VITEST_TEST_EXECUTOR_DEPRECATION_MESSAGE = "The `@nx/vitest:test` executor is deprecated and will be removed in Nx v24. Run `nx g @nx/vitest:convert-to-inferred` to migrate to the `@nx/vitest/plugin` inferred targets. See https://nx.dev/docs/guides/tasks--caching/convert-to-inferred for details.";
2
- export declare function warnVitestTestExecutorDeprecation(): void;
3
- export declare function warnVitestExecutorGenerating(): void;
@@ -1,19 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.VITEST_TEST_EXECUTOR_DEPRECATION_MESSAGE = void 0;
4
- exports.warnVitestTestExecutorDeprecation = warnVitestTestExecutorDeprecation;
5
- exports.warnVitestExecutorGenerating = warnVitestExecutorGenerating;
6
- const devkit_1 = require("@nx/devkit");
7
- // TODO(v24): Remove the @nx/vitest:test executor. The inferred plugin
8
- // (@nx/vitest/plugin) and the convert-to-inferred generator stay supported.
9
- exports.VITEST_TEST_EXECUTOR_DEPRECATION_MESSAGE = 'The `@nx/vitest:test` executor is deprecated and will be removed in Nx v24. Run `nx g @nx/vitest:convert-to-inferred` to migrate to the `@nx/vitest/plugin` inferred targets. See https://nx.dev/docs/guides/tasks--caching/convert-to-inferred for details.';
10
- function warnVitestTestExecutorDeprecation() {
11
- devkit_1.logger.warn(exports.VITEST_TEST_EXECUTOR_DEPRECATION_MESSAGE);
12
- }
13
- // Fired when the @nx/vitest:configuration generator is about to generate a
14
- // target that uses the deprecated executor — i.e. when @nx/vitest/plugin
15
- // isn't registered in nx.json. Surfaces the deprecation at generation time
16
- // rather than only when the user later runs the generated target.
17
- function warnVitestExecutorGenerating() {
18
- devkit_1.logger.warn('Generating a target that uses the deprecated `@nx/vitest:test` executor. This executor will be removed in Nx v24. Run `nx g @nx/vitest:convert-to-inferred` next to migrate this target to the `@nx/vitest/plugin` inferred plugin and prevent future generators from emitting executor targets. See https://nx.dev/docs/guides/tasks--caching/convert-to-inferred for details.');
19
- }
@@ -1,7 +0,0 @@
1
- import { ExecutorContext } from '@nx/devkit';
2
- /**
3
- * Returns the path to the vite config file or undefined when not found.
4
- */
5
- export declare function normalizeViteConfigFilePath(contextRoot: string, projectRoot: string, configFile?: string): string | undefined;
6
- export declare function getProjectTsConfigPath(projectRoot: string): string | undefined;
7
- export declare function getNxTargetOptions(target: string, context: ExecutorContext): any;
@@ -1,41 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.normalizeViteConfigFilePath = normalizeViteConfigFilePath;
4
- exports.getProjectTsConfigPath = getProjectTsConfigPath;
5
- exports.getNxTargetOptions = getNxTargetOptions;
6
- const devkit_1 = require("@nx/devkit");
7
- const fs_1 = require("fs");
8
- /**
9
- * Returns the path to the vite config file or undefined when not found.
10
- */
11
- function normalizeViteConfigFilePath(contextRoot, projectRoot, configFile) {
12
- if (configFile) {
13
- const normalized = (0, devkit_1.joinPathFragments)(contextRoot, configFile);
14
- if (!(0, fs_1.existsSync)(normalized)) {
15
- throw new Error(`Could not find vite config at provided path "${normalized}".`);
16
- }
17
- return normalized;
18
- }
19
- const allowsExt = ['js', 'mjs', 'ts', 'cjs', 'mts', 'cts'];
20
- for (const ext of allowsExt) {
21
- if ((0, fs_1.existsSync)((0, devkit_1.joinPathFragments)(contextRoot, projectRoot, `vite.config.${ext}`))) {
22
- return (0, devkit_1.joinPathFragments)(contextRoot, projectRoot, `vite.config.${ext}`);
23
- }
24
- else if ((0, fs_1.existsSync)((0, devkit_1.joinPathFragments)(contextRoot, projectRoot, `vitest.config.${ext}`))) {
25
- return (0, devkit_1.joinPathFragments)(contextRoot, projectRoot, `vitest.config.${ext}`);
26
- }
27
- }
28
- }
29
- function getProjectTsConfigPath(projectRoot) {
30
- return (0, fs_1.existsSync)((0, devkit_1.joinPathFragments)(devkit_1.workspaceRoot, projectRoot, 'tsconfig.app.json'))
31
- ? (0, devkit_1.joinPathFragments)(projectRoot, 'tsconfig.app.json')
32
- : (0, fs_1.existsSync)((0, devkit_1.joinPathFragments)(devkit_1.workspaceRoot, projectRoot, 'tsconfig.lib.json'))
33
- ? (0, devkit_1.joinPathFragments)(projectRoot, 'tsconfig.lib.json')
34
- : (0, fs_1.existsSync)((0, devkit_1.joinPathFragments)(devkit_1.workspaceRoot, projectRoot, 'tsconfig.json'))
35
- ? (0, devkit_1.joinPathFragments)(projectRoot, 'tsconfig.json')
36
- : undefined;
37
- }
38
- function getNxTargetOptions(target, context) {
39
- const targetObj = (0, devkit_1.parseTargetString)(target, context);
40
- return (0, devkit_1.readTargetOptions)(targetObj, context);
41
- }