@nx/nuxt 23.0.0-beta.2 → 23.0.0-beta.21

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.
package/migrations.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "update-22-2-0-create-ai-instructions-for-nuxt-4": {
4
4
  "version": "22.2.0-beta.0",
5
5
  "description": "Create AI Instructions to help migrate workspaces to Nuxt 4.",
6
- "implementation": "./src/migrations/update-22-2-0/create-ai-instructions-for-nuxt-4"
6
+ "prompt": "./src/migrations/update-22-2-0/ai-instructions-for-nuxt-4.md"
7
7
  }
8
8
  },
9
9
  "packageJsonUpdates": {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nx/nuxt",
3
- "version": "23.0.0-beta.2",
3
+ "version": "23.0.0-beta.21",
4
4
  "private": false,
5
5
  "description": "The Nuxt plugin for Nx contains executors and generators for managing Nuxt applications and libraries within an Nx workspace. It provides:\n\n\n- Integration with libraries such as Vitest, Playwright, Cypress, and Storybook.\n\n- Generators for applications, libraries, and more.\n\n- Library build support for publishing packages to npm or other registries.\n\n- Utilities for automatic workspace refactoring.",
6
6
  "repository": {
@@ -45,16 +45,16 @@
45
45
  "dependencies": {
46
46
  "tslib": "^2.3.0",
47
47
  "@nuxt/kit": "^3.10.0 || ^4.0.0",
48
- "@nx/devkit": "23.0.0-beta.2",
49
- "@nx/js": "23.0.0-beta.2",
50
- "@nx/eslint": "23.0.0-beta.2",
51
- "@nx/vue": "23.0.0-beta.2",
52
- "@nx/vite": "23.0.0-beta.2",
53
- "@nx/vitest": "23.0.0-beta.2",
54
- "semver": "^7.5.3"
48
+ "@nx/devkit": "23.0.0-beta.21",
49
+ "@nx/js": "23.0.0-beta.21",
50
+ "@nx/eslint": "23.0.0-beta.21",
51
+ "@nx/vue": "23.0.0-beta.21",
52
+ "@nx/vite": "23.0.0-beta.21",
53
+ "@nx/vitest": "23.0.0-beta.21",
54
+ "semver": "^7.6.3"
55
55
  },
56
56
  "devDependencies": {
57
- "nx": "23.0.0-beta.2"
57
+ "nx": "23.0.0-beta.21"
58
58
  },
59
59
  "peerDependencies": {
60
60
  "@nuxt/schema": "^3.10.0 || ^4.0.0"
@@ -1 +1 @@
1
- {"version":3,"file":"application.d.ts","sourceRoot":"","sources":["../../../../../../packages/nuxt/src/generators/application/application.ts"],"names":[],"mappings":"AAAA,OAAO,EAKL,iBAAiB,EAKjB,IAAI,EAEL,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AA6BlC,wBAAsB,oBAAoB,CAAC,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,8BAKpE;AAED,wBAAsB,4BAA4B,CAAC,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,8BAiN5E;AAED,eAAe,oBAAoB,CAAC"}
1
+ {"version":3,"file":"application.d.ts","sourceRoot":"","sources":["../../../../../../packages/nuxt/src/generators/application/application.ts"],"names":[],"mappings":"AACA,OAAO,EAKL,iBAAiB,EAKjB,IAAI,EAEL,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AA4BlC,wBAAsB,oBAAoB,CAAC,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,8BAKpE;AAED,wBAAsB,4BAA4B,CAAC,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,8BAiN5E;AAED,eAAe,oBAAoB,CAAC"}
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.applicationGenerator = applicationGenerator;
4
4
  exports.applicationGeneratorInternal = applicationGeneratorInternal;
5
5
  const tslib_1 = require("tslib");
6
+ const internal_1 = require("@nx/devkit/internal");
6
7
  const devkit_1 = require("@nx/devkit");
7
8
  const init_1 = tslib_1.__importDefault(require("../init/init"));
8
9
  const normalize_options_1 = require("./lib/normalize-options");
@@ -14,12 +15,10 @@ const add_linting_1 = require("../../utils/add-linting");
14
15
  const add_vitest_1 = require("./lib/add-vitest");
15
16
  const vue_1 = require("@nx/vue");
16
17
  const ensure_dependencies_1 = require("./lib/ensure-dependencies");
17
- const log_show_project_command_1 = require("@nx/devkit/src/utils/log-show-project-command");
18
18
  const node_child_process_1 = require("node:child_process");
19
19
  const node_path_1 = require("node:path");
20
20
  const onboarding_1 = require("nx/src/nx-cloud/utilities/onboarding");
21
- const ts_solution_setup_1 = require("@nx/js/src/utils/typescript/ts-solution-setup");
22
- const sort_fields_1 = require("@nx/js/src/utils/package-json/sort-fields");
21
+ const internal_2 = require("@nx/js/internal");
23
22
  async function applicationGenerator(tree, schema) {
24
23
  return await applicationGeneratorInternal(tree, {
25
24
  useProjectJson: true,
@@ -28,7 +27,7 @@ async function applicationGenerator(tree, schema) {
28
27
  }
29
28
  async function applicationGeneratorInternal(tree, schema) {
30
29
  const tasks = [];
31
- const addTsPlugin = (0, ts_solution_setup_1.shouldConfigureTsSolutionSetup)(tree, true, // nuxt always adds plugins
30
+ const addTsPlugin = (0, internal_2.shouldConfigureTsSolutionSetup)(tree, true, // nuxt always adds plugins
32
31
  schema.useTsSolution);
33
32
  const jsInitTask = await (0, js_1.initGenerator)(tree, {
34
33
  ...schema,
@@ -113,7 +112,7 @@ async function applicationGeneratorInternal(tree, schema) {
113
112
  // If we are using the new TS solution
114
113
  // We need to update the workspace file (package.json or pnpm-workspaces.yaml) to include the new project
115
114
  if (options.isUsingTsSolutionConfig) {
116
- await (0, ts_solution_setup_1.addProjectToTsSolutionWorkspace)(tree, options.appProjectRoot);
115
+ await (0, internal_2.addProjectToTsSolutionWorkspace)(tree, options.appProjectRoot);
117
116
  }
118
117
  tasks.push(await (0, add_linting_1.addLinting)(tree, {
119
118
  projectName: options.projectName,
@@ -138,7 +137,7 @@ async function applicationGeneratorInternal(tree, schema) {
138
137
  if (options.js)
139
138
  (0, devkit_1.toJS)(tree);
140
139
  if (options.isUsingTsSolutionConfig) {
141
- (0, ts_solution_setup_1.updateTsconfigFiles)(tree, options.appProjectRoot, 'tsconfig.app.json', {
140
+ (0, internal_2.updateTsconfigFiles)(tree, options.appProjectRoot, 'tsconfig.app.json', {
142
141
  jsx: 'preserve',
143
142
  jsxImportSource: 'vue',
144
143
  module: 'esnext',
@@ -148,7 +147,7 @@ async function applicationGeneratorInternal(tree, schema) {
148
147
  ? ['eslint.config.js', 'eslint.config.cjs', 'eslint.config.mjs']
149
148
  : undefined);
150
149
  }
151
- (0, sort_fields_1.sortPackageJsonFields)(tree, options.appProjectRoot);
150
+ (0, internal_2.sortPackageJsonFields)(tree, options.appProjectRoot);
152
151
  if (!options.skipFormat)
153
152
  await (0, devkit_1.formatFiles)(tree);
154
153
  tasks.push(() => {
@@ -163,7 +162,7 @@ async function applicationGeneratorInternal(tree, schema) {
163
162
  }
164
163
  });
165
164
  tasks.push(() => {
166
- (0, log_show_project_command_1.logShowProjectCommand)(options.projectName);
165
+ (0, internal_1.logShowProjectCommand)(options.projectName);
167
166
  });
168
167
  return (0, devkit_1.runTasksInSerial)(...tasks);
169
168
  }
@@ -1 +1 @@
1
- {"version":3,"file":"add-e2e.d.ts","sourceRoot":"","sources":["../../../../../../../packages/nuxt/src/generators/application/lib/add-e2e.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,iBAAiB,EAGjB,IAAI,EAEL,MAAM,YAAY,CAAC;AAGpB,OAAO,EAAE,gBAAgB,EAAE,MAAM,WAAW,CAAC;AAG7C,wBAAsB,MAAM,CAC1B,IAAI,EAAE,IAAI,EACV,OAAO,EAAE,gBAAgB,GACxB,OAAO,CAAC,iBAAiB,CAAC,CA8G5B"}
1
+ {"version":3,"file":"add-e2e.d.ts","sourceRoot":"","sources":["../../../../../../../packages/nuxt/src/generators/application/lib/add-e2e.ts"],"names":[],"mappings":"AAIA,OAAO,EAGL,iBAAiB,EAGjB,IAAI,EAEL,MAAM,YAAY,CAAC;AAEpB,OAAO,EAAE,gBAAgB,EAAE,MAAM,WAAW,CAAC;AAG7C,wBAAsB,MAAM,CAC1B,IAAI,EAAE,IAAI,EACV,OAAO,EAAE,gBAAgB,GACxB,OAAO,CAAC,iBAAiB,CAAC,CA8G5B"}
@@ -1,8 +1,8 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.addE2e = addE2e;
4
+ const internal_1 = require("@nx/devkit/internal");
4
5
  const devkit_1 = require("@nx/devkit");
5
- const e2e_web_server_info_utils_1 = require("@nx/devkit/src/generators/e2e-web-server-info-utils");
6
6
  const versions_1 = require("../../../utils/versions");
7
7
  async function addE2e(host, options) {
8
8
  const e2eWebServerInfo = await getNuxtE2EWebServerInfo(host, options.projectName, (0, devkit_1.joinPathFragments)(options.appProjectRoot, `nuxt.config.${options.js ? 'js' : 'ts'}`));
@@ -92,11 +92,11 @@ async function addE2e(host, options) {
92
92
  async function getNuxtE2EWebServerInfo(tree, projectName, configFilePath) {
93
93
  const nxJson = (0, devkit_1.readNxJson)(tree);
94
94
  let e2ePort = 4200;
95
- if (nxJson.targetDefaults?.['serve'] &&
96
- nxJson.targetDefaults?.['serve'].options?.port) {
97
- e2ePort = nxJson.targetDefaults?.['serve'].options?.port;
95
+ const serveTargetOptions = (0, internal_1.readTargetDefaultsForTarget)('serve', nxJson.targetDefaults)?.options;
96
+ if (serveTargetOptions?.port) {
97
+ e2ePort = serveTargetOptions.port;
98
98
  }
99
- return (0, e2e_web_server_info_utils_1.getE2EWebServerInfo)(tree, projectName, {
99
+ return (0, internal_1.getE2EWebServerInfo)(tree, projectName, {
100
100
  plugin: '@nx/nuxt/plugin',
101
101
  serveTargetName: 'serveTargetName',
102
102
  serveStaticTargetName: 'serveStaticTargetName',
@@ -1,19 +1,19 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.normalizeOptions = normalizeOptions;
4
- const project_name_and_root_utils_1 = require("@nx/devkit/src/generators/project-name-and-root-utils");
5
- const ts_solution_setup_1 = require("@nx/js/src/utils/typescript/ts-solution-setup");
4
+ const internal_1 = require("@nx/devkit/internal");
5
+ const internal_2 = require("@nx/js/internal");
6
6
  const version_utils_1 = require("../../../utils/version-utils");
7
7
  async function normalizeOptions(host, options) {
8
- await (0, project_name_and_root_utils_1.ensureRootProjectName)(options, 'application');
9
- const { projectName, names: projectNames, projectRoot: appProjectRoot, importPath, } = await (0, project_name_and_root_utils_1.determineProjectNameAndRootOptions)(host, {
8
+ await (0, internal_1.ensureRootProjectName)(options, 'application');
9
+ const { projectName, names: projectNames, projectRoot: appProjectRoot, importPath, } = await (0, internal_1.determineProjectNameAndRootOptions)(host, {
10
10
  name: options.name,
11
11
  projectType: 'application',
12
12
  directory: options.directory,
13
13
  rootProject: options.rootProject,
14
14
  });
15
15
  options.rootProject = appProjectRoot === '.';
16
- const isUsingTsSolutionConfig = (0, ts_solution_setup_1.isUsingTsSolutionSetup)(host);
16
+ const isUsingTsSolutionConfig = (0, internal_2.isUsingTsSolutionSetup)(host);
17
17
  const appProjectName = !isUsingTsSolutionConfig || options.name ? projectName : importPath;
18
18
  const e2eProjectName = options.rootProject ? 'e2e' : `${appProjectName}-e2e`;
19
19
  const e2eProjectRoot = options.rootProject ? 'e2e' : `${appProjectRoot}-e2e`;
@@ -2,11 +2,11 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.nuxtInitGenerator = nuxtInitGenerator;
4
4
  const devkit_1 = require("@nx/devkit");
5
- const add_plugin_1 = require("@nx/devkit/src/utils/add-plugin");
5
+ const internal_1 = require("@nx/devkit/internal");
6
6
  const plugin_1 = require("../../plugins/plugin");
7
7
  const utils_1 = require("./lib/utils");
8
8
  async function nuxtInitGenerator(host, schema) {
9
- await (0, add_plugin_1.addPlugin)(host, await (0, devkit_1.createProjectGraphAsync)(), '@nx/nuxt/plugin', plugin_1.createNodesV2, {
9
+ await (0, internal_1.addPlugin)(host, await (0, devkit_1.createProjectGraphAsync)(), '@nx/nuxt/plugin', plugin_1.createNodesV2, {
10
10
  buildTargetName: ['build', 'nuxt:build', 'nuxt-build'],
11
11
  serveTargetName: ['serve', 'nuxt:serve', 'nuxt-serve'],
12
12
  buildDepsTargetName: ['build-deps', 'nuxt:build-deps', 'nuxt-build-deps'],
@@ -1 +1 @@
1
- {"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../../../../../packages/nuxt/src/plugins/plugin.ts"],"names":[],"mappings":"AACA,OAAO,EAIL,aAAa,EAQd,MAAM,YAAY,CAAC;AA6BpB,MAAM,WAAW,iBAAiB;IAChC,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAC/B,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAC/B,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,mBAAmB,CAAC,EAAE,MAAM,CAAC;CAC9B;AAED,eAAO,MAAM,WAAW,EAAE,aAAa,CAAC,iBAAiB,CAaxD,CAAC;AAEF,eAAO,MAAM,aAAa,kCAAc,CAAC"}
1
+ {"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../../../../../packages/nuxt/src/plugins/plugin.ts"],"names":[],"mappings":"AAOA,OAAO,EAML,aAAa,EAMd,MAAM,YAAY,CAAC;AAapB,MAAM,WAAW,iBAAiB;IAChC,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAC/B,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAC/B,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,mBAAmB,CAAC,EAAE,MAAM,CAAC;CAC9B;AAED,eAAO,MAAM,WAAW,EAAE,aAAa,CAAC,iBAAiB,CAoDxD,CAAC;AAEF,eAAO,MAAM,aAAa,kCAAc,CAAC"}
@@ -1,55 +1,62 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.createNodesV2 = exports.createNodes = void 0;
4
+ const internal_1 = require("@nx/devkit/internal");
4
5
  const devkit_1 = require("@nx/devkit");
5
- const config_utils_1 = require("@nx/devkit/src/utils/config-utils");
6
- const get_named_inputs_1 = require("@nx/devkit/src/utils/get-named-inputs");
7
- const calculate_hash_for_create_nodes_1 = require("@nx/devkit/src/utils/calculate-hash-for-create-nodes");
8
6
  const cache_directory_1 = require("nx/src/utils/cache-directory");
9
7
  const js_1 = require("@nx/js");
10
8
  const path_1 = require("path");
11
9
  const fs_1 = require("fs");
12
10
  const executor_utils_1 = require("../utils/executor-utils");
13
- const util_1 = require("@nx/js/src/plugins/typescript/util");
11
+ const internal_2 = require("@nx/js/internal");
14
12
  const cachePath = (0, path_1.join)(cache_directory_1.workspaceDataDirectory, 'nuxt.hash');
15
- const targetsCache = readTargetsCache();
16
- function readTargetsCache() {
17
- return (0, fs_1.existsSync)(cachePath) ? (0, devkit_1.readJsonFile)(cachePath) : {};
18
- }
19
- function writeTargetsToCache() {
20
- const oldCache = readTargetsCache();
21
- (0, devkit_1.writeJsonFile)(cachePath, {
22
- ...oldCache,
23
- ...targetsCache,
24
- });
25
- }
13
+ const targetsCache = new internal_1.PluginCache(cachePath);
26
14
  exports.createNodes = [
27
15
  '**/nuxt.config.{js,ts,mjs,mts,cjs,cts}',
28
16
  async (files, options, context) => {
29
- //TODO(@nrwl/nx-vue-reviewers): This should batch hashing like our other plugins.
30
- const result = await (0, devkit_1.createNodesFromFiles)(createNodesInternal, files, options, context);
31
- writeTargetsToCache();
32
- return result;
17
+ const packageManager = (0, devkit_1.detectPackageManager)(context.workspaceRoot);
18
+ const pmc = (0, devkit_1.getPackageManagerCommand)(packageManager);
19
+ const lockFileName = (0, js_1.getLockFileName)(packageManager);
20
+ const normalizedOptions = normalizeOptions(options);
21
+ try {
22
+ const { entries, preErrors } = await filterNuxtConfigs(files, context);
23
+ const projectHashes = await (0, internal_1.calculateHashesForCreateNodes)(entries.map((e) => e.projectRoot), normalizedOptions, context, entries.map(() => [lockFileName]));
24
+ let results = [];
25
+ let nodeErrors = [];
26
+ try {
27
+ results = await (0, devkit_1.createNodesFromFiles)((configFile, _, ctx, idx) => createNodesInternal(configFile, normalizedOptions, ctx, pmc, projectHashes[idx]), entries.map((e) => e.configFile), options, context);
28
+ }
29
+ catch (e) {
30
+ if (e instanceof devkit_1.AggregateCreateNodesError) {
31
+ results = e.partialResults ?? [];
32
+ nodeErrors = e.errors;
33
+ }
34
+ else {
35
+ throw e;
36
+ }
37
+ }
38
+ const allErrors = [...preErrors, ...nodeErrors];
39
+ if (allErrors.length > 0) {
40
+ throw new devkit_1.AggregateCreateNodesError(allErrors, results);
41
+ }
42
+ return results;
43
+ }
44
+ finally {
45
+ targetsCache.writeToDisk();
46
+ }
33
47
  },
34
48
  ];
35
49
  exports.createNodesV2 = exports.createNodes;
36
- async function createNodesInternal(configFilePath, options, context) {
50
+ async function createNodesInternal(configFilePath, options, context, pmc, hash) {
37
51
  const projectRoot = (0, path_1.dirname)(configFilePath);
38
- // Do not create a project if package.json and project.json isn't there.
39
- const siblingFiles = (0, fs_1.readdirSync)((0, path_1.join)(context.workspaceRoot, projectRoot));
40
- if (!siblingFiles.includes('package.json') &&
41
- !siblingFiles.includes('project.json')) {
42
- return {};
52
+ if (!targetsCache.has(hash)) {
53
+ targetsCache.set(hash, await buildNuxtTargets(configFilePath, projectRoot, options, context, pmc));
43
54
  }
44
- options = normalizeOptions(options);
45
- const pmc = (0, devkit_1.getPackageManagerCommand)((0, devkit_1.detectPackageManager)(context.workspaceRoot));
46
- const hash = await (0, calculate_hash_for_create_nodes_1.calculateHashForCreateNodes)(projectRoot, options, context, [(0, js_1.getLockFileName)((0, devkit_1.detectPackageManager)(context.workspaceRoot))]);
47
- targetsCache[hash] ??= await buildNuxtTargets(configFilePath, projectRoot, options, context, pmc);
48
55
  return {
49
56
  projects: {
50
57
  [projectRoot]: {
51
58
  root: projectRoot,
52
- targets: targetsCache[hash],
59
+ targets: targetsCache.get(hash),
53
60
  },
54
61
  },
55
62
  };
@@ -57,13 +64,13 @@ async function createNodesInternal(configFilePath, options, context) {
57
64
  async function buildNuxtTargets(configFilePath, projectRoot, options, context, pmc) {
58
65
  const nuxtConfig = await getInfoFromNuxtConfig(configFilePath, context, projectRoot);
59
66
  const { buildOutputs } = getOutputs(nuxtConfig, projectRoot);
60
- const namedInputs = (0, get_named_inputs_1.getNamedInputs)(projectRoot, context);
67
+ const namedInputs = (0, internal_1.getNamedInputs)(projectRoot, context);
61
68
  const targets = {};
62
69
  targets[options.buildTargetName] = buildTarget(options.buildTargetName, namedInputs, buildOutputs, projectRoot);
63
70
  targets[options.serveTargetName] = serveTarget(projectRoot);
64
71
  targets[options.serveStaticTargetName] = serveStaticTarget(options);
65
72
  targets[options.buildStaticTargetName] = buildStaticTarget(options.buildStaticTargetName, namedInputs, buildOutputs, projectRoot);
66
- (0, util_1.addBuildAndWatchDepsTargets)(context.workspaceRoot, projectRoot, targets, options, pmc);
73
+ (0, internal_2.addBuildAndWatchDepsTargets)(context.workspaceRoot, projectRoot, targets, options, pmc);
67
74
  return targets;
68
75
  }
69
76
  function buildTarget(buildTargetName, namedInputs, buildOutputs, projectRoot) {
@@ -134,7 +141,7 @@ async function getInfoFromNuxtConfig(configFilePath, context, projectRoot) {
134
141
  });
135
142
  }
136
143
  else {
137
- config = await (0, config_utils_1.loadConfigFile)((0, path_1.join)(context.workspaceRoot, configFilePath));
144
+ config = await (0, internal_1.loadConfigFile)((0, path_1.join)(context.workspaceRoot, configFilePath));
138
145
  }
139
146
  return {
140
147
  buildDir: config?.buildDir ??
@@ -172,6 +179,28 @@ function normalizeOutputPath(outputPath, projectRoot) {
172
179
  }
173
180
  }
174
181
  }
182
+ async function filterNuxtConfigs(configFiles, context) {
183
+ const preErrors = [];
184
+ const candidates = await Promise.all(configFiles.map(async (configFile) => {
185
+ try {
186
+ const projectRoot = (0, path_1.dirname)(configFile);
187
+ const siblingFiles = (0, fs_1.readdirSync)((0, path_1.join)(context.workspaceRoot, projectRoot));
188
+ if (!siblingFiles.includes('package.json') &&
189
+ !siblingFiles.includes('project.json')) {
190
+ return null;
191
+ }
192
+ return { configFile, projectRoot };
193
+ }
194
+ catch (e) {
195
+ preErrors.push([configFile, e]);
196
+ return null;
197
+ }
198
+ }));
199
+ return {
200
+ entries: candidates.filter((c) => c !== null),
201
+ preErrors,
202
+ };
203
+ }
175
204
  function normalizeOptions(options) {
176
205
  options ??= {};
177
206
  options.buildTargetName ??= 'build';
@@ -4,9 +4,8 @@ exports.addLinting = addLinting;
4
4
  const eslint_1 = require("@nx/eslint");
5
5
  const path_1 = require("nx/src/utils/path");
6
6
  const devkit_1 = require("@nx/devkit");
7
- const eslint_file_1 = require("@nx/eslint/src/generators/utils/eslint-file");
7
+ const internal_1 = require("@nx/eslint/internal");
8
8
  const versions_1 = require("./versions");
9
- const flat_config_1 = require("@nx/eslint/src/utils/flat-config");
10
9
  async function addLinting(host, options) {
11
10
  const tasks = [];
12
11
  if (options.linter === 'eslint') {
@@ -20,7 +19,7 @@ async function addLinting(host, options) {
20
19
  addPlugin: true,
21
20
  });
22
21
  tasks.push(lintTask);
23
- const isFlatConfig = (0, flat_config_1.useFlatConfig)(host);
22
+ const isFlatConfig = (0, internal_1.useFlatConfig)(host);
24
23
  // Version-aware dependencies:
25
24
  // - Flat config (v4+): use @nuxt/eslint-config ^1.10.0 with createConfigForNuxt
26
25
  // - Legacy (.eslintrc.json): use @nuxt/eslint-config ~0.5.6 with extends
@@ -29,7 +28,7 @@ async function addLinting(host, options) {
29
28
  ? versions_1.nuxtEslintConfigVersion
30
29
  : versions_1.nuxtEslintConfigLegacyVersion,
31
30
  };
32
- if ((0, eslint_file_1.isEslintConfigSupported)(host, options.projectRoot)) {
31
+ if ((0, internal_1.isEslintConfigSupported)(host, options.projectRoot)) {
33
32
  if (isFlatConfig) {
34
33
  // For flat config: Generate eslint.config.mjs using createConfigForNuxt
35
34
  generateNuxtFlatEslintConfig(host, options.projectRoot);
@@ -37,9 +36,9 @@ async function addLinting(host, options) {
37
36
  else {
38
37
  // For legacy: Use extends with the old @nuxt/eslint-config
39
38
  editEslintConfigFiles(host, options.projectRoot);
40
- const addExtendsTask = (0, eslint_file_1.addExtendsToLintConfig)(host, options.projectRoot, ['@nuxt/eslint-config'], true);
39
+ const addExtendsTask = (0, internal_1.addExtendsToLintConfig)(host, options.projectRoot, ['@nuxt/eslint-config'], true);
41
40
  tasks.push(addExtendsTask);
42
- (0, eslint_file_1.addIgnoresToLintConfig)(host, options.projectRoot, [
41
+ (0, internal_1.addIgnoresToLintConfig)(host, options.projectRoot, [
43
42
  '.nuxt/**',
44
43
  '.output/**',
45
44
  'node_modules',
@@ -56,7 +55,7 @@ async function addLinting(host, options) {
56
55
  * This is the recommended approach for Nuxt v4+ and ESLint flat config.
57
56
  */
58
57
  function generateNuxtFlatEslintConfig(tree, projectRoot) {
59
- const eslintFile = (0, eslint_file_1.findEslintFile)(tree, projectRoot);
58
+ const eslintFile = (0, internal_1.findEslintFile)(tree, projectRoot);
60
59
  if (!eslintFile)
61
60
  return;
62
61
  const configPath = (0, path_1.joinPathFragments)(projectRoot, eslintFile);
@@ -132,22 +131,22 @@ function editEslintConfigFiles(tree, projectRoot) {
132
131
  o.files = [o.files, '*.vue'];
133
132
  }
134
133
  };
135
- if ((0, eslint_file_1.lintConfigHasOverride)(tree, projectRoot, (o) => o.parserOptions && !hasVueFiles(o), true)) {
136
- (0, eslint_file_1.updateOverrideInLintConfig)(tree, projectRoot, (o) => !!o.parserOptions, (o) => {
134
+ if ((0, internal_1.lintConfigHasOverride)(tree, projectRoot, (o) => o.parserOptions && !hasVueFiles(o), true)) {
135
+ (0, internal_1.updateOverrideInLintConfig)(tree, projectRoot, (o) => !!o.parserOptions, (o) => {
137
136
  addVueFiles(o);
138
137
  return o;
139
138
  });
140
139
  }
141
140
  else {
142
- (0, eslint_file_1.replaceOverridesInLintConfig)(tree, projectRoot, [
141
+ (0, internal_1.replaceOverridesInLintConfig)(tree, projectRoot, [
143
142
  {
144
143
  files: ['*.ts', '*.tsx', '*.js', '*.jsx', '*.vue'],
145
144
  rules: {},
146
145
  },
147
146
  ]);
148
147
  }
149
- if ((0, eslint_file_1.lintConfigHasOverride)(tree, '', (o) => o.rules?.['@nx/enforce-module-boundaries'] && !hasVueFiles(o), true)) {
150
- (0, eslint_file_1.updateOverrideInLintConfig)(tree, '', (o) => !!o.rules?.['@nx/enforce-module-boundaries'], (o) => {
148
+ if ((0, internal_1.lintConfigHasOverride)(tree, '', (o) => o.rules?.['@nx/enforce-module-boundaries'] && !hasVueFiles(o), true)) {
149
+ (0, internal_1.updateOverrideInLintConfig)(tree, '', (o) => !!o.rules?.['@nx/enforce-module-boundaries'], (o) => {
151
150
  addVueFiles(o);
152
151
  return o;
153
152
  });
@@ -3,7 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.createTsConfig = createTsConfig;
4
4
  const tslib_1 = require("tslib");
5
5
  const devkit_1 = require("@nx/devkit");
6
- const shared = tslib_1.__importStar(require("@nx/js/src/utils/typescript/create-ts-config"));
6
+ const shared = tslib_1.__importStar(require("@nx/js"));
7
7
  function createTsConfig(host, options, relativePathToRootTsConfig) {
8
8
  createAppTsConfig(host, options);
9
9
  const json = {
@@ -1,3 +0,0 @@
1
- import { Tree } from '@nx/devkit';
2
- export default function (tree: Tree): Promise<void>;
3
- //# sourceMappingURL=add-include-tsconfig.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"add-include-tsconfig.d.ts","sourceRoot":"","sources":["../../../../../../packages/nuxt/src/migrations/update-18-1-0/add-include-tsconfig.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,IAAI,EAML,MAAM,YAAY,CAAC;AAIpB,yBAA+B,IAAI,EAAE,IAAI,iBAmCxC"}
@@ -1,48 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.default = default_1;
4
- const devkit_1 = require("@nx/devkit");
5
- const executor_utils_1 = require("../../utils/executor-utils");
6
- const path_1 = require("path");
7
- async function default_1(tree) {
8
- const projects = (0, devkit_1.getProjects)(tree);
9
- for (const project of projects.values()) {
10
- const nuxtConfigPath = findNuxtConfig(tree, project.root);
11
- if (!nuxtConfigPath) {
12
- continue;
13
- }
14
- const nuxtConfig = await getInfoFromNuxtConfig(nuxtConfigPath, project.root);
15
- const buildDir = nuxtConfig.buildDir ?? '.nuxt';
16
- const tsConfigPath = (0, devkit_1.joinPathFragments)(project.root, 'tsconfig.json');
17
- if (tree.exists(tsConfigPath)) {
18
- (0, devkit_1.updateJson)(tree, tsConfigPath, (json) => {
19
- if (!json.include) {
20
- json.include = [];
21
- }
22
- if (!json.include.includes(buildDir + '/nuxt.d.ts')) {
23
- json.include.push(buildDir + '/nuxt.d.ts');
24
- }
25
- return json;
26
- });
27
- }
28
- }
29
- await (0, devkit_1.formatFiles)(tree);
30
- }
31
- function findNuxtConfig(tree, projectRoot) {
32
- const allowsExt = ['js', 'mjs', 'ts', 'cjs', 'mts', 'cts'];
33
- for (const ext of allowsExt) {
34
- if (tree.exists((0, devkit_1.joinPathFragments)(projectRoot, `nuxt.config.${ext}`))) {
35
- return (0, devkit_1.joinPathFragments)(projectRoot, `nuxt.config.${ext}`);
36
- }
37
- }
38
- }
39
- async function getInfoFromNuxtConfig(configFilePath, projectRoot) {
40
- const { loadNuxtConfig } = await (0, executor_utils_1.loadNuxtKitDynamicImport)();
41
- const config = await loadNuxtConfig({
42
- cwd: (0, devkit_1.joinPathFragments)(devkit_1.workspaceRoot, projectRoot),
43
- configFile: (0, path_1.basename)(configFilePath),
44
- });
45
- return {
46
- buildDir: config?.buildDir,
47
- };
48
- }
@@ -1,3 +0,0 @@
1
- import { Tree } from '@nx/devkit';
2
- export default function createAiInstructionsForNuxt(tree: Tree): Promise<string[]>;
3
- //# sourceMappingURL=create-ai-instructions-for-nuxt-4.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"create-ai-instructions-for-nuxt-4.d.ts","sourceRoot":"","sources":["../../../../../../packages/nuxt/src/migrations/update-22-2-0/create-ai-instructions-for-nuxt-4.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;AAElC,wBAA8B,2BAA2B,CAAC,IAAI,EAAE,IAAI,qBAenE"}
@@ -1,16 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.default = createAiInstructionsForNuxt;
4
- const path_1 = require("path");
5
- const fs_1 = require("fs");
6
- async function createAiInstructionsForNuxt(tree) {
7
- const pathToAiInstructions = (0, path_1.join)(__dirname, 'files', 'ai-instructions-for-nuxt-4.md');
8
- if (!(0, fs_1.existsSync)(pathToAiInstructions)) {
9
- return;
10
- }
11
- const contents = (0, fs_1.readFileSync)(pathToAiInstructions);
12
- tree.write('tools/ai-migrations/MIGRATE_NUXT_4.md', contents);
13
- return [
14
- `We created 'tools/ai-migrations/MIGRATE_NUXT_4.md' with instructions for an AI Agent to help migrate your Nuxt projects to Nuxt 4.`,
15
- ];
16
- }
@@ -1,531 +0,0 @@
1
- # Nuxt 3 to Nuxt 4 Migration Instructions
2
-
3
- This document provides instructions for an AI Agent to assist with migrating Nuxt 3 projects to Nuxt 4.
4
-
5
- ## Pre-Migration Checklist
6
-
7
- Before starting the migration, run these commands to understand the scope:
8
-
9
- ```bash
10
- # List all Nuxt projects in the workspace
11
- nx show projects --with-target build | xargs -I {} sh -c 'cat {}/nuxt.config.ts 2>/dev/null && echo "Project: {}"' | grep -B1 "Project:"
12
-
13
- # Find all files that may need updates
14
- find . -name "*.vue" -o -name "*.ts" | head -50
15
- ```
16
-
17
- ---
18
-
19
- ## Section 1: Configuration Updates
20
-
21
- ### 1.1 Directory Structure (Optional but Recommended)
22
-
23
- **Search Pattern**: Check `nuxt.config.ts` for `srcDir` configuration
24
-
25
- Nuxt 4 introduces a new default directory structure using `app/` instead of `src/`.
26
-
27
- **If adopting new structure:**
28
-
29
- ```typescript
30
- // Before (Nuxt 3 with srcDir)
31
- export default defineNuxtConfig({
32
- srcDir: 'src',
33
- });
34
-
35
- // After (Nuxt 4 - remove srcDir, move files to app/)
36
- export default defineNuxtConfig({
37
- // srcDir removed - app/ is now the default
38
- });
39
- ```
40
-
41
- **Action Items:**
42
-
43
- - [ ] Move `src/` contents to `app/` directory
44
- - [ ] Keep `server/`, `public/`, `layers/`, `modules/` at project root
45
- - [ ] Remove `srcDir` from `nuxt.config.ts`
46
-
47
- **OR to keep existing structure:**
48
-
49
- ```typescript
50
- export default defineNuxtConfig({
51
- srcDir: '.',
52
- dir: { app: 'app' },
53
- });
54
- ```
55
-
56
- ### 1.2 Remove Deprecated `generate` Configuration
57
-
58
- **Search Pattern**: `grep -r "generate:" --include="nuxt.config.ts"`
59
-
60
- ```typescript
61
- // Before
62
- export default defineNuxtConfig({
63
- generate: {
64
- exclude: ['/admin'],
65
- routes: ['/sitemap.xml'],
66
- },
67
- });
68
-
69
- // After
70
- export default defineNuxtConfig({
71
- nitro: {
72
- prerender: {
73
- ignore: ['/admin'],
74
- routes: ['/sitemap.xml'],
75
- },
76
- },
77
- });
78
- ```
79
-
80
- ### 1.3 TypeScript Configuration
81
-
82
- **Search Pattern**: Check `tsconfig.json` files
83
-
84
- Nuxt 4 sets `noUncheckedIndexedAccess: true` by default.
85
-
86
- **To override if needed:**
87
-
88
- ```typescript
89
- export default defineNuxtConfig({
90
- typescript: {
91
- tsConfig: {
92
- compilerOptions: {
93
- noUncheckedIndexedAccess: false,
94
- },
95
- },
96
- },
97
- });
98
- ```
99
-
100
- ---
101
-
102
- ## Section 2: Data Fetching Updates
103
-
104
- ### 2.1 Default Values Changed from `null` to `undefined`
105
-
106
- **Search Pattern**: `grep -rn "!== null\|=== null" --include="*.vue" --include="*.ts"`
107
-
108
- ```typescript
109
- // Before (Nuxt 3)
110
- const { data } = await useAsyncData('key', () => fetch('/api/data'));
111
- if (data.value !== null) {
112
- /* ... */
113
- }
114
-
115
- // After (Nuxt 4)
116
- const { data } = await useAsyncData('key', () => fetch('/api/data'));
117
- if (data.value !== undefined) {
118
- /* ... */
119
- }
120
- ```
121
-
122
- **Automation available:**
123
-
124
- ```bash
125
- npx codemod@latest nuxt/4/default-data-error-value
126
- ```
127
-
128
- ### 2.2 `getCachedData` Context Parameter
129
-
130
- **Search Pattern**: `grep -rn "getCachedData" --include="*.vue" --include="*.ts"`
131
-
132
- ```typescript
133
- // Before
134
- getCachedData: (key, nuxtApp) => cachedData[key];
135
-
136
- // After
137
- getCachedData: (key, nuxtApp, ctx) => {
138
- // ctx.cause: 'initial' | 'refresh:hook' | 'refresh:manual' | 'watch'
139
- if (ctx.cause === 'refresh:manual') return undefined;
140
- return cachedData[key];
141
- };
142
- ```
143
-
144
- ### 2.3 Shallow Data Reactivity
145
-
146
- **Search Pattern**: `grep -rn "useAsyncData\|useFetch" --include="*.vue" --include="*.ts"`
147
-
148
- Data from `useAsyncData`/`useFetch` is now `shallowRef` (not deep reactive).
149
-
150
- ```typescript
151
- // If deep reactivity is needed:
152
- const { data } = useFetch('/api/test', { deep: true });
153
- ```
154
-
155
- **Automation available:**
156
-
157
- ```bash
158
- npx codemod@latest nuxt/4/shallow-function-reactivity
159
- ```
160
-
161
- ### 2.4 Removed `dedupe` Boolean Values
162
-
163
- **Search Pattern**: `grep -rn "dedupe: true\|dedupe: false" --include="*.vue" --include="*.ts"`
164
-
165
- ```typescript
166
- // Before
167
- refresh({ dedupe: true });
168
- refresh({ dedupe: false });
169
-
170
- // After
171
- refresh({ dedupe: 'cancel' });
172
- refresh({ dedupe: 'defer' });
173
- ```
174
-
175
- **Automation available:**
176
-
177
- ```bash
178
- npx codemod@latest nuxt/4/deprecated-dedupe-value
179
- ```
180
-
181
- ### 2.5 Unique Keys for Shared Prerender Data
182
-
183
- **Search Pattern**: Check dynamic route files `[*.vue` in `pages/`
184
-
185
- ```typescript
186
- // Before (unsafe for dynamic routes)
187
- const { data } = await useAsyncData(async () =>
188
- $fetch(`/api/page/${route.params.slug}`)
189
- );
190
-
191
- // After (safe - key includes slug)
192
- const { data } = await useAsyncData(route.params.slug, async () =>
193
- $fetch(`/api/page/${route.params.slug}`)
194
- );
195
- ```
196
-
197
- ---
198
-
199
- ## Section 3: Unhead v2 Migration
200
-
201
- ### 3.1 Remove Deprecated Props
202
-
203
- **Search Pattern**: `grep -rn "hid:\|vmid:\|children:\|body:" --include="*.vue" --include="*.ts"`
204
-
205
- ```typescript
206
- // Before
207
- useHead({
208
- meta: [{ name: 'description', hid: 'description', content: 'My page' }],
209
- script: [{ children: 'console.log("hello")' }],
210
- });
211
-
212
- // After
213
- useHead({
214
- meta: [{ name: 'description', content: 'My page' }],
215
- script: [{ innerHTML: 'console.log("hello")' }],
216
- });
217
- ```
218
-
219
- ---
220
-
221
- ## Section 4: Component and Routing Changes
222
-
223
- ### 4.1 Normalized Component Names
224
-
225
- **Search Pattern**: Check test files using `findComponent` and templates with `<KeepAlive>`
226
-
227
- ```typescript
228
- // Component in SomeFolder/MyComponent.vue
229
- // Before: findComponent({ name: 'MyComponent' })
230
- // After: findComponent({ name: 'SomeFolderMyComponent' })
231
- ```
232
-
233
- **To disable if needed:**
234
-
235
- ```typescript
236
- export default defineNuxtConfig({
237
- experimental: {
238
- normalizeComponentNames: false,
239
- },
240
- });
241
- ```
242
-
243
- ### 4.2 Route Metadata Deduplication
244
-
245
- **Search Pattern**: `grep -rn "route.meta.name\|route.meta.path" --include="*.vue" --include="*.ts"`
246
-
247
- ```typescript
248
- // Before
249
- const name = route.meta.name;
250
-
251
- // After
252
- const name = route.name;
253
- ```
254
-
255
- ---
256
-
257
- ## Section 5: Removed Experimental Flags
258
-
259
- These flags are now hardcoded and cannot be configured:
260
-
261
- - `experimental.treeshakeClientOnly` → always `true`
262
- - `experimental.configSchema` → always `true`
263
- - `experimental.polyfillVueUseHead` → always `false`
264
- - `experimental.respectNoSSRHeader` → always `false`
265
-
266
- **Action Items:**
267
-
268
- - [ ] Remove these from `nuxt.config.ts` if present
269
-
270
- ---
271
-
272
- ## Section 6: Error Handling
273
-
274
- ### 6.1 Parsed `error.data`
275
-
276
- **Search Pattern**: `grep -rn "JSON.parse.*error.data\|error.data.*JSON.parse" --include="*.vue" --include="*.ts"`
277
-
278
- ```typescript
279
- // Before
280
- const data = JSON.parse(error.data);
281
-
282
- // After (data is already parsed)
283
- const data = error.data;
284
- ```
285
-
286
- ---
287
-
288
- ## Section 7: Module and Build Changes
289
-
290
- ### 7.1 Absolute Watch Paths in `builder:watch`
291
-
292
- **Search Pattern**: Check custom modules using `builder:watch` hook
293
-
294
- ```typescript
295
- import { relative, resolve } from 'node:fs';
296
-
297
- nuxt.hook('builder:watch', async (event, path) => {
298
- // Convert to relative path for backward/forward compatibility
299
- path = relative(nuxt.options.srcDir, resolve(nuxt.options.srcDir, path));
300
- });
301
- ```
302
-
303
- ### 7.2 Template Compilation Changes
304
-
305
- **Search Pattern**: Check modules using `addTemplate` with EJS syntax
306
-
307
- ```typescript
308
- // Before (using lodash template)
309
- addTemplate({
310
- fileName: 'plugin.js',
311
- src: './runtime/plugin.ejs',
312
- });
313
-
314
- // After (using getContents)
315
- import { template } from 'es-toolkit/compat';
316
-
317
- addTemplate({
318
- fileName: 'plugin.js',
319
- getContents({ options }) {
320
- const contents = readFileSync('./runtime/plugin.ejs', 'utf-8');
321
- return template(contents)({ options });
322
- },
323
- });
324
- ```
325
-
326
- ---
327
-
328
- ## Section 8: ESLint Configuration (Flat Config Only)
329
-
330
- > **Note:** This section only applies if your workspace uses ESLint flat config (`eslint.config.js`, `eslint.config.mjs`, or `eslint.config.cjs`). If you're using legacy `.eslintrc.json`, no changes are required.
331
-
332
- ### 8.1 Migrate to `createConfigForNuxt`
333
-
334
- **Search Pattern**: Check for `eslint.config.js`, `eslint.config.mjs`, or `eslint.config.cjs` in Nuxt project directories
335
-
336
- For workspaces using ESLint flat config, Nuxt 4 requires updating to `@nuxt/eslint-config` version `^1.10.0` and using `createConfigForNuxt` from `@nuxt/eslint-config/flat`.
337
-
338
- **Before (Nuxt 3 flat config):**
339
-
340
- ```javascript
341
- import baseConfig from '../../eslint.config.mjs';
342
-
343
- export default [
344
- ...baseConfig,
345
- {
346
- files: ['**/*.vue'],
347
- languageOptions: {
348
- parserOptions: { parser: '@typescript-eslint/parser' },
349
- },
350
- },
351
- {
352
- ignores: ['.nuxt/**', '.output/**', 'node_modules'],
353
- },
354
- ];
355
- ```
356
-
357
- **After (Nuxt 4 flat config - eslint.config.mjs):**
358
-
359
- ```javascript
360
- import { createConfigForNuxt } from '@nuxt/eslint-config/flat';
361
- import baseConfig from '../../eslint.config.mjs';
362
-
363
- export default createConfigForNuxt({
364
- features: {
365
- typescript: true,
366
- },
367
- })
368
- .prepend(...baseConfig)
369
- .append(
370
- {
371
- files: ['**/*.ts', '**/*.tsx', '**/*.js', '**/*.jsx', '**/*.vue'],
372
- rules: {},
373
- },
374
- {
375
- ignores: ['.nuxt/**', '.output/**', 'node_modules'],
376
- }
377
- );
378
- ```
379
-
380
- **For CJS (eslint.config.cjs):**
381
-
382
- ```javascript
383
- const { createConfigForNuxt } = require('@nuxt/eslint-config/flat');
384
- const baseConfig = require('../../eslint.config.cjs');
385
-
386
- module.exports = createConfigForNuxt({
387
- features: {
388
- typescript: true,
389
- },
390
- })
391
- .prepend(...baseConfig)
392
- .append(
393
- {
394
- files: ['**/*.ts', '**/*.tsx', '**/*.js', '**/*.jsx', '**/*.vue'],
395
- rules: {},
396
- },
397
- {
398
- ignores: ['.nuxt/**', '.output/**', 'node_modules'],
399
- }
400
- );
401
- ```
402
-
403
- **Action Items (Flat Config Only):**
404
-
405
- - [ ] Update `@nuxt/eslint-config` to `^1.10.0` in `package.json`
406
- - [ ] Replace manual Vue/TypeScript parser config with `createConfigForNuxt`
407
- - [ ] Use `features.typescript: true` option for TypeScript support
408
- - [ ] Remove `@typescript-eslint/parser` from devDependencies (handled automatically)
409
- - [ ] Use `.prepend()` for base configs and `.append()` for project-specific rules/ignores
410
-
411
- ### 8.2 Understanding the New Config Structure
412
-
413
- The `createConfigForNuxt` function returns a chainable config builder:
414
-
415
- - **`features.typescript: true`** - Enables TypeScript support with proper Vue file parsing
416
- - **`.prepend(...configs)`** - Adds configs at the beginning (useful for workspace base configs)
417
- - **`.append(...configs)`** - Adds configs at the end (for project-specific rules and ignores)
418
-
419
- ---
420
-
421
- ## Post-Migration Validation
422
-
423
- After completing the migration, run these commands:
424
-
425
- ```bash
426
- # 1. Install updated dependencies
427
- npm install
428
-
429
- # 2. Run Nuxt prepare
430
- npx nuxi prepare
431
-
432
- # 3. Type check
433
- npx nuxi typecheck
434
-
435
- # 4. Build the application
436
- nx build <project-name>
437
-
438
- # 5. Run tests
439
- nx test <project-name>
440
-
441
- # 6. Start dev server to verify
442
- nx serve <project-name>
443
- ```
444
-
445
- ---
446
-
447
- ## Quick Migration Commands
448
-
449
- Nuxt provides codemods to automate many changes:
450
-
451
- ```bash
452
- # Run the full migration recipe
453
- npx codemod@0.18.7 nuxt/4/migration-recipe
454
-
455
- # Or run individual codemods:
456
- npx codemod@latest nuxt/4/file-structure
457
- npx codemod@latest nuxt/4/default-data-error-value
458
- npx codemod@latest nuxt/4/shallow-function-reactivity
459
- npx codemod@latest nuxt/4/deprecated-dedupe-value
460
- npx codemod@latest nuxt/4/template-compilation-changes
461
- npx codemod@latest nuxt/4/absolute-watch-path
462
- ```
463
-
464
- ---
465
-
466
- ## Common Issues and Solutions
467
-
468
- ### Issue: White flash on initial load
469
-
470
- **Solution:** This is expected behavior - SPA loading template now renders outside `#__nuxt`. To revert:
471
-
472
- ```typescript
473
- experimental: {
474
- spaLoadingTemplateLocation: 'within';
475
- }
476
- ```
477
-
478
- ### Issue: Global CSS not inlined
479
-
480
- **Solution:** Only component CSS is inlined by default. To inline all CSS:
481
-
482
- ```typescript
483
- features: {
484
- inlineStyles: true;
485
- }
486
- ```
487
-
488
- ### Issue: Middleware index files being registered
489
-
490
- **Solution:** Filter unwanted middleware:
491
-
492
- ```typescript
493
- hooks: {
494
- 'app:resolve'(app) {
495
- app.middleware = app.middleware.filter(mw => !/\/index\.[^/]+$/.test(mw.path))
496
- }
497
- }
498
- ```
499
-
500
- ---
501
-
502
- ## Files to Review
503
-
504
- ```bash
505
- # Find all Vue files
506
- find . -name "*.vue" -not -path "./node_modules/*"
507
-
508
- # Find all nuxt config files
509
- find . -name "nuxt.config.*" -not -path "./node_modules/*"
510
-
511
- # Find composables using data fetching
512
- grep -rn "useAsyncData\|useFetch\|getCachedData" --include="*.vue" --include="*.ts" | grep -v node_modules
513
- ```
514
-
515
- ---
516
-
517
- ## Notes for AI Agent
518
-
519
- 1. **Work systematically** through each section
520
- 2. **Run codemods first** where available, then manually fix remaining issues
521
- 3. **Test incrementally** - run `nx build` and `nx test` after each major change
522
- 4. **Document changes** as you make them for user review
523
- 5. **Handle errors gracefully** - if a file doesn't exist or a pattern isn't found, continue to the next item
524
-
525
- ---
526
-
527
- ## References
528
-
529
- - [Official Nuxt 4 Upgrade Guide](https://nuxt.com/docs/4.x/getting-started/upgrade)
530
- - [Nuxt 4 Announcement Blog](https://nuxt.com/blog/v4)
531
- - [Nuxt GitHub Repository](https://github.com/nuxt/nuxt)