Skip to content

fix(Link): export onNuxtReady from the Vue stubs - #546

Merged
IgorShevchik merged 1 commit into
mainfrom
fix/vue-stub-on-nuxt-ready
Sep 7, 2026
Merged

fix(Link): export onNuxtReady from the Vue stubs#546
IgorShevchik merged 1 commit into
mainfrom
fix/vue-stub-on-nuxt-ready

Conversation

@IgorShevchik

Copy link
Copy Markdown
Collaborator

pnpm repl:build has been failing on main since #541, taking the Pages deploy down with it — three commits (89f81a79, dbd5e7dd, 6ae5680d), while ci stayed green the whole time.

[MISSING_EXPORT] "onNuxtReady" is not exported by "../../dist/runtime/vue/stubs/none.js"
   ╭─[ ../../src/runtime/components/Link.vue?vue&type=script&setup=true&lang.ts:9:46 ]

Link.vue imports onNuxtReady from #imports unconditionally and calls it only behind prefetchApi, which is undefined without NuxtLink — so no Vue build ever runs it. An import that is never called still has to resolve, and rolldown fails the whole bundle rather than warning.

The fix

onNuxtReady in src/runtime/vue/stubs/base.ts: runs the callback at the next idle moment, does nothing on the server. Nuxt's own waits for hydration and then for idle; a plain Vue app has no hydration to wait for, so only the idle half is left — and that is the half callers want, since this is how work is kept out of the mount path.

Why ci could not see it

#imports is a Nuxt alias. typecheck, test and build all resolve it against Nuxt's generated types, where every name is present. The stubs are consulted only by a bundle built without Nuxt, which in this repository is pnpm repl:build — a step in deploy.yml and in no other workflow. So a missing export leaves ci green, merges, and takes the deploy down on main.

test/utils/vue-stub-imports.spec.ts closes that gap where it is cheap: it reads every import { … } from '#imports' under src/runtime as text and asserts all three stub entry points (none, vue-router, inertia) cover the names. Read as text on purpose — importing #imports from a test resolves it through Nuxt, which is the resolution this check exists to bypass.

Mutation-checked:

mutation result
un-export onNuxtReady from base.ts (the regression itself) red, and names src/runtime/components/Link.vue as the caller
delete export * from './base' in none.ts red on none only
rename one inherited export (useAppConfig) red on all three

One of those mutations was invalid on the first attempt and worth recording: commenting the re-export out with // left the test green, because the helper's export \* from '\./base' regex matches inside a comment too. Deleting the line is the mutation that actually removes the behaviour.

Verified against the real criterion, not just the guard: pnpm repl:build fails on main and succeeds here.

Local gate green: lint · typecheck · build (3.87 MB) · test (345 files, 7855 passed, 6 skipped) · test:module · repl:build.

Not fixed here

ci still builds nothing against the stubs, so a repl breakage of a different shape would still reach main the same way. Adding repl:build to ci.yml is the general fix and a separate call — this PR covers the specific failure class cheaply.

🤖 Generated with Claude Code

https://claude.ai/code/session_01JS8ypVfQSFzYVZzkTHhURb


Generated by Claude Code

`pnpm repl:build` has been failing on `main` since #541, taking the Pages
deploy with it — three commits, while `ci` stayed green the whole time.

rolldown reports it as:

    [MISSING_EXPORT] "onNuxtReady" is not exported by
    "../../dist/runtime/vue/stubs/none.js"

`Link.vue` imports `onNuxtReady` from `#imports` unconditionally and calls it
only behind `prefetchApi`, which is `undefined` without `NuxtLink` — so no Vue
build ever runs it. An import that is never called still has to resolve, and
rolldown fails the whole bundle rather than warning.

The stub runs the callback at the next idle moment and does nothing on the
server. Nuxt's own waits for hydration and then for idle; a plain Vue app has
no hydration to wait for, so only the idle half is left, and that is the half
callers want.

Why `ci` could not see it: `#imports` is a Nuxt alias, so `typecheck`, `test`
and `build` all resolve it against Nuxt's generated types, where the name is
present. The stubs are consulted only by a bundle built *without* Nuxt, which
here is `pnpm repl:build` — a step in `deploy.yml` and in no other workflow.

`test/utils/vue-stub-imports.spec.ts` closes that gap at the level where it is
cheap: it reads every `import { … } from '#imports'` under `src/runtime` as
text and asserts all three stub entry points cover the names. Mutation-checked
— removing this export, dropping `export * from './base'`, and renaming one
inherited export each turn it red, and the first names `Link.vue` as the caller.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JS8ypVfQSFzYVZzkTHhURb
@IgorShevchik
IgorShevchik merged commit 87af000 into main Sep 7, 2026
2 checks passed
@IgorShevchik
IgorShevchik deleted the fix/vue-stub-on-nuxt-ready branch September 7, 2026 09:04
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants