fix(nextjs): lazy-load edge WASM and make next/server resolvable when externalized#59
Merged
Merged
Conversation
… externalized The `/nextjs` subpath eagerly imported the WASM glue at module load, whose top-level `__wbindgen_start` a Next build's page-data collection cannot run, and imported `next/server` as an extensionless subpath, which Node's native ESM resolver cannot resolve because `next` ships no `exports` map (so an externalized `serverExternalPackages` consumer failed `next build`). - Defer the WASM to a memoized dynamic `import()` on first use inside the jwt helpers; importing the module (or the barrel) now has no WASM side effect. `decodeJwtToken` becomes async to match `verifyJwtToken`. - Import `next/server.js` (fully specified) in the proxy and route handlers so the built ESM/CJS resolve under Node's raw loader; unchanged under bundlers/Vitest. Keep `next/server.js` external in the tsup build.
There was a problem hiding this comment.
Pull request overview
This PR fixes Next 16 “externalized package” compatibility for the ./nextjs subpath by (1) removing eager WASM initialization at module-load time and (2) making next/server resolvable under Node’s native ESM resolver when serverExternalPackages is used.
Changes:
- Lazy-load the edge WASM glue via a memoized dynamic
import()and use it inside JWT helpers. - Switch Next route/middleware helpers to import
next/server.js(fully specified ESM subpath). - Update tsup externals and Vitest coverage for the now-async
decodeJwtToken.
Reviewed changes
Copilot reviewed 5 out of 5 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| packages/rust-auth/tsup.config.ts | Externalizes next/server.js so the fully-specified import stays external in the build output. |
| packages/rust-auth/tests/nextjs.test.ts | Updates decode tests to await decodeJwtToken after it became async. |
| packages/rust-auth/src/nextjs/proxy.ts | Imports NextResponse / NextRequest from next/server.js to support Node ESM resolution when externalized. |
| packages/rust-auth/src/nextjs/jwt.ts | Introduces memoized dynamic WASM loader; makes decodeJwtToken async and loads wasm on first use. |
| packages/rust-auth/src/nextjs/handlers.ts | Imports NextResponse / NextRequest from next/server.js for the same ESM-resolution reason as proxy.ts. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Member
Author
|
Both threads are intentional/minor:
Resolving. |
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
A Next 16 app that installs
@bymax-one/rust-authand marks itserverExternalPackages(required today because the/nextjssubpath ships aWASM verifier) could not
next build, and could not import the/nextjsbarrelunder Node's ESM loader:
src/nextjs/jwt.tsimported the WASM glue at module load; theglue self-initializes (
__wbindgen_start) on import, which Next's page-datacollection sandbox cannot execute. Importing the
/nextjsbarrel therefore hada WASM side effect at load time.
next/serverunresolvable.proxy.tsandhandlers.tsimported the baresubpath
next/server.nextships noexportsmap, so Node's native ESMresolver (used for externalized packages) cannot resolve an extensionless
subpath — it fails with
ERR_MODULE_NOT_FOUND … next/serverand the hint"Did you mean to import next/server.js?". (The CJS
requirepath worked; onlythe ESM
.mjsbuild broke, which is what atype: moduleNext 16 app loads.)Fix
import()on first useinside the jwt helpers. Importing the module — or the
/nextjsbarrel — now hasno WASM side effect.
decodeJwtTokenbecomesasyncto matchverifyJwtToken(both await the shared, single-instance loader). No other public export changes.
next/server: import the fully-specifiednext/server.jsin theproxy and route handlers, and keep it external in the tsup build. This resolves
under Node's raw ESM loader while remaining resolvable under bundlers
(Next/Turbopack/webpack) and Vitest.
nextstays an optional peer dependency.Verification
typecheck,lint,test(48 passing),build.rust-auth-exampleconsole (Next 16.2.10):next buildsucceeds (edge middleware + route handlers), the
.wasmis emitted as anon-demand code-split chunk, and the web unit suite passes (123 tests).
nest-auth-exampledependson the separate
@bymax-one/nest-authpackage, not this one; the change keepsthe same public export names and both ESM and CJS builds.