@nx/vitest 23.3.0-beta.0 → 23.3.0-beta.2

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.
@@ -92,18 +92,6 @@ async function buildVitestTargets(configFilePath, projectRoot, options, context,
92
92
  catch {
93
93
  // do nothing
94
94
  }
95
- // Workaround for race condition with ESM-only Vite plugins (e.g. @vitejs/plugin-vue@6+)
96
- // If vite.config.ts is compiled as CJS, then when both require('@vitejs/plugin-vue') and import('@vitejs/plugin-vue')
97
- // are pending in the same process, Node will throw an error:
98
- // Error [ERR_INTERNAL_ASSERTION]: Cannot require() ES Module @vitejs/plugin-vue/dist/index.js because it is not yet fully loaded.
99
- // This may be caused by a race condition if the module is simultaneously dynamically import()-ed via Promise.all().
100
- try {
101
- const importVuePlugin = () => new Function('return import("@vitejs/plugin-vue")')();
102
- await importVuePlugin();
103
- }
104
- catch {
105
- // Plugin not installed or not needed, ignore
106
- }
107
95
  // Workaround for race condition with vitest/node on Node 24+
108
96
  // When multiple vitest.config files are processed in parallel, Node can throw:
109
97
  // Error [ERR_INTERNAL_ASSERTION]: Cannot require() ES Module vitest/dist/node.js
@@ -117,10 +105,10 @@ async function buildVitestTargets(configFilePath, projectRoot, options, context,
117
105
  // vitest/node not available or not needed, ignore
118
106
  }
119
107
  const { resolveConfig } = await (0, executor_utils_1.loadViteDynamicImport)();
120
- const viteBuildConfig = await resolveConfig({
108
+ const viteBuildConfig = await (0, internal_1.retryOnRequireEsmRace)(() => resolveConfig({
121
109
  configFile: absoluteConfigFilePath,
122
110
  mode: 'development',
123
- }, 'build');
111
+ }, 'build'));
124
112
  // A root config that aggregates project configs via `test.projects` is just an
125
113
  // orchestrator; the actual tests live in the individual project configs. Skip it
126
114
  // entirely so it does not register a project rooted at the workspace root (which
@@ -160,7 +148,7 @@ async function buildVitestTargets(configFilePath, projectRoot, options, context,
160
148
  // Capture the raw root after user hooks: graph construction and the
161
149
  // atom run resolve it against different cwds.
162
150
  let configuredViteRoot;
163
- const viteServeConfig = await resolveConfig({
151
+ const viteServeConfig = await (0, internal_1.retryOnRequireEsmRace)(() => resolveConfig({
164
152
  configFile: absoluteConfigFilePath,
165
153
  mode: 'test',
166
154
  plugins: [
@@ -186,7 +174,7 @@ async function buildVitestTargets(configFilePath, projectRoot, options, context,
186
174
  },
187
175
  },
188
176
  ],
189
- }, 'serve');
177
+ }, 'serve'));
190
178
  const projectRootRelativeTestPaths = await getTestPathsRelativeToProjectRoot(projectRoot, context.workspaceRoot,
191
179
  // Only the glob path reads this config; the opt-out path forces the
192
180
  // runtime by receiving no config, and takes `test.dir` separately.
@@ -448,16 +436,39 @@ function collectTsconfigInputsByProjectRoot(projectRoots, workspaceRoot) {
448
436
  const jsonCache = new Map();
449
437
  const result = new Map();
450
438
  const rootTsConfigName = (0, js_1.getRootTsConfigFileName)();
439
+ // A directory cache requires project-specific filtering on replay.
440
+ const dirChainCache = new Map();
441
+ const collectDirChain = (dir) => {
442
+ const cached = dirChainCache.get(dir);
443
+ if (cached !== undefined)
444
+ return cached;
445
+ const paths = [];
446
+ const localSeen = new Set();
447
+ const tsconfigPath = dir
448
+ ? (0, node_path_1.join)(workspaceRoot, dir, 'tsconfig.json')
449
+ : (0, node_path_1.join)(workspaceRoot, 'tsconfig.json');
450
+ if ((0, node_fs_1.existsSync)(tsconfigPath)) {
451
+ (0, internal_2.walkTsconfigExtendsChain)(tsconfigPath, (absPath) => {
452
+ const wsRelative = (0, node_path_1.relative)(workspaceRoot, absPath)
453
+ .split(node_path_1.sep)
454
+ .join('/');
455
+ if (!localSeen.has(wsRelative)) {
456
+ localSeen.add(wsRelative);
457
+ paths.push(wsRelative);
458
+ }
459
+ return 'continue';
460
+ }, { jsonCache });
461
+ }
462
+ dirChainCache.set(dir, paths);
463
+ return paths;
464
+ };
451
465
  for (const projectRoot of projectRoots) {
452
466
  if (projectRoot === '.')
453
467
  continue;
454
468
  const outside = [];
455
469
  const seen = new Set();
456
470
  const projectPrefix = `${projectRoot}/`;
457
- const collect = (absolutePath) => {
458
- const wsRelative = (0, node_path_1.relative)(workspaceRoot, absolutePath)
459
- .split(node_path_1.sep)
460
- .join('/');
471
+ const collectWsRelative = (wsRelative) => {
461
472
  if (seen.has(wsRelative))
462
473
  return;
463
474
  seen.add(wsRelative);
@@ -472,11 +483,13 @@ function collectTsconfigInputsByProjectRoot(projectRoots, workspaceRoot) {
472
483
  return;
473
484
  outside.push(wsRelative);
474
485
  };
475
- // 1. Walk the project tsconfig's extends chain
476
486
  const projectTsconfig = (0, node_path_1.join)(workspaceRoot, projectRoot, 'tsconfig.json');
477
487
  if ((0, node_fs_1.existsSync)(projectTsconfig)) {
478
488
  (0, internal_2.walkTsconfigExtendsChain)(projectTsconfig, (absPath) => {
479
- collect(absPath);
489
+ const wsRelative = (0, node_path_1.relative)(workspaceRoot, absPath)
490
+ .split(node_path_1.sep)
491
+ .join('/');
492
+ collectWsRelative(wsRelative);
480
493
  return 'continue';
481
494
  }, { jsonCache });
482
495
  }
@@ -484,12 +497,8 @@ function collectTsconfigInputsByProjectRoot(projectRoots, workspaceRoot) {
484
497
  // between the entry point and the filesystem root)
485
498
  let dir = (0, node_path_1.dirname)(projectRoot);
486
499
  while (dir && dir !== '.') {
487
- const ancestorTsconfig = (0, node_path_1.join)(workspaceRoot, dir, 'tsconfig.json');
488
- if ((0, node_fs_1.existsSync)(ancestorTsconfig)) {
489
- (0, internal_2.walkTsconfigExtendsChain)(ancestorTsconfig, (absPath) => {
490
- collect(absPath);
491
- return 'continue';
492
- }, { jsonCache });
500
+ for (const wsRelative of collectDirChain(dir)) {
501
+ collectWsRelative(wsRelative);
493
502
  }
494
503
  const parent = (0, node_path_1.dirname)(dir);
495
504
  if (parent === dir)
@@ -497,12 +506,8 @@ function collectTsconfigInputsByProjectRoot(projectRoots, workspaceRoot) {
497
506
  dir = parent;
498
507
  }
499
508
  // 3. Check the workspace root itself (dirname loop above stops at '.')
500
- const rootTsconfig = (0, node_path_1.join)(workspaceRoot, 'tsconfig.json');
501
- if ((0, node_fs_1.existsSync)(rootTsconfig)) {
502
- (0, internal_2.walkTsconfigExtendsChain)(rootTsconfig, (absPath) => {
503
- collect(absPath);
504
- return 'continue';
505
- }, { jsonCache });
509
+ for (const wsRelative of collectDirChain('')) {
510
+ collectWsRelative(wsRelative);
506
511
  }
507
512
  if (outside.length > 0) {
508
513
  result.set(projectRoot, outside);
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": "23.3.0-beta.0",
4
+ "version": "23.3.0-beta.2",
5
5
  "type": "commonjs",
6
6
  "files": [
7
7
  "dist",
@@ -81,13 +81,13 @@
81
81
  "tslib": "^2.3.0",
82
82
  "semver": "^7.6.3",
83
83
  "@phenomnomnominal/tsquery": "~6.2.0",
84
- "@nx/devkit": "23.3.0-beta.0",
85
- "@nx/js": "23.3.0-beta.0"
84
+ "@nx/devkit": "23.3.0-beta.2",
85
+ "@nx/js": "23.3.0-beta.2"
86
86
  },
87
87
  "peerDependencies": {
88
88
  "vitest": "^3.0.0 || ^4.0.0",
89
89
  "vite": "^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0",
90
- "@nx/eslint": "23.3.0-beta.0"
90
+ "@nx/eslint": "23.3.0-beta.2"
91
91
  },
92
92
  "peerDependenciesMeta": {
93
93
  "@nx/eslint": {
@@ -101,6 +101,6 @@
101
101
  }
102
102
  },
103
103
  "devDependencies": {
104
- "nx": "23.3.0-beta.0"
104
+ "nx": "23.3.0-beta.2"
105
105
  }
106
106
  }