Skip to content

feat!: redesign registry config — presence = available, trigger = load#661

Open
harlan-zw wants to merge 2 commits intomainfrom
feat/registry-config-redesign
Open

feat!: redesign registry config — presence = available, trigger = load#661
harlan-zw wants to merge 2 commits intomainfrom
feat/registry-config-redesign

Conversation

@harlan-zw
Copy link
Collaborator

Summary

Redesigns the scripts.registry config API to separate "availability" from "loading":

  • Presence in config = infrastructure (proxy routes, types, bundling, composable auto-imports)
  • trigger = global auto-loading (opt-in, explicit)

This eliminates the proxy-only hack, removes the need for $production wrappers in most cases, and simplifies the mental model.

Before

scripts: {
  registry: {
    googleAnalytics: true,                    // auto-loads globally (implicit)
    googleAnalytics: { id: 'G-xxx' },         // auto-loads globally (implicit)
    googleAnalytics: 'proxy-only',            // hack: infra only
  }
}

After

scripts: {
  registry: {
    googleAnalytics: {},                                          // infra only (env vars)
    googleAnalytics: { id: 'G-xxx' },                            // infra only (explicit config)
    googleAnalytics: { id: 'G-xxx', trigger: 'onNuxtReady' },    // infra + global auto-load
  }
}

Breaking Changes

  • true removed as config value (build error with migration message)
  • 'proxy-only' removed (build error with migration message; infra-only is now the default)
  • Scripts configured without trigger no longer auto-load globally
  • trigger hoisted to top-level of config object alongside script input options
  • Tuple form [input, scriptOptions] still supported internally

Migration

Before After
googleAnalytics: true googleAnalytics: {} or googleAnalytics: { trigger: 'onNuxtReady' }
googleAnalytics: { id: 'G-xxx' } (wanted global load) googleAnalytics: { id: 'G-xxx', trigger: 'onNuxtReady' }
googleAnalytics: { id: 'G-xxx' } (wanted composable only) unchanged
googleAnalytics: 'proxy-only' googleAnalytics: {}
$production: { scripts: { ... } } Usually unnecessary; no trigger = no load

Production-only improvement

Previously required wrapping everything in $production, which disabled types and composables in dev. Now:

// Infra available everywhere (types, proxy, composables work in dev)
scripts: { registry: { googleAnalytics: { id: 'G-xxx' } } },
// Add trigger only in prod
$production: { scripts: { registry: { googleAnalytics: { trigger: 'onNuxtReady' } } } }

Test plan

  • All 435 unit tests pass
  • Verify playground works with {} entries
  • Verify trigger: 'onNuxtReady' generates correct plugin code
  • Verify true and 'proxy-only' throw clear build errors
  • E2E tests (pre-existing tsconfig failure unrelated to this change)

@vercel
Copy link
Contributor

vercel bot commented Mar 20, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
scripts-playground Ready Ready Preview, Comment Mar 20, 2026 1:41pm

@pkg-pr-new
Copy link

pkg-pr-new bot commented Mar 20, 2026

Open in StackBlitz

npm i https://pkg.pr.new/@nuxt/scripts@661

commit: 74c2afa

@harlan-zw harlan-zw marked this pull request as ready for review March 20, 2026 13:26
BREAKING CHANGE: Registry config no longer auto-loads scripts globally.
Adding a script to `scripts.registry` now only sets up infrastructure
(proxy routes, types, bundling, composable auto-imports). Scripts only
auto-load globally when `trigger` is explicitly set.

- `true` removed: use `{}` (infra only) or `{ trigger: 'onNuxtReady' }` (global load)
- `'proxy-only'` removed: infra-only is now the default behavior
- `trigger` hoisted to top-level config alongside script input options
- Tuple form `[input, scriptOptions]` still supported internally

Migration:
- `googleAnalytics: true` → `googleAnalytics: {}` or `googleAnalytics: { trigger: 'onNuxtReady' }`
- `googleAnalytics: { id: 'G-xxx' }` → unchanged (but no longer auto-loads; add `trigger` to auto-load)
- `googleAnalytics: 'proxy-only'` → `googleAnalytics: {}`
@harlan-zw harlan-zw force-pushed the feat/registry-config-redesign branch from e1ee76a to 85c19a4 Compare March 20, 2026 13:28
@coderabbitai
Copy link

coderabbitai bot commented Mar 20, 2026

📝 Walkthrough

Walkthrough

The PR changes the scripts registry shape from boolean (true) and 'proxy-only' forms to object/tuple forms. normalizeRegistryConfig now throws on true/'proxy-only' and normalizes plain object entries into [input] or [input, scriptOptions] tuples when script-related fields exist. Type definitions remove bare true and require object or tuple shapes. Template generation skips composable initialization for entries lacking scriptOptions.trigger. Nuxt config fixtures and tests were updated to use {} entries and to assert trigger-dependent behavior. Minor dev-server path null-safety fix included.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 66.67% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the main redesign: separating registry config presence (infrastructure availability) from trigger-based loading, which aligns with all major changes across the codebase.
Description check ✅ Passed The description is comprehensive and addresses all template requirements. It includes a detailed summary, before/after examples, clear breaking changes, migration guidance, and a test plan with specific verification items.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

Important

Merge conflicts detected (Beta)

  • Resolve merge conflict in branch feat/registry-config-redesign
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/registry-config-redesign
📝 Coding Plan
  • Generate coding plan for human review comments

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
test/fixtures/first-party/nuxt.config.ts (1)

38-38: ⚠️ Potential issue | 🟡 Minor

Inconsistent vercelAnalytics value in runtimeConfig.

Line 38 in runtimeConfig.public.scripts has vercelAnalytics: true, but true is no longer a valid configuration value per this PR. This should be changed to vercelAnalytics: {} for consistency with the registry entry at line 76.

🔧 Proposed fix
-        vercelAnalytics: true,
+        vercelAnalytics: {},
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@test/fixtures/first-party/nuxt.config.ts` at line 38, Update the
runtimeConfig.public.scripts entry for vercelAnalytics to use an object instead
of a boolean: locate runtimeConfig.public.scripts and change the vercelAnalytics
value from true to an empty object (vercelAnalytics: {}) so it matches the
registry format used elsewhere (see the existing registry entry for
vercelAnalytics).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Outside diff comments:
In `@test/fixtures/first-party/nuxt.config.ts`:
- Line 38: Update the runtimeConfig.public.scripts entry for vercelAnalytics to
use an object instead of a boolean: locate runtimeConfig.public.scripts and
change the vercelAnalytics value from true to an empty object (vercelAnalytics:
{}) so it matches the registry format used elsewhere (see the existing registry
entry for vercelAnalytics).

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 3e8ac1e4-8ecb-45b1-96e0-69df230f37fd

📥 Commits

Reviewing files that changed from the base of the PR and between d8378ce and 85c19a4.

📒 Files selected for processing (9)
  • playground/nuxt.config.ts
  • src/module.ts
  • src/normalize.ts
  • src/runtime/types.ts
  • src/templates.ts
  • test/fixtures/basic/nuxt.config.ts
  • test/fixtures/first-party/nuxt.config.ts
  • test/unit/auto-inject.test.ts
  • test/unit/templates.test.ts

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/assets.ts`:
- Line 56: The expression creating cleanPath uses (event.path ||
'').split('?')[0] which TypeScript flags as possibly undefined; update the
assignment in src/assets.ts (the cleanPath declaration) to provide a safe
fallback for the split result before calling .slice(1) — e.g. take the first
element of the split with a nullish/empty-string fallback (so the index access
cannot be undefined) or use destructuring with a default, ensuring the final
value passed to .slice is always a string derived from event.path.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: ef88c5d3-176b-496b-80bb-fcce7b24621b

📥 Commits

Reviewing files that changed from the base of the PR and between 85c19a4 and acdad53.

📒 Files selected for processing (1)
  • src/assets.ts

src/assets.ts Outdated
handler: lazyEventHandler(async () => {
return eventHandler(async (event) => {
const cleanPath = event.path.split('?')[0].slice(1)
const cleanPath = (event.path || '').split('?')[0].slice(1)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

TypeScript error: split('?')[0] may be typed as undefined.

The pipeline is failing with TS2532. While .split() always returns at least one element at runtime, TypeScript's strict array indexing (likely noUncheckedIndexedAccess) treats array[0] as potentially undefined. Add a fallback for the array access.

🔧 Proposed fix
-        const cleanPath = (event.path || '').split('?')[0].slice(1)
+        const cleanPath = ((event.path ?? '').split('?')[0] ?? '').slice(1)
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const cleanPath = (event.path || '').split('?')[0].slice(1)
const cleanPath = ((event.path ?? '').split('?')[0] ?? '').slice(1)
🧰 Tools
🪛 GitHub Actions: Test

[error] 56-56: TypeScript error TS2532: Object is possibly 'undefined'. (reported during 'nuxt typecheck' in 'pnpm typecheck')

🪛 GitHub Check: test

[failure] 56-56:
Object is possibly 'undefined'.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/assets.ts` at line 56, The expression creating cleanPath uses (event.path
|| '').split('?')[0] which TypeScript flags as possibly undefined; update the
assignment in src/assets.ts (the cleanPath declaration) to provide a safe
fallback for the split result before calling .slice(1) — e.g. take the first
element of the split with a nullish/empty-string fallback (so the index access
cannot be undefined) or use destructuring with a default, ensuring the final
value passed to .slice is always a string derived from event.path.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

♻️ Duplicate comments (1)
src/assets.ts (1)

56-56: ⚠️ Potential issue | 🔴 Critical

Fix the remaining TS2532 on cleanPath construction.

At Line 56, event.path! avoids only the nullable path case; split('?')[0] is still typed as possibly undefined with strict indexed access, so .slice(1) keeps typecheck failing.

🔧 Proposed fix
-        const cleanPath = event.path!.split('?')[0].slice(1)
+        const cleanPath = (event.path?.split('?')[0] ?? '').slice(1)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/assets.ts` at line 56, The TS2532 arises because event.path can be
undefined and indexed access split('?')[0] is still considered possibly
undefined; replace the non-null assertion with a safe default so the expression
always yields a string. Change the construction of cleanPath to use a
nullish-coalescing default on event.path (e.g., (event.path ?? '') or
String(event.path)) before calling split and slice so that cleanPath is
calculated from a guaranteed string; update the statement that sets cleanPath
accordingly (referencing cleanPath and event.path in your edit).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Duplicate comments:
In `@src/assets.ts`:
- Line 56: The TS2532 arises because event.path can be undefined and indexed
access split('?')[0] is still considered possibly undefined; replace the
non-null assertion with a safe default so the expression always yields a string.
Change the construction of cleanPath to use a nullish-coalescing default on
event.path (e.g., (event.path ?? '') or String(event.path)) before calling split
and slice so that cleanPath is calculated from a guaranteed string; update the
statement that sets cleanPath accordingly (referencing cleanPath and event.path
in your edit).

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: f0406ca9-c121-4202-a16a-08fb1a5e8ca1

📥 Commits

Reviewing files that changed from the base of the PR and between acdad53 and 74c2afa.

📒 Files selected for processing (1)
  • src/assets.ts

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.

1 participant