@nx/nuxt 23.0.0-beta.22 → 23.0.0-beta.24
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 +9 -0
- package/package.json +22 -10
- package/src/generators/application/application.d.ts.map +1 -1
- package/src/generators/application/application.js +3 -1
- package/src/generators/application/lib/ensure-dependencies.d.ts.map +1 -1
- package/src/generators/application/lib/ensure-dependencies.js +2 -1
- package/src/generators/init/init.d.ts.map +1 -1
- package/src/generators/init/init.js +2 -0
- package/src/generators/init/lib/utils.js +1 -1
- package/src/generators/init/schema.json +1 -1
- package/src/generators/storybook-configuration/configuration.d.ts.map +1 -1
- package/src/generators/storybook-configuration/configuration.js +2 -0
- package/src/migrations/update-22-2-0/ai-instructions-for-nuxt-4.md +531 -0
- package/src/migrations/update-23-0-0/migrate-create-nodes-v2-to-create-nodes.d.ts +10 -0
- package/src/migrations/update-23-0-0/migrate-create-nodes-v2-to-create-nodes.d.ts.map +1 -0
- package/src/migrations/update-23-0-0/migrate-create-nodes-v2-to-create-nodes.js +134 -0
- package/src/migrations/update-23-0-0/migrate-create-nodes-v2-to-create-nodes.md +25 -0
- package/src/plugins/plugin.d.ts +3 -3
- package/src/plugins/plugin.d.ts.map +1 -1
- package/src/plugins/plugin.js +5 -0
- package/src/utils/add-linting.d.ts.map +1 -1
- package/src/utils/add-linting.js +1 -1
- package/src/utils/assert-supported-nuxt-version.d.ts +3 -0
- package/src/utils/assert-supported-nuxt-version.d.ts.map +1 -0
- package/src/utils/assert-supported-nuxt-version.js +8 -0
- package/src/utils/version-utils.d.ts +1 -0
- package/src/utils/version-utils.d.ts.map +1 -1
- package/src/utils/version-utils.js +2 -0
- package/src/utils/versions.d.ts +4 -0
- package/src/utils/versions.d.ts.map +1 -1
- package/src/utils/versions.js +11 -1
package/migrations.json
CHANGED
|
@@ -4,11 +4,20 @@
|
|
|
4
4
|
"version": "22.2.0-beta.0",
|
|
5
5
|
"description": "Create AI Instructions to help migrate workspaces to Nuxt 4.",
|
|
6
6
|
"prompt": "./src/migrations/update-22-2-0/ai-instructions-for-nuxt-4.md"
|
|
7
|
+
},
|
|
8
|
+
"update-23-0-0-migrate-create-nodes-v2-import": {
|
|
9
|
+
"version": "23.0.0-beta.24",
|
|
10
|
+
"description": "Rename imports of `createNodesV2` from `@nx/nuxt/plugin` to the canonical `createNodes` export.",
|
|
11
|
+
"implementation": "./dist/src/migrations/update-23-0-0/migrate-create-nodes-v2-to-create-nodes",
|
|
12
|
+
"documentation": "./dist/src/migrations/update-23-0-0/migrate-create-nodes-v2-to-create-nodes.md"
|
|
7
13
|
}
|
|
8
14
|
},
|
|
9
15
|
"packageJsonUpdates": {
|
|
10
16
|
"22.2.0": {
|
|
11
17
|
"version": "22.2.0-beta.0",
|
|
18
|
+
"requires": {
|
|
19
|
+
"nuxt": ">=3.0.0 <4.0.0"
|
|
20
|
+
},
|
|
12
21
|
"packages": {
|
|
13
22
|
"nuxt": {
|
|
14
23
|
"version": "^4.0.0",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nx/nuxt",
|
|
3
|
-
"version": "23.0.0-beta.
|
|
3
|
+
"version": "23.0.0-beta.24",
|
|
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": {
|
|
@@ -44,20 +44,32 @@
|
|
|
44
44
|
},
|
|
45
45
|
"dependencies": {
|
|
46
46
|
"tslib": "^2.3.0",
|
|
47
|
-
"@
|
|
48
|
-
"@nx/
|
|
49
|
-
"@nx/
|
|
50
|
-
"@nx/
|
|
51
|
-
"@nx/
|
|
52
|
-
"@nx/
|
|
53
|
-
"@nx/vitest": "23.0.0-beta.22",
|
|
47
|
+
"@nx/devkit": "23.0.0-beta.24",
|
|
48
|
+
"@nx/js": "23.0.0-beta.24",
|
|
49
|
+
"@nx/eslint": "23.0.0-beta.24",
|
|
50
|
+
"@nx/vue": "23.0.0-beta.24",
|
|
51
|
+
"@nx/vite": "23.0.0-beta.24",
|
|
52
|
+
"@nx/vitest": "23.0.0-beta.24",
|
|
54
53
|
"semver": "^7.6.3"
|
|
55
54
|
},
|
|
56
55
|
"devDependencies": {
|
|
57
|
-
"nx": "23.0.0-beta.
|
|
56
|
+
"nx": "23.0.0-beta.24"
|
|
58
57
|
},
|
|
59
58
|
"peerDependencies": {
|
|
60
|
-
"
|
|
59
|
+
"nuxt": ">=3.0.0 <5.0.0",
|
|
60
|
+
"@nuxt/schema": "^3.0.0 || ^4.0.0",
|
|
61
|
+
"@nuxt/kit": "^3.0.0 || ^4.0.0"
|
|
62
|
+
},
|
|
63
|
+
"peerDependenciesMeta": {
|
|
64
|
+
"nuxt": {
|
|
65
|
+
"optional": true
|
|
66
|
+
},
|
|
67
|
+
"@nuxt/schema": {
|
|
68
|
+
"optional": true
|
|
69
|
+
},
|
|
70
|
+
"@nuxt/kit": {
|
|
71
|
+
"optional": true
|
|
72
|
+
}
|
|
61
73
|
},
|
|
62
74
|
"publishConfig": {
|
|
63
75
|
"access": "public"
|
|
@@ -1 +1 @@
|
|
|
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;
|
|
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;AA6BlC,wBAAsB,oBAAoB,CAAC,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,8BAKpE;AAED,wBAAsB,4BAA4B,CAAC,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,8BAqN5E;AAED,eAAe,oBAAoB,CAAC"}
|
|
@@ -15,6 +15,7 @@ const add_linting_1 = require("../../utils/add-linting");
|
|
|
15
15
|
const add_vitest_1 = require("./lib/add-vitest");
|
|
16
16
|
const vue_1 = require("@nx/vue");
|
|
17
17
|
const ensure_dependencies_1 = require("./lib/ensure-dependencies");
|
|
18
|
+
const assert_supported_nuxt_version_1 = require("../../utils/assert-supported-nuxt-version");
|
|
18
19
|
const node_child_process_1 = require("node:child_process");
|
|
19
20
|
const node_path_1 = require("node:path");
|
|
20
21
|
const onboarding_1 = require("nx/src/nx-cloud/utilities/onboarding");
|
|
@@ -26,6 +27,7 @@ async function applicationGenerator(tree, schema) {
|
|
|
26
27
|
});
|
|
27
28
|
}
|
|
28
29
|
async function applicationGeneratorInternal(tree, schema) {
|
|
30
|
+
(0, assert_supported_nuxt_version_1.assertSupportedNuxtVersion)(tree);
|
|
29
31
|
const tasks = [];
|
|
30
32
|
const addTsPlugin = (0, internal_2.shouldConfigureTsSolutionSetup)(tree, true, // nuxt always adds plugins
|
|
31
33
|
schema.useTsSolution);
|
|
@@ -125,7 +127,7 @@ async function applicationGeneratorInternal(tree, schema) {
|
|
|
125
127
|
tasks.push((0, devkit_1.addDependenciesToPackageJson)(tree, {}, {
|
|
126
128
|
'@vue/test-utils': vue_1.vueTestUtilsVersion,
|
|
127
129
|
'@vitejs/plugin-vue': vue_1.vitePluginVueVersion,
|
|
128
|
-
}));
|
|
130
|
+
}, undefined, true));
|
|
129
131
|
tasks.push(await (0, add_vitest_1.addVitest)(tree, options));
|
|
130
132
|
}
|
|
131
133
|
const nuxtInitTask = await (0, init_1.default)(tree, {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ensure-dependencies.d.ts","sourceRoot":"","sources":["../../../../../../../packages/nuxt/src/generators/application/lib/ensure-dependencies.ts"],"names":[],"mappings":"AAAA,OAAO,EAAgC,KAAK,IAAI,EAAE,MAAM,YAAY,CAAC;AASrE,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,WAAW,CAAC;AAElD,wBAAsB,kBAAkB,CACtC,IAAI,EAAE,IAAI,EACV,OAAO,EAAE,gBAAgB,
|
|
1
|
+
{"version":3,"file":"ensure-dependencies.d.ts","sourceRoot":"","sources":["../../../../../../../packages/nuxt/src/generators/application/lib/ensure-dependencies.ts"],"names":[],"mappings":"AAAA,OAAO,EAAgC,KAAK,IAAI,EAAE,MAAM,YAAY,CAAC;AASrE,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,WAAW,CAAC;AAElD,wBAAsB,kBAAkB,CACtC,IAAI,EAAE,IAAI,EACV,OAAO,EAAE,gBAAgB,mDA4B1B"}
|
|
@@ -11,6 +11,7 @@ async function ensureDependencies(host, options) {
|
|
|
11
11
|
'@nx/vite': versions_1.nxVersion, // needed for the nxViteTsPaths plugin and @nx/vite/plugin
|
|
12
12
|
'@nuxt/devtools': nuxtVersions.nuxtDevtools,
|
|
13
13
|
'@nuxt/kit': nuxtVersions.nuxtKit,
|
|
14
|
+
'@nuxt/schema': nuxtVersions.nuxtSchema,
|
|
14
15
|
'@nuxt/ui-templates': nuxtVersions.nuxtUiTemplates,
|
|
15
16
|
nuxt: nuxtVersions.nuxt,
|
|
16
17
|
h3: nuxtVersions.h3,
|
|
@@ -21,5 +22,5 @@ async function ensureDependencies(host, options) {
|
|
|
21
22
|
if (options.style === 'scss') {
|
|
22
23
|
devDependencies['sass'] = vue_1.sassVersion;
|
|
23
24
|
}
|
|
24
|
-
return (0, devkit_1.addDependenciesToPackageJson)(host, {}, devDependencies);
|
|
25
|
+
return (0, devkit_1.addDependenciesToPackageJson)(host, {}, devDependencies, undefined, true);
|
|
25
26
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../../../../../packages/nuxt/src/generators/init/init.ts"],"names":[],"mappings":"AAAA,OAAO,EAA2B,iBAAiB,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;AAI9E,OAAO,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;
|
|
1
|
+
{"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../../../../../packages/nuxt/src/generators/init/init.ts"],"names":[],"mappings":"AAAA,OAAO,EAA2B,iBAAiB,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;AAI9E,OAAO,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AAItC,wBAAsB,iBAAiB,CAAC,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,UAAU,8BAuBrE;AAED,eAAe,iBAAiB,CAAC"}
|
|
@@ -5,7 +5,9 @@ const devkit_1 = require("@nx/devkit");
|
|
|
5
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
|
+
const assert_supported_nuxt_version_1 = require("../../utils/assert-supported-nuxt-version");
|
|
8
9
|
async function nuxtInitGenerator(host, schema) {
|
|
10
|
+
(0, assert_supported_nuxt_version_1.assertSupportedNuxtVersion)(host);
|
|
9
11
|
await (0, internal_1.addPlugin)(host, await (0, devkit_1.createProjectGraphAsync)(), '@nx/nuxt/plugin', plugin_1.createNodesV2, {
|
|
10
12
|
buildTargetName: ['build', 'nuxt:build', 'nuxt-build'],
|
|
11
13
|
serveTargetName: ['serve', 'nuxt:serve', 'nuxt-serve'],
|
|
@@ -12,7 +12,7 @@ async function updateDependencies(host, schema) {
|
|
|
12
12
|
'@nx/nuxt': versions_1.nxVersion,
|
|
13
13
|
nuxt: nuxtVersions.nuxt,
|
|
14
14
|
'@nx/vite': versions_1.nxVersion,
|
|
15
|
-
}, undefined, schema.keepExistingVersions);
|
|
15
|
+
}, undefined, schema.keepExistingVersions ?? true);
|
|
16
16
|
}
|
|
17
17
|
function addVitestTargetDefaults(tree) {
|
|
18
18
|
const nxJson = (0, devkit_1.readNxJson)(tree);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"configuration.d.ts","sourceRoot":"","sources":["../../../../../../packages/nuxt/src/generators/storybook-configuration/configuration.ts"],"names":[],"mappings":"AAAA,OAAO,EAKL,IAAI,EAEL,MAAM,YAAY,CAAC;AAEpB,OAAO,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;
|
|
1
|
+
{"version":3,"file":"configuration.d.ts","sourceRoot":"","sources":["../../../../../../packages/nuxt/src/generators/storybook-configuration/configuration.ts"],"names":[],"mappings":"AAAA,OAAO,EAKL,IAAI,EAEL,MAAM,YAAY,CAAC;AAEpB,OAAO,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAOlC,wBAAsB,+BAA+B,CACnD,IAAI,EAAE,IAAI,EACV,OAAO,EAAE,MAAM,mDA2ChB;AAED,eAAe,+BAA+B,CAAC"}
|
|
@@ -3,11 +3,13 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.storybookConfigurationGenerator = storybookConfigurationGenerator;
|
|
4
4
|
const devkit_1 = require("@nx/devkit");
|
|
5
5
|
const vue_1 = require("@nx/vue");
|
|
6
|
+
const assert_supported_nuxt_version_1 = require("../../utils/assert-supported-nuxt-version");
|
|
6
7
|
/*
|
|
7
8
|
* This generator is basically the Vue one, but for Nuxt we
|
|
8
9
|
* are just adding the styles in `.storybook/preview.ts`
|
|
9
10
|
*/
|
|
10
11
|
async function storybookConfigurationGenerator(tree, options) {
|
|
12
|
+
(0, assert_supported_nuxt_version_1.assertSupportedNuxtVersion)(tree);
|
|
11
13
|
const { root, sourceRoot } = (0, devkit_1.readProjectConfiguration)(tree, options.project);
|
|
12
14
|
// Determine the source directory (app/ for Nuxt v4, src/ for Nuxt v3)
|
|
13
15
|
const sourceDir = sourceRoot?.endsWith('/app')
|
|
@@ -0,0 +1,531 @@
|
|
|
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)
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { type Tree } from '@nx/devkit';
|
|
2
|
+
export default function migrateCreateNodesV2ToCreateNodes(tree: Tree): Promise<void>;
|
|
3
|
+
/**
|
|
4
|
+
* Rewrites named imports and re-exports of `createNodesV2` to `createNodes`
|
|
5
|
+
* when they come from one of the given module specifiers. Only the named
|
|
6
|
+
* bindings are touched — the module specifier, the `import`/`export` keyword,
|
|
7
|
+
* any `type` modifier, and any default import are left untouched.
|
|
8
|
+
*/
|
|
9
|
+
export declare function rewriteCreateNodesV2Imports(source: string, specifiers: ReadonlySet<string>): string;
|
|
10
|
+
//# sourceMappingURL=migrate-create-nodes-v2-to-create-nodes.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"migrate-create-nodes-v2-to-create-nodes.d.ts","sourceRoot":"","sources":["../../../../../../packages/nuxt/src/migrations/update-23-0-0/migrate-create-nodes-v2-to-create-nodes.ts"],"names":[],"mappings":"AAAA,OAAO,EAOL,KAAK,IAAI,EAEV,MAAM,YAAY,CAAC;AAsBpB,wBAA8B,iCAAiC,CAC7D,IAAI,EAAE,IAAI,GACT,OAAO,CAAC,IAAI,CAAC,CAyBf;AAED;;;;;GAKG;AACH,wBAAgB,2BAA2B,CACzC,MAAM,EAAE,MAAM,EACd,UAAU,EAAE,WAAW,CAAC,MAAM,CAAC,GAC9B,MAAM,CAoBR"}
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.default = migrateCreateNodesV2ToCreateNodes;
|
|
4
|
+
exports.rewriteCreateNodesV2Imports = rewriteCreateNodesV2Imports;
|
|
5
|
+
const devkit_1 = require("@nx/devkit");
|
|
6
|
+
const TS_EXTENSIONS = ['.ts', '.tsx', '.cts', '.mts'];
|
|
7
|
+
const DEPRECATED_NAME = 'createNodesV2';
|
|
8
|
+
const CANONICAL_NAME = 'createNodes';
|
|
9
|
+
// Module specifiers from which `@nx/nuxt` publicly exposes `createNodesV2`.
|
|
10
|
+
// A named import or re-export of `createNodesV2` from one of these is rewritten
|
|
11
|
+
// to the canonical `createNodes` export.
|
|
12
|
+
const TARGET_SPECIFIERS = new Set(['@nx/nuxt/plugin']);
|
|
13
|
+
let ts;
|
|
14
|
+
async function migrateCreateNodesV2ToCreateNodes(tree) {
|
|
15
|
+
let touchedCount = 0;
|
|
16
|
+
(0, devkit_1.visitNotIgnoredFiles)(tree, '.', (filePath) => {
|
|
17
|
+
if (!TS_EXTENSIONS.some((ext) => filePath.endsWith(ext))) {
|
|
18
|
+
return;
|
|
19
|
+
}
|
|
20
|
+
const original = tree.read(filePath, 'utf-8');
|
|
21
|
+
if (!original || !original.includes(DEPRECATED_NAME)) {
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
24
|
+
const updated = rewriteCreateNodesV2Imports(original, TARGET_SPECIFIERS);
|
|
25
|
+
if (updated !== original) {
|
|
26
|
+
tree.write(filePath, updated);
|
|
27
|
+
touchedCount += 1;
|
|
28
|
+
}
|
|
29
|
+
});
|
|
30
|
+
if (touchedCount > 0) {
|
|
31
|
+
devkit_1.logger.info(`Renamed \`${DEPRECATED_NAME}\` imports to \`${CANONICAL_NAME}\` in ${touchedCount} file(s).`);
|
|
32
|
+
}
|
|
33
|
+
await (0, devkit_1.formatFiles)(tree);
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Rewrites named imports and re-exports of `createNodesV2` to `createNodes`
|
|
37
|
+
* when they come from one of the given module specifiers. Only the named
|
|
38
|
+
* bindings are touched — the module specifier, the `import`/`export` keyword,
|
|
39
|
+
* any `type` modifier, and any default import are left untouched.
|
|
40
|
+
*/
|
|
41
|
+
function rewriteCreateNodesV2Imports(source, specifiers) {
|
|
42
|
+
ts ??= (0, devkit_1.ensurePackage)('typescript', '*');
|
|
43
|
+
const sourceFile = ts.createSourceFile('tmp.ts', source, ts.ScriptTarget.Latest,
|
|
44
|
+
/* setParentNodes */ true, ts.ScriptKind.TSX);
|
|
45
|
+
const changes = [];
|
|
46
|
+
for (const stmt of sourceFile.statements) {
|
|
47
|
+
if (ts.isImportDeclaration(stmt)) {
|
|
48
|
+
collectImportRewrite(sourceFile, stmt, specifiers, changes);
|
|
49
|
+
}
|
|
50
|
+
else if (ts.isExportDeclaration(stmt)) {
|
|
51
|
+
collectExportRewrite(sourceFile, stmt, specifiers, changes);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
return changes.length > 0 ? (0, devkit_1.applyChangesToString)(source, changes) : source;
|
|
55
|
+
}
|
|
56
|
+
function isTargetSpecifier(node, specifiers) {
|
|
57
|
+
return ts.isStringLiteral(node) && specifiers.has(node.text);
|
|
58
|
+
}
|
|
59
|
+
function collectImportRewrite(sourceFile, stmt, specifiers, changes) {
|
|
60
|
+
if (!isTargetSpecifier(stmt.moduleSpecifier, specifiers)) {
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
const namedBindings = stmt.importClause?.namedBindings;
|
|
64
|
+
// Only `import { ... }` carries renameable named bindings. `import x`,
|
|
65
|
+
// `import * as ns`, and side-effect imports reference the module wholesale
|
|
66
|
+
// and keep working through the `createNodesV2` runtime alias, so we leave
|
|
67
|
+
// them be. A mixed `import def, { createNodesV2 }` still has its named
|
|
68
|
+
// bindings rewritten below — the default binding is untouched.
|
|
69
|
+
if (!namedBindings || !ts.isNamedImports(namedBindings)) {
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
rewriteNamedBindings(sourceFile, namedBindings, changes);
|
|
73
|
+
}
|
|
74
|
+
function collectExportRewrite(sourceFile, stmt, specifiers, changes) {
|
|
75
|
+
if (!stmt.moduleSpecifier ||
|
|
76
|
+
!isTargetSpecifier(stmt.moduleSpecifier, specifiers)) {
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
// `export { ... } from '...'` can be rewritten; `export * from '...'` has no
|
|
80
|
+
// named bindings to rename.
|
|
81
|
+
if (!stmt.exportClause || !ts.isNamedExports(stmt.exportClause)) {
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
rewriteNamedBindings(sourceFile, stmt.exportClause, changes);
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Re-renders the `{ ... }` of a named import/export, renaming any
|
|
88
|
+
* `createNodesV2` specifier to `createNodes`. If renaming would collide with a
|
|
89
|
+
* `createNodes` that is already present (e.g. `{ createNodes, createNodesV2 }`),
|
|
90
|
+
* the duplicate is dropped. Returns without recording a change when the binding
|
|
91
|
+
* list contains no `createNodesV2`.
|
|
92
|
+
*/
|
|
93
|
+
function rewriteNamedBindings(sourceFile, namedBindings, changes) {
|
|
94
|
+
const elements = namedBindings.elements;
|
|
95
|
+
const hasDeprecated = elements.some((el) => (el.propertyName ?? el.name).text === DEPRECATED_NAME);
|
|
96
|
+
if (!hasDeprecated) {
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
99
|
+
const seen = new Set();
|
|
100
|
+
const rendered = [];
|
|
101
|
+
for (const el of elements) {
|
|
102
|
+
const text = renderSpecifier(el);
|
|
103
|
+
if (!seen.has(text)) {
|
|
104
|
+
seen.add(text);
|
|
105
|
+
rendered.push(text);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
const start = namedBindings.getStart(sourceFile);
|
|
109
|
+
changes.push({
|
|
110
|
+
type: devkit_1.ChangeType.Delete,
|
|
111
|
+
start,
|
|
112
|
+
length: namedBindings.getEnd() - start,
|
|
113
|
+
}, {
|
|
114
|
+
type: devkit_1.ChangeType.Insert,
|
|
115
|
+
index: start,
|
|
116
|
+
text: `{ ${rendered.join(', ')} }`,
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
function renderSpecifier(el) {
|
|
120
|
+
const typePrefix = el.isTypeOnly ? 'type ' : '';
|
|
121
|
+
const rename = (name) => name === DEPRECATED_NAME ? CANONICAL_NAME : name;
|
|
122
|
+
// `{ name }` — no alias, so the local binding follows the rename.
|
|
123
|
+
if (!el.propertyName) {
|
|
124
|
+
return `${typePrefix}${rename(el.name.text)}`;
|
|
125
|
+
}
|
|
126
|
+
// `{ propertyName as name }` — only the imported (left) side is renamed; the
|
|
127
|
+
// local alias is preserved. A now-redundant alias such as
|
|
128
|
+
// `createNodesV2 as createNodes` collapses to `createNodes`.
|
|
129
|
+
const canonicalImported = rename(el.propertyName.text);
|
|
130
|
+
const localName = el.name.text;
|
|
131
|
+
return canonicalImported === localName
|
|
132
|
+
? `${typePrefix}${localName}`
|
|
133
|
+
: `${typePrefix}${canonicalImported} as ${localName}`;
|
|
134
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
#### Rename `createNodesV2` imports to `createNodes`
|
|
2
|
+
|
|
3
|
+
`@nx/nuxt` renamed its primary inferred-plugin export from `createNodesV2` to `createNodes`. The `createNodesV2` name is preserved as a deprecated alias for now, but new code should use `createNodes`.
|
|
4
|
+
|
|
5
|
+
This migration scans every `.ts`, `.tsx`, `.cts`, and `.mts` file in your workspace and rewrites named imports and re-exports of `createNodesV2` from `@nx/nuxt/plugin` to `createNodes`.
|
|
6
|
+
|
|
7
|
+
#### Sample Code Changes
|
|
8
|
+
|
|
9
|
+
##### Before
|
|
10
|
+
|
|
11
|
+
```ts
|
|
12
|
+
import { createNodesV2 } from '@nx/nuxt/plugin';
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
##### After
|
|
16
|
+
|
|
17
|
+
```ts
|
|
18
|
+
import { createNodes } from '@nx/nuxt/plugin';
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
Aliases are preserved (`createNodesV2 as cn` becomes `createNodes as cn`), and if a file already imports both names (`{ createNodes, createNodesV2 }`) the redundant binding is dropped.
|
|
22
|
+
|
|
23
|
+
#### What is not rewritten
|
|
24
|
+
|
|
25
|
+
Only static `import`/`export` named bindings from `@nx/nuxt/plugin` are rewritten. Namespace imports, dynamic `import(...)`, `require(...)` destructuring, and property access such as `plugin.createNodesV2` are left untouched — they keep working through the `createNodesV2` runtime alias. Update those by hand if you want to drop the deprecated name everywhere.
|
package/src/plugins/plugin.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { CreateNodes } from '@nx/devkit';
|
|
2
2
|
export interface NuxtPluginOptions {
|
|
3
3
|
buildTargetName?: string;
|
|
4
4
|
serveTargetName?: string;
|
|
@@ -7,6 +7,6 @@ export interface NuxtPluginOptions {
|
|
|
7
7
|
buildDepsTargetName?: string;
|
|
8
8
|
watchDepsTargetName?: string;
|
|
9
9
|
}
|
|
10
|
-
export declare const createNodes:
|
|
11
|
-
export declare const createNodesV2:
|
|
10
|
+
export declare const createNodes: CreateNodes<NuxtPluginOptions>;
|
|
11
|
+
export declare const createNodesV2: CreateNodes<NuxtPluginOptions>;
|
|
12
12
|
//# sourceMappingURL=plugin.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../../../../../packages/nuxt/src/plugins/plugin.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../../../../../packages/nuxt/src/plugins/plugin.ts"],"names":[],"mappings":"AAMA,OAAO,EAML,WAAW,EAMZ,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,WAAW,CAAC,iBAAiB,CAoDtD,CAAC;AAEF,eAAO,MAAM,aAAa,gCAAc,CAAC"}
|
package/src/plugins/plugin.js
CHANGED
|
@@ -134,6 +134,11 @@ function buildStaticTarget(buildStaticTargetName, namedInputs, buildOutputs, pro
|
|
|
134
134
|
return targetConfig;
|
|
135
135
|
}
|
|
136
136
|
async function getInfoFromNuxtConfig(configFilePath, context, projectRoot) {
|
|
137
|
+
// Only `buildDir` is read below. Typing it to the full `@nuxt/schema`
|
|
138
|
+
// `NuxtOptions` couples to one schema version, which clashes when
|
|
139
|
+
// `loadNuxtConfig` returns the (possibly older) `@nuxt/schema` bundled by the
|
|
140
|
+
// installed `@nuxt/kit`. Type just what we read so it holds across the
|
|
141
|
+
// supported Nuxt 3.x–4.x range.
|
|
137
142
|
let config;
|
|
138
143
|
if (process.env.NX_ISOLATE_PLUGINS !== 'false') {
|
|
139
144
|
config = await (await (0, executor_utils_1.loadNuxtKitDynamicImport)()).loadNuxtConfig({
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"add-linting.d.ts","sourceRoot":"","sources":["../../../../../packages/nuxt/src/utils/add-linting.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,wBAAwB,CAAC;AAE9C,OAAO,EAAE,MAAM,EAAE,UAAU,EAAwB,MAAM,YAAY,CAAC;AAEtE,OAAO,EAEL,iBAAiB,EAElB,MAAM,YAAY,CAAC;AAgBpB,wBAAsB,UAAU,CAC9B,IAAI,EAAE,IAAI,EACV,OAAO,EAAE;IACP,MAAM,EAAE,MAAM,GAAG,UAAU,CAAC;IAC5B,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,cAAc,CAAC,EAAE,QAAQ,GAAG,MAAM,CAAC;IACnC,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB,
|
|
1
|
+
{"version":3,"file":"add-linting.d.ts","sourceRoot":"","sources":["../../../../../packages/nuxt/src/utils/add-linting.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,wBAAwB,CAAC;AAE9C,OAAO,EAAE,MAAM,EAAE,UAAU,EAAwB,MAAM,YAAY,CAAC;AAEtE,OAAO,EAEL,iBAAiB,EAElB,MAAM,YAAY,CAAC;AAgBpB,wBAAsB,UAAU,CAC9B,IAAI,EAAE,IAAI,EACV,OAAO,EAAE;IACP,MAAM,EAAE,MAAM,GAAG,UAAU,CAAC;IAC5B,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,cAAc,CAAC,EAAE,QAAQ,GAAG,MAAM,CAAC;IACnC,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB,8BA4DF"}
|
package/src/utils/add-linting.js
CHANGED
|
@@ -45,7 +45,7 @@ async function addLinting(host, options) {
|
|
|
45
45
|
]);
|
|
46
46
|
}
|
|
47
47
|
}
|
|
48
|
-
const installTask = (0, devkit_1.addDependenciesToPackageJson)(host, {}, devDependencies);
|
|
48
|
+
const installTask = (0, devkit_1.addDependenciesToPackageJson)(host, {}, devDependencies, undefined, true);
|
|
49
49
|
tasks.push(installTask);
|
|
50
50
|
}
|
|
51
51
|
return (0, devkit_1.runTasksInSerial)(...tasks);
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"assert-supported-nuxt-version.d.ts","sourceRoot":"","sources":["../../../../../packages/nuxt/src/utils/assert-supported-nuxt-version.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,IAAI,EAAE,MAAM,YAAY,CAAC;AAIvC,wBAAgB,0BAA0B,CAAC,IAAI,EAAE,IAAI,GAAG,IAAI,CAE3D"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.assertSupportedNuxtVersion = assertSupportedNuxtVersion;
|
|
4
|
+
const internal_1 = require("@nx/devkit/internal");
|
|
5
|
+
const versions_1 = require("./versions");
|
|
6
|
+
function assertSupportedNuxtVersion(tree) {
|
|
7
|
+
(0, internal_1.assertSupportedPackageVersion)(tree, 'nuxt', versions_1.minSupportedNuxtVersion);
|
|
8
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"version-utils.d.ts","sourceRoot":"","sources":["../../../../../packages/nuxt/src/utils/version-utils.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,wBAAwB,CAAC;
|
|
1
|
+
{"version":3,"file":"version-utils.d.ts","sourceRoot":"","sources":["../../../../../packages/nuxt/src/utils/version-utils.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,wBAAwB,CAAC;AAenD,MAAM,MAAM,wBAAwB,GAAG;IACrC,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB,EAAE,EAAE,MAAM,CAAC;IACX,YAAY,EAAE,MAAM,CAAC;IACrB,eAAe,EAAE,MAAM,CAAC;CACzB,CAAC;AAEF,wBAAsB,oCAAoC,CACxD,IAAI,EAAE,IAAI,GACT,OAAO,CAAC,wBAAwB,CAAC,CAqBnC;AAED,wBAAsB,QAAQ,CAAC,IAAI,EAAE,IAAI,GAAG,OAAO,CAAC,OAAO,CAAC,CAS3D;AAED,wBAAsB,QAAQ,CAAC,IAAI,EAAE,IAAI,GAAG,OAAO,CAAC,OAAO,CAAC,CAS3D;AAED,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,IAAI,GAAG,MAAM,GAAG,SAAS,CAetE;AAED,wBAAgB,4BAA4B,CAAC,IAAI,EAAE,IAAI,GAAG,CAAC,GAAG,CAAC,GAAG,SAAS,CAW1E;AAED,wBAAsB,gCAAgC,IAAI,OAAO,CAC/D,MAAM,GAAG,SAAS,CACnB,CAWA"}
|
|
@@ -14,6 +14,7 @@ async function getNuxtDependenciesVersionsToInstall(tree) {
|
|
|
14
14
|
return {
|
|
15
15
|
nuxt: versions_1.nuxtV3Version,
|
|
16
16
|
nuxtKit: versions_1.nuxtKitV3Version,
|
|
17
|
+
nuxtSchema: versions_1.nuxtSchemaV3Version,
|
|
17
18
|
h3: versions_1.h3Version,
|
|
18
19
|
nuxtDevtools: versions_1.nuxtDevtoolsV3Version,
|
|
19
20
|
nuxtUiTemplates: versions_1.nuxtUiTemplatesVersion,
|
|
@@ -24,6 +25,7 @@ async function getNuxtDependenciesVersionsToInstall(tree) {
|
|
|
24
25
|
return {
|
|
25
26
|
nuxt: versions_1.nuxtVersion,
|
|
26
27
|
nuxtKit: versions_1.nuxtKitVersion,
|
|
28
|
+
nuxtSchema: versions_1.nuxtSchemaVersion,
|
|
27
29
|
h3: versions_1.h3Version,
|
|
28
30
|
nuxtDevtools: versions_1.nuxtDevtoolsVersion,
|
|
29
31
|
nuxtUiTemplates: versions_1.nuxtUiTemplatesVersion,
|
package/src/utils/versions.d.ts
CHANGED
|
@@ -1,10 +1,14 @@
|
|
|
1
1
|
export declare const nxVersion: any;
|
|
2
|
+
export declare const minSupportedNuxtVersion = "3.0.0";
|
|
2
3
|
export declare const nuxtV4Version = "^4.0.0";
|
|
3
4
|
export declare const nuxtV3Version = "^3.21.1";
|
|
4
5
|
export declare const nuxtVersion = "^4.0.0";
|
|
5
6
|
export declare const nuxtKitV4Version = "^4.0.0";
|
|
6
7
|
export declare const nuxtKitV3Version = "^3.21.1";
|
|
7
8
|
export declare const nuxtKitVersion = "^4.0.0";
|
|
9
|
+
export declare const nuxtSchemaV4Version = "^4.0.0";
|
|
10
|
+
export declare const nuxtSchemaV3Version = "^3.21.1";
|
|
11
|
+
export declare const nuxtSchemaVersion = "^4.0.0";
|
|
8
12
|
export declare const h3Version = "^1.8.2";
|
|
9
13
|
export declare const nuxtDevtoolsV4Version = "^3.0.0";
|
|
10
14
|
export declare const nuxtDevtoolsV3Version = "^3.1.1";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"versions.d.ts","sourceRoot":"","sources":["../../../../../packages/nuxt/src/utils/versions.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,SAAS,KAAwC,CAAC;
|
|
1
|
+
{"version":3,"file":"versions.d.ts","sourceRoot":"","sources":["../../../../../packages/nuxt/src/utils/versions.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,SAAS,KAAwC,CAAC;AAO/D,eAAO,MAAM,uBAAuB,UAAU,CAAC;AAG/C,eAAO,MAAM,aAAa,WAAW,CAAC;AACtC,eAAO,MAAM,aAAa,YAAY,CAAC;AACvC,eAAO,MAAM,WAAW,WAAgB,CAAC;AAGzC,eAAO,MAAM,gBAAgB,WAAW,CAAC;AACzC,eAAO,MAAM,gBAAgB,YAAY,CAAC;AAC1C,eAAO,MAAM,cAAc,WAAmB,CAAC;AAG/C,eAAO,MAAM,mBAAmB,WAAW,CAAC;AAC5C,eAAO,MAAM,mBAAmB,YAAY,CAAC;AAC7C,eAAO,MAAM,iBAAiB,WAAsB,CAAC;AAGrD,eAAO,MAAM,SAAS,WAAW,CAAC;AAClC,eAAO,MAAM,qBAAqB,WAAW,CAAC;AAC9C,eAAO,MAAM,qBAAqB,WAAW,CAAC;AAC9C,eAAO,MAAM,mBAAmB,WAAwB,CAAC;AACzD,eAAO,MAAM,sBAAsB,WAAW,CAAC;AAG/C,eAAO,MAAM,uBAAuB,YAAY,CAAC;AACjD,eAAO,MAAM,6BAA6B,WAAW,CAAC"}
|
package/src/utils/versions.js
CHANGED
|
@@ -1,7 +1,13 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.nuxtEslintConfigLegacyVersion = exports.nuxtEslintConfigVersion = exports.nuxtUiTemplatesVersion = exports.nuxtDevtoolsVersion = exports.nuxtDevtoolsV3Version = exports.nuxtDevtoolsV4Version = exports.h3Version = exports.nuxtKitVersion = exports.nuxtKitV3Version = exports.nuxtKitV4Version = exports.nuxtVersion = exports.nuxtV3Version = exports.nuxtV4Version = exports.nxVersion = void 0;
|
|
3
|
+
exports.nuxtEslintConfigLegacyVersion = exports.nuxtEslintConfigVersion = exports.nuxtUiTemplatesVersion = exports.nuxtDevtoolsVersion = exports.nuxtDevtoolsV3Version = exports.nuxtDevtoolsV4Version = exports.h3Version = exports.nuxtSchemaVersion = exports.nuxtSchemaV3Version = exports.nuxtSchemaV4Version = exports.nuxtKitVersion = exports.nuxtKitV3Version = exports.nuxtKitV4Version = exports.nuxtVersion = exports.nuxtV3Version = exports.nuxtV4Version = exports.minSupportedNuxtVersion = exports.nxVersion = void 0;
|
|
4
4
|
exports.nxVersion = require('../../package.json').version;
|
|
5
|
+
// Lowest Nuxt version the plugin supports. Nuxt 2 is EOL (2024-06-30). The only
|
|
6
|
+
// runtime Nuxt API the plugin uses is `@nuxt/kit`'s `loadNuxtConfig` (reading
|
|
7
|
+
// `buildDir`), which resolves the workspace's own `@nuxt/kit` (an optional
|
|
8
|
+
// peer) and is present since 3.0.0; `@nuxt/schema` is a type-only import. So the
|
|
9
|
+
// effective floor is the v3 major, 3.0.0.
|
|
10
|
+
exports.minSupportedNuxtVersion = '3.0.0';
|
|
5
11
|
// Nuxt versions
|
|
6
12
|
exports.nuxtV4Version = '^4.0.0';
|
|
7
13
|
exports.nuxtV3Version = '^3.21.1';
|
|
@@ -10,6 +16,10 @@ exports.nuxtVersion = exports.nuxtV4Version; // Default to v4
|
|
|
10
16
|
exports.nuxtKitV4Version = '^4.0.0';
|
|
11
17
|
exports.nuxtKitV3Version = '^3.21.1';
|
|
12
18
|
exports.nuxtKitVersion = exports.nuxtKitV4Version;
|
|
19
|
+
// @nuxt/schema versions (aligned with Nuxt)
|
|
20
|
+
exports.nuxtSchemaV4Version = '^4.0.0';
|
|
21
|
+
exports.nuxtSchemaV3Version = '^3.21.1';
|
|
22
|
+
exports.nuxtSchemaVersion = exports.nuxtSchemaV4Version;
|
|
13
23
|
// nuxt deps
|
|
14
24
|
exports.h3Version = '^1.8.2';
|
|
15
25
|
exports.nuxtDevtoolsV4Version = '^3.0.0';
|