Skip to content

Conversation

@maoberlehner
Copy link
Contributor

@maoberlehner maoberlehner commented Jan 13, 2026

Upgrade Nuxt-related dependencies to v4 and declare Nuxt 3/4
compatibility in the module meta so the package can be used in Nuxt 4
projects. Adjust the async Storyblok composable to detect the visual
editor via route query and enable deep fetching to keep editor updates
working correctly, and update playground configs accordingly for the new
major version.

Fixes WDX-140
Fixes WDX-62
Fixes #210


Note

Nuxt 4 compatibility and editor behavior

  • Upgrade nuxt, @nuxt/kit, and @nuxt/schema to v4 in packages/nuxt and playgrounds; update playground package.json files to use Nuxt v4
  • Declare Nuxt compatibility (^3.0.0 || ^4.0.0) in module meta and fix auto-import path to runtime/composables/useAsyncStoryblok.ts
  • Enhance useAsyncStoryblok to read useRoute and detect Storyblok visual editor via _storyblok_tk[token], enabling deep: true in useAsyncData when active to preserve live updates
  • Adjust playground nuxt.config.ts (enableServerClient: false) and minor config updates for the new major version

Written by Cursor Bugbot for commit 697328d. This will update automatically on new commits. Configure here.

Upgrade Nuxt-related dependencies to v4 and declare Nuxt 3/4
compatibility in the module meta so the package can be used in Nuxt 4
projects. Adjust the async Storyblok composable to detect the visual
editor via route query and enable deep fetching to keep editor updates
working correctly, and update playground configs accordingly for the new
major version.

Fixes WDX-140
Fixes WDX-62
Fixes #210
Ensure Nuxt auto-imports the composable from the .ts source to avoid
duplicated imports and related runtime issues

Fixes #331
Fixes WDX-166
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR upgrades the Nuxt integration to support Nuxt 4 while maintaining backward compatibility with Nuxt 3. The changes update dependencies to v4, declare compatibility in the module metadata, and fix visual editor behavior by detecting the editor mode via route query parameters and enabling deep fetching for proper reactivity.

Changes:

  • Upgraded Nuxt dependencies from v3 to v4 across package.json files
  • Added Nuxt 3/4 compatibility declaration in module metadata
  • Enhanced useAsyncStoryblok to detect visual editor mode and enable deep fetching

Reviewed changes

Copilot reviewed 6 out of 7 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
packages/nuxt/src/runtime/composables/useAsyncStoryblok.ts Added visual editor detection via route query and conditional deep fetching
packages/nuxt/src/module.ts Declared Nuxt 3/4 compatibility and corrected file extension in import path
packages/nuxt/playground/package.json Updated Nuxt dependency from v3 to v4
packages/nuxt/playground/nuxt.config.ts Disabled enableServerClient for Nuxt 4 compatibility
packages/nuxt/playground-e2e/package.json Updated Nuxt dependency from v3 to v4
packages/nuxt/package.json Updated @nuxt/kit, @nuxt/schema, and nuxt dependencies to v4

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

const { api, bridge, ...rest } = options;
const uniqueKey = `${stableStringify(api)}${url}`;
const route = useRoute();
const isInVisualEditor = Boolean(route.query?.['_storyblok_tk[token]']);
Copy link

Copilot AI Jan 13, 2026

Choose a reason for hiding this comment

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

The query parameter key '_storyblok_tk[token]' contains bracket notation which may not match the actual query parameter structure. Query parameters are typically parsed into nested objects, so this should likely be route.query?._storyblok_tk?.token instead. Verify the actual structure of the query parameter in the visual editor URL.

Copilot uses AI. Check for mistakes.
() => storyblokApiInstance.get(`cdn/stories/${url}`, api),
{
...rest,
deep: isInVisualEditor ? true : undefined,
Copy link

Copilot AI Jan 13, 2026

Choose a reason for hiding this comment

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

The ternary operator can be simplified. Since deep accepts a boolean value, you can directly assign isInVisualEditor instead of using the ternary with true : undefined.

Suggested change
deep: isInVisualEditor ? true : undefined,
deep: isInVisualEditor,

Copilot uses AI. Check for mistakes.
},
devtools: true,
enableServerClient: true,
enableServerClient: false,
Copy link
Contributor Author

Choose a reason for hiding this comment

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

@alexjoverm when this is true, I get the following error (on main too!) when I run pnpm nx dev:https @storyblok/playground-nuxt and open the page https://localhost:3000:

ERROR  You can't use useStoryblokApi if you're not loading apiPlugin. Please provide it on StoryblokVue initialization.

Copy link
Contributor

Choose a reason for hiding this comment

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

Yep, that's by design. When enabling server client, you're not supposed to use useAsyncStoryblok anymore

https://www.storyblok.com/mp/better-nitro-support-improved-security-nuxt-sdk

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Makes sense, but this means we have to disable it in the playground (like I did here) correct?

Copy link

@cursor cursor bot left a comment

Choose a reason for hiding this comment

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

This is the final PR Bugbot will review for you during this billing cycle

Your free Bugbot reviews will reset on February 1

Details

Your team is on the Bugbot Free tier. On this plan, Bugbot will review limited PRs each billing cycle for each member of your team.

To receive Bugbot reviews on all of your PRs, visit the Cursor dashboard to activate Pro and start your 14-day free trial.

{
...rest,
deep: isInVisualEditor ? true : undefined,
},
Copy link

Choose a reason for hiding this comment

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

User-provided deep option is silently overwritten

Low Severity

The deep option from rest (which contains user-provided AsyncDataOptions) is unconditionally overwritten. When isInVisualEditor is false, deep is set to undefined, which discards any explicit deep: true or deep: false the user may have passed in options. The intended behavior to force deep: true in the visual editor is correct, but the fallback case loses user preferences instead of preserving them via rest.deep.

Fix in Cursor Fix in Web

name: 'useAsyncStoryblok',
as: 'useAsyncStoryblok',
from: resolver.resolve('runtime/composables/useAsyncStoryblok'),
from: resolver.resolve('runtime/composables/useAsyncStoryblok.ts'),
Copy link

Choose a reason for hiding this comment

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

Explicit .ts extension inconsistent with other resolver paths

Medium Severity

The resolver.resolve() call for useAsyncStoryblok now includes an explicit .ts extension, while all other resolver calls in the same file (lines 50, 53, 66, 71) omit file extensions. When the module is built with nuxt-module-build, TypeScript files are compiled to .mjs, but this path would still resolve to .ts. This inconsistency could cause import resolution failures in the published package since the .ts file won't exist in the dist folder.

Fix in Cursor Fix in Web

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.

🐛 [Bug]: Bridge in useAsyncStoryblok is not working

2 participants