Skip to content

fix: improve registry script DX and type safety#647

Merged
harlan-zw merged 3 commits intomainfrom
worktree-dx-type-safety
Mar 18, 2026
Merged

fix: improve registry script DX and type safety#647
harlan-zw merged 3 commits intomainfrom
worktree-dx-type-safety

Conversation

@harlan-zw
Copy link
Collaborator

@harlan-zw harlan-zw commented Mar 18, 2026

🔗 Linked issue

Related to #292

❓ Type of change

  • 📖 Documentation
  • 🐞 Bug fix
  • 👌 Enhancement
  • ✨ New feature
  • 🧹 Chore
  • ⚠️ Breaking change

📚 Description

Registry script composables (useScriptCrisp, etc.) required config options like id even when provided via runtime config / env vars, forcing id: '' as a workaround. Additionally, Object.assign in useRegistryScript caused runtime config to silently overwrite composable args — the wrong merge direction.

This PR makes all schema fields Partial in RegistryScriptInput (runtime valibot validation still catches missing fields in dev), fixes the merge order with defu so composable args take priority, adds false support to registry config for explicitly disabling scripts, and skips disabled entries in template plugin code generation.

Before:

// TS error: 'id' is required
useScriptCrisp({ scriptOptions: { trigger: consent } })

After:

// Works — id comes from NUXT_PUBLIC_SCRIPTS_CRISP_ID
useScriptCrisp({ scriptOptions: { trigger: consent } })

// Explicitly disable a script per-environment
scripts: { registry: { crisp: false } }

- Make all schema fields Partial in RegistryScriptInput so composables
  don't require config when provided via runtime config / env vars
- Drop CanBypassOptions type param (no longer needed)
- Fix merge order: use defu instead of Object.assign so composable
  args take priority over runtime config
- Add false to NuxtConfigScriptRegistryEntry for explicit disable
- Skip false entries in module registry processing
@vercel
Copy link
Contributor

vercel bot commented Mar 18, 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 18, 2026 6:42am

@pkg-pr-new
Copy link

pkg-pr-new bot commented Mar 18, 2026

Open in StackBlitz

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

commit: fa12a3f

@coderabbitai
Copy link

coderabbitai bot commented Mar 18, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 16a0954c-30b5-4978-8861-f5bdb3be41ab

📥 Commits

Reviewing files that changed from the base of the PR and between be71b8c and fa12a3f.

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

📝 Walkthrough

Walkthrough

Adds a guard to skip registry entries explicitly set to false during registry processing. Introduces RegistryScriptInputExtras and simplifies RegistryScriptInput by removing the prior CanBypassOptions generic; expands NuxtConfigScriptRegistryEntry to include false. Updates ~16 registry files to use the new RegistryScriptInput arity. Replaces a shallow Object.assign merge with a deep/defu merge when combining _userOptions and scriptConfig. No other runtime control-flow changes beyond the new false-disabled guard.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% 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 describes the main changes: making registry scripts more user-friendly (DX) and improving type safety by making schema fields partial.
Description check ✅ Passed The description comprehensively covers the linked issue, type of change (bug fix and enhancement), and detailed explanation of the problem and solution with before/after examples.

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

✨ 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 worktree-dx-type-safety
📝 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.

Actionable comments posted: 1

Caution

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

⚠️ Outside diff range comments (1)
src/module.ts (1)

505-512: ⚠️ Potential issue | 🟡 Minor

Add an explicit check to skip false registry entries in templatePlugin.

The function at src/templates.ts:121 iterates over config.registry without filtering disabled entries. When a registry entry value is false, it falls into the else block (line 149) and generates initialization code with empty args (const xyz = useScriptXyz({})). Add a check after line 123 to skip entries where c === false to prevent generating unnecessary code for disabled scripts.

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

In `@src/module.ts` around lines 505 - 512, templatePlugin iterates
config.registry and treats entries with value false as enabled, producing empty
initialization calls; modify templatePlugin to skip registry entries whose value
is strictly false (check the iterated value `c === false`) before the existing
handling so disabled scripts are not emitted (i.e., do not enter the else/init
generation for that entry). Ensure you reference the `templatePlugin` function
and the `config.registry` iteration and skip when `c === false`.
🤖 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/runtime/types.ts`:
- Around line 220-228: Indent the type declaration beginning with "=
Partial<InferIfSchema<T>>" by two spaces to satisfy ESLint; update the leading
whitespace so the "=" line and the following "& {" block are aligned with the
surrounding type definition, and ensure the property lines (key, scriptInput,
scriptOptions) keep their current relative indentation (two spaces inside the
block) so the whole `Partial<InferIfSchema<T>> & { ... }` declaration is
consistently indented in src/runtime/types.ts.

---

Outside diff comments:
In `@src/module.ts`:
- Around line 505-512: templatePlugin iterates config.registry and treats
entries with value false as enabled, producing empty initialization calls;
modify templatePlugin to skip registry entries whose value is strictly false
(check the iterated value `c === false`) before the existing handling so
disabled scripts are not emitted (i.e., do not enter the else/init generation
for that entry). Ensure you reference the `templatePlugin` function and the
`config.registry` iteration and skip when `c === false`.
🪄 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: 9fb12700-f29b-40e4-9289-c688aac02e34

📥 Commits

Reviewing files that changed from the base of the PR and between f3a4b68 and 2d0ff9f.

📒 Files selected for processing (19)
  • src/module.ts
  • src/runtime/registry/bluesky-embed.ts
  • src/runtime/registry/crisp.ts
  • src/runtime/registry/fathom-analytics.ts
  • src/runtime/registry/google-adsense.ts
  • src/runtime/registry/hotjar.ts
  • src/runtime/registry/instagram-embed.ts
  • src/runtime/registry/intercom.ts
  • src/runtime/registry/matomo-analytics.ts
  • src/runtime/registry/meta-pixel.ts
  • src/runtime/registry/npm.ts
  • src/runtime/registry/reddit-pixel.ts
  • src/runtime/registry/snapchat-pixel.ts
  • src/runtime/registry/tiktok-pixel.ts
  • src/runtime/registry/vercel-analytics.ts
  • src/runtime/registry/x-embed.ts
  • src/runtime/registry/x-pixel.ts
  • src/runtime/types.ts
  • src/runtime/utils.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

🧹 Nitpick comments (1)
src/runtime/types.ts (1)

215-222: Extract conditional type to a helper for clarity.

The scriptOptions conditional type is verbose and difficult to parse visually. Extract it to a dedicated helper type with explicit never branches to improve readability and make the intent clearer.

♻️ Proposed refactor
+type RegistryScriptOptionOmittedKeys<Bundelable extends boolean, Usable extends boolean> =
+  (Bundelable extends true ? never : 'bundle')
+  | (Usable extends true ? never : 'use')
+
 export interface RegistryScriptInputExtras<Bundelable extends boolean = true, Usable extends boolean = false> {
   /**
    * A unique key to use for the script, this can be used to load multiple of the same script with different options.
    */
   key?: string
   scriptInput?: ScriptInput
-  scriptOptions?: Omit<NuxtUseScriptOptions, Bundelable extends true ? '' : 'bundle' | Usable extends true ? '' : 'use'>
+  scriptOptions?: Omit<NuxtUseScriptOptions, RegistryScriptOptionOmittedKeys<Bundelable, Usable>>
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/runtime/types.ts` around lines 215 - 222, The conditional in
RegistryScriptInputExtras's scriptOptions (type parameters Bundelable and
Usable) is hard to read; extract that logic into a small named helper type
(e.g., ScriptOptionsFor<Bundelable,Usable>) with explicit branches that use
Omit<NuxtUseScriptOptions, 'bundle' | 'use'> and never where appropriate, then
replace the inline conditional in RegistryScriptInputExtras.scriptOptions with
that helper type to improve clarity while preserving the same semantics;
reference the existing type name RegistryScriptInputExtras and the type
parameters Bundelable and Usable when implementing the helper.
🤖 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/runtime/types.ts`:
- Line 199: The template code is still treating entries typed as
NuxtConfigScriptRegistryEntry<T> with the `false` variant as if they were
present (initializing them to {}), violating the “explicitly disable script”
semantics; locate the initialization logic in src/templates.ts that maps or
reduces the script registry (the function that builds/initializes the script
registry entries—look for names like initScriptRegistry, buildScriptEntries, or
the loop that handles registry values) and change it to skip any entry whose
value is strictly === false (do not create an empty object or default entry), so
disabled entries are omitted from the emitted template while leaving handling
for true, 'mock', T, and [T, NuxtUseScriptOptionsSerializable] unchanged.

---

Nitpick comments:
In `@src/runtime/types.ts`:
- Around line 215-222: The conditional in RegistryScriptInputExtras's
scriptOptions (type parameters Bundelable and Usable) is hard to read; extract
that logic into a small named helper type (e.g.,
ScriptOptionsFor<Bundelable,Usable>) with explicit branches that use
Omit<NuxtUseScriptOptions, 'bundle' | 'use'> and never where appropriate, then
replace the inline conditional in RegistryScriptInputExtras.scriptOptions with
that helper type to improve clarity while preserving the same semantics;
reference the existing type name RegistryScriptInputExtras and the type
parameters Bundelable and Usable when implementing the helper.
🪄 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: 6f043e3c-074b-49f2-baa9-4a2e4abdf32b

📥 Commits

Reviewing files that changed from the base of the PR and between 2d0ff9f and be71b8c.

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

@harlan-zw harlan-zw merged commit 32ff4fa into main Mar 18, 2026
10 checks passed
@harlan-zw harlan-zw deleted the worktree-dx-type-safety branch March 18, 2026 06:48
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