Add support for Nuxt 4 - #13
Merged
Merged
Conversation
Widen the nuxt peer range to ^3.0.0 || ^4.0.0 and the @nuxt/kit dependency to ^3.17.5 || ^4.0.0, so kit dedupes to the copy the host application already installs instead of nesting a second major. Nuxt 4 changed the default of useAsyncData's data and error from null to undefined. Slot and Personalization compared error strictly against null, so a successful Personalization rendered its error slot with an undefined error and failed with a 500. Both now treat undefined as no error. Tests: - Upgrade @nuxt/test-utils to v4 and vitest to v4, and move the development dependency on nuxt to 4.5.2. Tests that read the runtime config at describe scope now do it in beforeAll, as Nuxt 4 has no app instance while the module body evaluates. - Run the e2e suite against both Nuxt 3 and Nuxt 4, pinning @nuxt/kit alongside nuxt so the Nuxt 3 leg does not load kit 4. - Wait for hydration before clicking links in the specs that assert a client-side navigation. Clicking earlier performs a full navigation, so those specs were asserting the server context instead. Tooling: - Upgrade @nuxt/module-builder to v1, which drops its nuxt-3-only kit peer. It emits the module declarations as .d.mts, so the type entry points move accordingly. - Stop publishing the prepare script. npm runs it for git and tarball installs, where e2e/app does not exist. The validate script now prepares the types it needs itself, and dev:prepare remains for editor support. - Configure an explicit import resolver for ESLint. Without one, import-x falls back to the legacy node resolver, which is not installed, and no-cycle walking into node_modules loaded lightningcss/node as the resolver, crashing the lint run.
commit: |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Installing
@croct/plug-nuxtin a Nuxt 4 app fails withERESOLVE, since the peer range is stillnuxt@^3.0.0. This widens the range, fixes the Nuxt 4 regressions that widening exposed, and moves the test toolchain to Nuxt 4 while keeping Nuxt 3 covered in CI.Changes
Support
peerDependencies.nuxt:^3.0.0→^3.0.0 || ^4.0.0dependencies["@nuxt/kit"]:^3.17.5→^3.17.5 || ^4.0.0. Left at^3, npm nests a second kit under the module; widened, it dedupes to the host's copy.Nuxt 4 fix
Nuxt 4 changed the default of
useAsyncData'sdataanderrorfromnulltoundefined.Personalizationcheckederror.value !== nullbefore anything else, so every successful render took the error branch and threw a 500 (Cannot read properties of undefined (reading 'message')).Slothad the same check but escaped because it testsdatafirst. Both now treatundefinedas no error.Tests
@nuxt/test-utils3 → 4 andvitest3 → 4; thenuxtdev dependency moves to^4.5.2. With test-utils 3, thenuxtvitest environment fails to boot under Nuxt 4.describebody. Nuxt 4 has no app instance while the module evaluates, so they now do it inbeforeAll.nuxtand@nuxt/kittogether; downgrading onlynuxtleaves kit 4 hoisted, so the module would run kit 4 against a Nuxt 3 app.waitForHydration()e2e helper. Clicking aNuxtLinkbefore hydration performs a full document navigation, so the client-navigation specs were asserting the server-rendered context instead. Nuxt 4 dev hydrates slowly enough to expose this;identity.spec.tshad the same race and was passing for the wrong reason.Tooling
@nuxt/module-builder0.8 → 1.0. v1 drops the Nuxt-3-only kit peer. It emits the module entry declarations as.d.mts, soexports["."].typesandtypespoint there now. The runtime declarations are still.d.ts, so./typesand./csrare unchanged.prepareis no longer published. npm runs it for git and tarball installs, wheree2e/appdoesn't exist.tscneeds the generated#importstypes, sovalidatenow runsnuxi prepare e2e/appitself, anddev:preparestays for editor support.master.@croct/eslint-pluginsets no import resolver, so import-x falls back to the legacynodeone, which isn't installed. Its last fallback resolves<package>/nodeas a path, and onceno-cyclewalked intonode_modules, it loadedlightningcss/node(native bindings) as the resolver and crashed the run. An expliciteslint-import-resolver-typescriptresolver fixes it, and also resolves#appand#importsthrough the tsconfig paths.Verification
lintvalidatebuildBoth Nuxt 4 e2e failures were reproduced first, and both specs were confirmed to pass on Nuxt 3, so neither was a flake.
Type resolution after the
.d.mtsmove was checked against the packed tarball in a scratch consumer: imports of@croct/plug-nuxt,/typesand/csrtypecheck under bothmoduleResolution: bundlerandnodenext. A negative control ({appId: 42}) fails as expected, so the types are really loaded rather than falling back toany.End to end, the packed tarball installs into a Nuxt 4.5.2 app without
overridesorERESOLVE, with a single@nuxt/kit, and the app builds with both/api/_croct/*handlers registered.Notes
nuxt@4.5.2requires Node^22.19.0 || ^24.11.0. On older Node,^4.0.0silently resolves to 4.4.5, whose exact kit pin nests a second@nuxt/schemaand breakstsc. That's why the dev dependency is pinned to^4.5.2. CI's Node 22 is unaffected.import-x/no-cycleruns now, but it doesn't report a planted two-file cycle, even withmaxDepthraised. That's a limitation of the import-x build bundled into@croct/eslint-plugin, not something this PR can fix.