fix(nuxt): make the Nuxt integration work on a stock Nuxt 4 app - #985
fix(nuxt): make the Nuxt integration work on a stock Nuxt 4 app#985philmillman wants to merge 14 commits into
Conversation
- Add packages/integrations/nuxt with Nuxt module wrapping the Vite plugin - Add docs page at integrations/nuxt - Add Nuxt to sidebar, works-with tiles, and root README Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Rename package to @varlock/nuxt across package metadata and docs - Use addVitePlugin from @nuxt/kit in the Nuxt module - Target Nuxt 4 in devDependencies while keeping compatibility >=3.0.0 - Add bumpy changeset for @varlock/nuxt Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Add inline declarations for __VARLOCK_INTEGRATION_NAME__ and __VARLOCK_INTEGRATION_VERSION__ - Keeps ts-src consumers type-safe during workspace typecheck Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Add a vitest for @varlock/nuxt module setup - Verify addVitePlugin registration and option forwarding - Add test and test:ci scripts to the Nuxt package Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Remove claim that ENV is available during nuxt.config evaluation - Document varlock run + process.env pattern for config-time usage Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Build @varlock/vite-integration before running Nuxt package tests - Ensures clean workspace runs do not depend on prebuilt dist artifacts Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The plugin reloaded varlock from vite's `root`, which is not the project root for every framework. Nuxt points `root` at the srcDir (`app/` in Nuxt 4), so `varlock load` ran where there is no `.env.schema`, succeeded with an empty graph, and silently dropped every build-time `ENV.*` replacement. - add a `rootDir` option so an integration can name the real project root - track the directory the config was loaded from, and compare against that rather than `process.cwd()`. This also fixes the telemetry-triggered reload and the dev-restart reload, which both fell back to cwd and would undo a corrected root, and removes one redundant `varlock load` per build - warn when a reload from a new directory empties a working config, instead of failing silently at runtime Also export `buildVarlockSsrInitCode`, extracted verbatim from the plugin closure, so integrations can inject the same init sequence into build pipelines vite does not own. It takes `rootDir` for callers that run before the `config` hook, and `preserveSideEffectImports` for bundlers that treat external modules as side-effect free. The `declare const` block added for ts-src consumers is reverted; the consuming package gets its own `globals.d.ts`, matching every other integration.
…ro build Two defects made the module non-functional on a stock Nuxt 4 app: 1. Nuxt sets vite's `root` to the srcDir, so varlock loaded no schema and `ENV.*` was never inlined. `nuxt dev` returned 500 on every route, and production builds shipped a client bundle that threw "`ENV.X` does not exist" during hydration. The module now passes `nuxt.options.rootDir` to the vite plugin. 2. Nitro rebuilds the server with its own rollup pass, so the init module injected into vite's SSR entry never reached `.output/server` — and `server/api/**` routes are never in vite's module graph at all. The result: `ssrInjectMode: 'auto-load'` was a no-op, log redaction never ran, and a route returning a sensitive value served it in plaintext. The module now registers the same init as a nitro plugin. Fixing (2) surfaced a third issue: nitro's rollup treats externals as side-effect free and tree-shook the bare `import 'varlock/auto-load'`, so the init code is emitted with `preserveSideEffectImports`. `nuxt build --cwd <dir>` does not chdir, so the nitro init template — which is generated before vite's `config` hook — is given `rootDir` too. Without it a `resolved-env` build baked an empty env and every route 500'd. Packaging: - `@nuxt/kit` moves to `dependencies`. It was bundled from devDependencies, which put a second copy of kit in the artifact and took dist from 575 KB to 67 KB once externalized. - add `src/globals.d.ts` for the build-time constants, as the other integrations do, so the vite source does not need the declarations - add a vitest config resolving workspace deps through `ts-src`, so `test:ci` no longer has to build another package first - register `cascadeFrom: ["@varlock/vite-integration"]` so a vite plugin release republishes the bundled copy
Both defects fixed in the previous commit only appear in a real build, so the integration needed the same end-to-end coverage every other one has. Scenarios: build assertions against the default Nuxt 4 layout (the srcDir regression guard), a `--cwd` build (guards the nitro init template's load directory), and three production-server runs covering `init-only` under `varlock run`, `auto-load` standalone, and response leak prevention. Registers `@varlock/nuxt` in the pack helper and the changed-integration detection so CI runs these when either package changes. The dev-server scenario is skipped: `nuxt dev` emits nothing when spawned by this harness (detached + shell) so the ready pattern never matches, while the identical spawn streams normally outside vitest. Details are in the TODO next to it; dev behavior was verified by hand.
- state the default mode (`init-only`) and what each mode is actually for, including the `varlock run` invocation the default requires. The previous text recommended `auto-load` without saying the default differs. - note that the module does not disable Nuxt's own `.env` loading, so `process.env.X` and `ENV.X` can diverge when a plain `.env` is present - the package README claimed it overrides Nuxt's env loading; it describes what the module does now that it covers the nitro build - drop em dashes per the repo writing conventions
|
The changes in this PR will be included in the next version bump.
|
commit: |
Deploying with
|
| Status | Name | Latest Commit | Preview URL | Updated (UTC) |
|---|---|---|---|---|
| ✅ Deployment successful! View logs |
varlock-website | 3591e9f | Commit Preview URL Branch Preview URL |
Aug 05 2026, 06:02 PM |
There was a problem hiding this comment.
Important
The Nuxt package's new standalone test setup still requires a prebuilt workspace dependency.
Reviewed changes across the new Nuxt module, shared Vite initialization extraction, Nitro integration, package wiring, framework coverage, and documentation.
- Nuxt module: Registers the Varlock Vite plugin with the Nuxt project root and injects the same initialization sequence into Nitro's server bundle.
- Shared Vite behavior: Adds explicit load-root tracking and exports the SSR initialization-code builder while retaining existing SSR modes, encryption, and platform-specific handling.
- Runtime coverage: Exercises stock Nuxt 4 builds, alternate working directories, Nitro routes, SSR injection modes, leak blocking, and log redaction; the live dev scenario remains skipped with its harness limitation documented.
- Packaging and docs: Adds release cascading, framework-test packing, package metadata, installation guidance, navigation, and SSR-mode documentation.
azure/gpt-5.6-sol | 𝕏
Matches the naming used by every other integration in the repo (astro-integration, cloudflare-integration, expo-integration, nextjs-integration, vite-integration), reverting the rename made earlier in this branch. Updates the package name, docs, root README table, bumpy config and changeset, framework test fixtures and pack helper, changed-integration detection, and the lockfile.
|
Addressed the review by explicitly aliasing Task list (4/4 completed)
|



Builds on #982 (from a fork, so this targets
mainand carries its 8 commits). The last four commits are the new work. Intended to land in place of #982, or to be cherry-picked onto it.Testing the Nuxt module against a real Nuxt 4 app turned up two defects that made it non-functional on a stock scaffold, plus a third found while fixing the second.
1. Env loaded from the wrong directory
Nuxt points vite's
rootat the srcDir (app/by default in Nuxt 4), but.env.schemalives at the project root. The vite plugin reloaded varlock fromroot,varlock loadsucceeded there with an empty graph, and every build-timeENV.*replacement was dropped without a warning:nuxt devreturned 500 on every route. Production builds shipped a client bundle that threwENV.PUBLIC_GREETING does not existduring hydration and rendered the Nuxt error page.The plugin gains a
rootDiroption; the module passesnuxt.options.rootDir. The plugin now also tracks which directory the config came from and compares against that instead ofprocess.cwd(), which fixes two other reloads that fell back to cwd (the telemetry-triggered one and the dev-restart one) and drops a redundantvarlock loadper build.2. Init never reached the nitro bundle
Nitro rebuilds the server with its own rollup pass, so the init module injected into vite's SSR entry never reached
.output/server— andserver/api/**routes are never in vite's module graph at all.So
ssrInjectMode: 'auto-load'was a no-op (the mode the docs recommended for Node hosting), server-side log redaction never ran, and a route returning a sensitive value served it in plaintext with a 200. The module now registers the same init as a nitro plugin viaaddTemplate+addServerPlugin.buildVarlockSsrInitCodeis extracted from the plugin closure and exported so both paths share one implementation; the extraction is verbatim.3.
auto-loadtree-shaken out of the nitro bundleNitro's rollup treats external modules as side-effect free and dropped the bare
import 'varlock/auto-load'. Emitted as a namespace binding under a newpreserveSideEffectImportsoption.Also covered:
nuxt build --cwd <dir>does not chdir, and the nitro init template is generated before vite'sconfighook, soresolved-envbaked an empty env and the server 500'd. The template is givenrootDirtoo.Verified
Against a real Nuxt 4 app on the default
app/layout:nuxt devENVauto-loadstandaloneresolved-env(incl.--cwd)DETECTED LEAKED SENSITIVE CONFIGsecret-log-test: su▒▒▒▒▒New framework tests cover all of it: 16 passed, 5 skipped. Since the shared vite plugin changed, I also ran the suites that exercise it hardest — SvelteKit 19 passed, Astro v7 50 passed. Lint,
typecheck:all, workspacetest:ci, and the docs build all pass.The
--cwdscenario was negative-controlled: with the fix reverted it fails onOutput files should contain "PUBLIC_VAR", and passes with it restored.Packaging
@nuxt/kitmoved todependencies. It was being bundled from devDependencies, putting a second copy of kit in the artifact; dist went 575 KB → 67 KB.src/globals.d.tsfor the build-time constants, matching the other integrations, so the vite source no longer needs inlinedeclare consts (that commit and its bump file are reverted).ts-src, sotest:ciis plainvitest --runagain rather than building another package first.cascadeFrom: ["@varlock/vite-integration"]so a vite plugin release republishes the bundled copy, and wired the package into the pack helper and changed-integration detection.For the reviewer
nuxt devemits nothing when spawned by this harness (detached + shell) so the ready pattern never matches, while the identical spawn — same command, cwd, env, pnpm version,--no-fork, stdin from/dev/null— streams normally outside vitest. It looks like harness plumbing rather than an integration bug; dev behavior was verified by hand. A TODO next to it records what was tried. Worth a look from someone who knows that harness better.ssrInjectModenow states the default and what each mode is for, and notes that the module does not disable Nuxt's own.envloading, soprocess.env.XandENV.Xcan diverge when a plain.envis present.@varlock/nuxt-integration, matching every other integration in the repo. feat: add @varlock/nuxt package and docs #982 had renamed it to@varlock/nuxt; that rename is reverted here.