feat(nuxt): build-time validation & dynamic runtime proxy#1256
feat(nuxt): build-time validation & dynamic runtime proxy#1256yamcodes wants to merge 22 commits into
Conversation
🦋 Changeset detectedLatest commit: 8f15234 The changes in this PR will be included in the next version bump. This PR includes changesets to release 1 package
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
arkenv
@arkenv/build
@arkenv/bun-plugin
@arkenv/cli
@arkenv/fumadocs-ui
@arkenv/nextjs
@arkenv/nuxt
@arkenv/vite-plugin
commit: |
📦 Bundle Size Report✅ All size limits passed! |
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
…rkenv dependencies
…vironment handling
|
not sure the nuxt integration needs codegen |
There was a problem hiding this comment.
Important
The changeset examples do not match the actual config API, and two runtime issues (an un-catchable process.exit and a global flag race) should be addressed before merge.
Reviewed changes — Adds build-time validation and env.gen.ts codegen to the @arkenv/nuxt module, closely mirroring the existing Next.js integration.
- Adds
setupArkEnv,runCodegen, andvalidateSchemapublic helpers inpackages/nuxt/src/config.ts. - Wires
validateandcodegenmodule options (both defaulttrue) into the Nuxt module lifecycle. - Adds generated
env.gen.tsfactories for flat, legacy, and strict layouts with Nuxt-specificruntimeEnv(window.__NUXT__.config.public). - Updates
examples/with-nuxtto the flat-layout generated-factory pattern. - Adds test coverage for codegen, validation, and dev file-watching.
⚠️ Changeset examples use incorrect option names and prefix
The changeset's usage examples do not match the actual ArkEnvConfigOptions API. Readers will copy-paste invalid config.
- The example uses
schema, but the option isschemaPath. codegenis shown as{ enabled, path, layout }, but the code expects a boolean;pathisoutputPathandlayoutis a top-level option.- The
env.tsexample declaresNEXT_PUBLIC_API_URLinstead ofNUXT_PUBLIC_API_URL.
⚠️ setupArkEnv exits the process on validation failure
packages/nuxt/src/config.ts catches validation errors and calls process.exit(1). The Nuxt module path (packages/nuxt/src/module.ts) rethrows the same error instead. A public helper that unconditionally terminates the process is hard to use in tests, scripts, or programmatic integrations.
⚠️ __arkenv_force_server__ global flag is racy for a public helper
validateSchema sets and deletes a global boolean. Because the helper is now exported and can be called concurrently, one call's finally block can clear the flag while another call is still evaluating the schema. Consider a reference counter or scoping the force-server state to the call context.
ℹ️ Nitpicks
validateSchemahardcodes jiti aliases for every@arkenv/nuxt/*subpath by probing for.ts/.jsfiles relative toimport.meta.url. This is fragile if package exports or build output layouts change.- The watcher test sleeps for 100 ms and 300 ms; real timers make it flaky in CI.
- Nuxt docs under
apps/www/content/docs/nuxt/should cover the newvalidateandcodegenoptions.
Kimi K2 (free via Pullfrog for OSS) | 𝕏
|
Run failed. View the logs →
|
There was a problem hiding this comment.
Important
The changeset example registers the wrong module entry, and the generated runtimeEnv code can break for valid environment-variable names that aren't JavaScript identifiers.
Reviewed changes — Re-reviewed the commits pushed since the last Pullfrog review. The prior feedback has been addressed: changeset examples now match the config API, setupArkEnv throws instead of calling process.exit, and validateSchema uses a reference counter for the force-server flag. Alias resolution was also moved from hardcoded file probing to reading package.json exports.
- Fixed
.changeset/nuxt-validation-codegen.mdusage example to useschemaPath,outputPath, top-levellayout, andNUXT_PUBLIC_prefix. - Replaced unconditional
process.exit(1)insetupArkEnvwith thrown errors. - Made
__arkenv_force_server__re-entrant by tracking a global reference count. - Replaced hardcoded jiti alias file probes with dynamic resolution from
@arkenv/nuxt/package.jsonexports. - Added Nuxt module tests for codegen and validation in
packages/nuxt/src/module.test.ts.
ℹ️ Nitpicks
- The watcher test in
packages/nuxt/src/config.test.tsstill sleeps for100ms and300ms with real timers; using fake timers or awaiting watcher readiness would make it less flaky. - The Nuxt docs under
apps/www/content/docs/nuxt/should cover the newvalidateandcodegenoptions.
Kimi K2 (free via Pullfrog for OSS) | 𝕏
There was a problem hiding this comment.
ℹ️ No new issues in this docs-only delta.
Reviewed changes — Merged docs updates from dev that rename the Nuxt "simple" layout to "flat" and refresh the examples to match the flat API.
- Renamed
simple.mdxtoflat.mdxand rewrote code samples to use the flat schema object withNUXT_PUBLIC_prefixes and anexposeToClientexample. - Updated Nuxt docs index and layouts meta to link to the new flat layout page.
- Updated
using-other-validators.mdxto show flat-layout Zod/Valibot examples. - Added a permanent redirect from
/docs/nuxt/layouts/simpleto/docs/nuxt/layouts/flatinapps/www/next.config.ts.
Kimi K2 (free via Pullfrog for OSS) | 𝕏
…racketed environment keys
There was a problem hiding this comment.
✅ No new issues found.
Reviewed changes — Addressed the remaining review feedback by fixing the changeset module entry and making generated runtimeEnv keys safe for env var names that are not valid JavaScript identifiers.
- Fixed
.changeset/nuxt-validation-codegen.mdmodule import — changed the registered module from@arkenv/nuxtto@arkenv/nuxt/moduleso the usage snippet actually boots. - Made generated
runtimeEnvuseJSON.stringifyand bracket access —generateRuntimeEnvLinesnow emits"KEY": ... public?.["KEY"] ?? process.env["KEY"] ..., so valid env var names such asNUXT_PUBLIC_MY-KEYproduce valid TypeScript and runtime lookups. - Updated generated examples and test assertions — refreshed
apps/playgrounds/nuxt/generated/env.gen.ts,examples/with-nuxt/generated/env.gen.ts, andpackages/nuxt/src/config.test.tsexpectations to match the bracketed output.
Kimi K2 (free via Pullfrog for OSS) | 𝕏
…me-validation-codegen # Conflicts: # packages/nuxt/src/module.test.ts # packages/nuxt/src/module.ts
There was a problem hiding this comment.
Important
packages/nuxt/src/module.ts has a duplicate normalizeLayout declaration that breaks tsc and Biome. Remove the local redeclaration (and the now-unused hasWarnedSimpleLayout) and use the import from ./config.
Reviewed changes — Re-reviewed the merge from dev since the last approval, which pulled a stricter client-side security guard into the branch.
- Added strict-layout client security blocking in
packages/nuxt/src/module.ts— the ViteresolveIdplugin now resolves Nuxt aliases (~/,~~/,@/) and blocks userlandenv/server.tsimports on the client when using the strict layout. - Added a module integration test in
packages/nuxt/src/module.test.tscovering alias and relative imports that should be blocked or allowed.
Kimi K2 (free via Pullfrog for OSS) | 𝕏
There was a problem hiding this comment.
✅ No new issues found.
Reviewed changes — Re-reviewed the fixes pushed since the last review. The duplicate normalizeLayout redeclaration in packages/nuxt/src/module.ts was removed, resolving the TypeScript and Biome errors. The playground/example generated env.gen.ts files were also refreshed to the bracketed property access format.
- Removed duplicate
normalizeLayoutfrompackages/nuxt/src/module.tsand kept the import from./config. - Updated generated examples in
apps/playgrounds/nuxt/generated/env.gen.tsandexamples/with-nuxt/generated/env.gen.tsto match the bracketed runtime lookups.
Type-checking and the @arkenv/nuxt test suite now pass.
Kimi K2 (free via Pullfrog for OSS) | 𝕏
|
LGTM |
There was a problem hiding this comment.
Important
The no-codegen refactor is solid, but two cleanup items need to land before merge: the public outputPath option is now dead, and stale generated/env.gen.ts files are still committed.
Reviewed changes — Re-reviewed the commits that removed codegen in favor of a dynamic useRuntimeConfig() proxy.
- Removed
runCodegen,watchSchema, and thecodegen/outputPathoptions from the Nuxt module andconfig.ts. - Added a
mock-imports.tsstub aliased to#importsso build-time validation can safely evaluate schemas that calluseRuntimeConfig(). - Updated
create-env.tsto resolve client values fromruntimeConfig.publicand server values from top-levelruntimeConfig, withprocess.envfallbacks. - Switched dev watching to
nuxt.options.watchand removed thechokidardependency. - Updated docs (
faq.mdx,flat.mdx,strict.mdx,comparison.mdx) and thewith-nuxtexample dependency.
Kimi K2 (free via Pullfrog for OSS) | 𝕏
| * }); | ||
| * ``` | ||
| */ | ||
| outputPath?: string; |
There was a problem hiding this comment.
Remove the stale outputPath option from ArkEnvConfigOptions. Codegen was removed, so setupArkEnv never reads this option; leaving it typed and documented will mislead users and break copy-pasted configs.
Technical details
## Affected sites
- `packages/nuxt/src/config.ts:71-85` — `outputPath` JSDoc and type describe a generated file that is no longer written.
- `packages/nuxt/src/config.ts:109-115` — `setupArkEnv` doc comment still refers to "schema and output files".
## Required outcome
- Delete the `outputPath` property from `ArkEnvConfigOptions`.
- Update the `setupArkEnv` JSDoc to describe only schema-path and validation options.| @@ -0,0 +1,29 @@ | |||
| /* eslint-disable */ | |||
There was a problem hiding this comment.
This file is now stale. The Nuxt integration no longer generates env.gen.ts, and the docs/changeset explicitly say zero files are created. Remove it from the playground and run pnpm sync:examples so the example stays consistent.
| @@ -0,0 +1,29 @@ | |||
| /* eslint-disable */ | |||
There was a problem hiding this comment.
This file is now stale. The Nuxt integration no longer generates env.gen.ts, and the docs/changeset explicitly say zero files are created. Remove it (it will be removed from the example when the playground is re-synced).
| @@ -0,0 +1,6 @@ | |||
| export function useRuntimeConfig(): any { | |||
There was a problem hiding this comment.
The validation stub returns process.env both as public and top-level. Since mock-imports.ts is also built into dist, tighten it to return only what build-time validation needs — e.g. { public: {} } — so it does not double as a full runtime config if the built file is ever resolved directly.
There was a problem hiding this comment.
✅ No new issues found.
Reviewed changes — Re-reviewed the follow-up commits that addressed the prior feedback.
- Removed the stale
outputPathoption fromArkEnvConfigOptionsand its JSDoc example. - Deleted the unused
generated/env.gen.tsfiles from the Nuxt playground and example. - Added module tests for the
validate: truesuccess path and thevalidate: falseskip path. - Updated the strict-layout config-test fixture to import from
@arkenv/nuxt/clientinstead of the removed generated factory.
All 26 @arkenv/nuxt tests and the package typecheck pass.
Kimi K2 (free via Pullfrog for OSS) | 𝕏

Summary
Resolves #1246 (and supersedes the original codegen approach for Nuxt).
What changed
The
@arkenv/nuxtmodule has been completely refactored away from static code generation toward a dynamic runtime proxy that reads environment variables natively from Nuxt'suseRuntimeConfig().Removed
runCodegen/generateFactoryCode/generateRuntimeEnvLines— no moreenv.gen.tsfile writeswatchSchema/chokidardependency — replaced by pushing schema paths intonuxt.options.watch(Nuxt's own native watcher)outputPathandcodegenoptions fromModuleOptions/ArkEnvConfigOptionsAdded / changed
mock-imports.ts— a lightweightuseRuntimeConfig()stub (returns{ public: process.env, ...process.env }) used by Jiti during build-time schema evaluation and by Vitest testscreate-env.ts—createSecurityProxynow importsuseRuntimeConfigfrom#importsand calls it lazily (inside the getter) so the Nuxt instance is always hydrated before access; client keys are read fromruntimeConfig.public, server keys from the top-levelruntimeConfigtsdown.config.ts—#importsandnuxt/appadded toneverBundleso the bundler externalises the virtual Nuxt aliasconfig.ts—"#imports": mockImportsPathadded to Jiti aliases invalidateSchemaso build-time validation can safely call through touseRuntimeConfig()module.ts— schema files pushed intonuxt.options.watch; validate-only flow at startup, no file writesWhy no codegen in Nuxt
Next.js requires codegen because webpack needs to physically see
process.env.NEXT_PUBLIC_Xin source at bundle time to inline it. Nuxt resolves public variables dynamically at runtime via itsuseRuntimeConfig()payload — there is nothing to statically compile. The entire generatedruntimeEnvblock was pure boilerplate; replacing it with a runtime proxy is both architecturally cleaner and eliminates a class of stale-file bugs.Docs
faq.mdx— new Q: "Does@arkenv/nuxtgenerate any files?" (answer: no)flat.mdx/strict.mdx— "Register module" step updated to reflect dynamic resolutioncomparison.mdx— T3 Env comparison updated to distinguish Next.js (codegen) from Nuxt (dynamic)Tests
All 24
@arkenv/nuxttests pass (src/module.test.ts,src/config.test.ts,src/index.test.ts,src/validation.test.ts).