fix: CJS/ESM named-export interop for js-sha256 & gql-query-builder under Nuxt 4 / Vite 7#18
Merged
Merged
Conversation
…uilder under Nuxt 4 / Vite 7 Removes the client-only build.transpile pushes for js-sha256 and gql-query-builder (the root cause: under Vite 7 / Nuxt 4 they were served raw, breaking named imports and the client bundle → no hydration). Both are now read through dedicated interop helpers (namespace import + default fallback) and pre-bundled via optimizeDeps. - add runtime/helpers/js-sha256-interop.ts and gql-query-builder-interop.ts (kept out of the auto-imported runtime dirs so their generic exports don't leak into the global Nuxt auto-import namespace) - point the 5 runtime import sites at the interop helpers - keep the two deps decoupled so the password-hashing path never pulls gql-query-builder - gate gql-query-builder pre-bundling behind !disableGraphql Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
Fixes Nuxt 4 / Vite 7 client hydration breakage caused by importing named exports from CJS/UMD dependencies (js-sha256, gql-query-builder) when those deps are served “raw” due to build.transpile.
Changes:
- Introduces explicit CJS/UMD interop helpers that resolve exports via namespace import + default fallback.
- Updates GraphQL composables and metadata hashing code to import from the interop helpers instead of named-importing the packages directly.
- Removes the
build.transpileworkaround and relies on Vite dep optimization (and Rollup CJS handling in production) to generate correct interop.
Reviewed changes
Copilot reviewed 8 out of 8 changed files in this pull request and generated no comments.
Show a summary per file
| File | Description |
|---|---|
| src/runtime/helpers/js-sha256-interop.ts | Adds a js-sha256 interop wrapper to safely access sha256 under CJS/UMD. |
| src/runtime/helpers/gql-query-builder-interop.ts | Adds a gql-query-builder interop wrapper for query/mutation/subscription. |
| src/runtime/functions/graphql-meta.ts | Switches hashing import to the js-sha256 interop helper. |
| src/runtime/composables/gql-subscription.ts | Switches subscription import to the interop helper. |
| src/runtime/composables/gql-query.ts | Switches query import to the interop helper. |
| src/runtime/composables/gql-mutation.ts | Switches mutation import to the interop helper. |
| src/runtime/composables/gql-async-query.ts | Switches query import to the interop helper. |
| src/module.ts | Stops transpiling the deps and instead ensures dev pre-bundling via optimizeDeps.include (with GraphQL gating). |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
The exclude array was initialized but never pushed to. Removed as part of the CJS/ESM interop cleanup (flagged by review). No behavior change. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
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.
Problem
Under Vite 7 / Nuxt 4,
@lenne.tech/nuxt-basebroke the client bundle → no hydration (dropdowns/forms/buttons dead). Root cause lived entirely in this module:{ sha256 }fromjs-sha256,{ query, mutation, subscription }fromgql-query-builder.module.tspushed both packages intobuild.transpile(client-only) — the// TODO: Remove when package fixed with valid ESM exportsworkaround. Under Vite 7 that serves them raw (no esbuild pre-bundling), so the named imports aren't statically detectable → client bundle crash.This surfaced during the Nuxt 3→4 migration in a consumer project, which had to work around it with per-project Vite-alias shims. That workaround belongs here instead — fixed at the source, no consumer shims needed.
Fix
build.transpilepushes — the actual root cause. Both deps are pure CJS (no ESM entry point), so pre-bundling viaoptimizeDeps(dev/esbuild) and Rollup's commonjs plugin (build) produces the proper interop wrapper.runtime/helpers/js-sha256-interop.ts,gql-query-builder-interop.ts) using namespace-import + default-fallback, covering both CJS shapes (__esModuleandmodule.exports = {}).Review hardening
A high-effort review caught follow-ups, all addressed:
query/mutation/subscription/sha256) don't leak into consumers' global Nuxt auto-import namespace.sha256) path never pullsgql-query-builderinto the graph.disableGraphql—gql-query-builderpre-bundling is gated behind!disableGraphql;js-sha256stays unconditional (backs password hashing).Validation
sha256/query/mutation/subscriptionresolve to functions,sha256("abc")correct, query builder works.Open / before release
Full production client build couldn't be exercised in the dev environment (pre-existing
nuxi preparefailure, unrelated to this change). Definitive test: production build + hydration/login check in a consumer (regio-match) with this nuxt-base and the MR !467 shims removed. Once released, that project's alias-shim workaround can be dropped.🤖 Generated with Claude Code