storyblok / storyblok-react

React SDK for Storyblok CMS
118 stars 36 forks source link

"You are not in Draft Mode or in the Visual Editor" #156

Closed wiledal closed 1 year ago

wiledal commented 2 years ago
Screenshot 2022-07-27 at 15 48 18

What's the point of this warning? Looking at the code, it just checks that the window.location === window.parent.location. I don't care if we are not in "Draft mode", the page should display in any case.

This warning is cluttering up our console in both development and production environments.

Are you suggesting we should not use useStoryblokState if outside the visual editor? It's not smooth to make React hooks conditional.

fgiuliani commented 2 years ago

Hi @wiledal! Thanks for your comment.

The idea of the message is not loading the Storyblok Bridge if you are outside the Visual Editor, or working with the Published Mode.

useStoryblokState has a preview parameter, where you can define if you are in a preview environment or not: https://github.com/storyblok/storyblok-react/blob/feature/v1/lib/index.ts#L56

Does this work for you?

wiledal commented 2 years ago

Hey, @fgiuliani, thanks for your reply.

I suppose using that parameter will suppress the message in production, but it still clutters our dev environments. Looking at the code, I'm under the impression that this message shows every time it does not load the bridge.

~I'm happy that the bridge isn't loaded, that seems to work fine, but I wish it wouldn't spam my console :)~

fgiuliani commented 2 years ago

Hey @wiledal thanks for your message. The code that is triggering the warning is in @storyblok/js, a dependency of this package:

https://github.com/storyblok/storyblok-js/blob/3932d6eaa5dd04892ceb4a75962a1552cbce8f38/lib/modules/bridge.ts#L10

Are you setting bridge: false in the storyblokInit function when you are outside of the Visual Editor?

wiledal commented 2 years ago

Hmm, our init function happens outside of the React context, naturally, as it is used by both serverside and clientside operations, and we are unaware of the preview state at the moment of initiation, since the preview state (version: 'draft') is handled during the fetch with storyblokApi.

~I suppose we can do storyblokInit({bridge: false}), and then call useStoryblokBridge() at a later stage, when we know we want it -- however that means we'd need to detect the editor manually which you are clearly already doing, hence the warning.~

(Also, why is useStoryblokBridge named that way, it's not a React hook. Seems like the naming conventions are a bit scattered. ~A name like storyblokBridgeInit would follow the same pattern as your other methods and not interfere with React standards)~

Edit: useStoryblokBridge apparently does not initiate the bridge...

It makes more sense to me that the bridge would not initiate automatically if it cannot be utilised.

wiledal commented 2 years ago

From the documention of @storyblok/js:

Screenshot 2022-07-28 at 08 58 21

This sentence does not make complete sense in the Storyblok context. You'd most likely never want to "disable the bridge in production". Since Storyblok is a headless CMS, meaning you'd want to preview content on any environment, which includes production, staging, local environments.

The only reason why the bridge would be unwanted is if it does not do anything and only adds to the kb budget.

It's still unclear to me how we can avoid boilerplate gymnastics in order to get the desired effect:

~I guess we'll have to make a lazy api-getter function that initiates Storyblok late which also uses a method (probably the same method as you do in storyblok-js) to check for the possible editor-scenario.~

wiledal commented 2 years ago

Ok, the answer was quite simple. Use the same check as the library does for displaying the warning message, and apply it to the bridge parameter.

const shouldUseBridge =
  typeof window !== 'undefined'
    ? window.location !== window.parent.location
    : false

export const storyblok = storyblokInit({
  accessToken: process.env.NEXT_PUBLIC_STORYBLOK_ACCESS_TOKEN,
  bridge: shouldUseBridge,
  use: [apiPlugin],
})

export const storyblokApi = getStoryblokApi()

This seems to work alright.

Edit: OKAY, so storyblokInit in @storyblok/react is not the same as storyblokInit in @storyblok/js, so it actually returns nothing.

wiledal commented 2 years ago

Are you setting bridge: false in the storyblokInit function when you are outside of the Visual Editor?

Please provide examples of how this is supposed to be achieved in the documentation 👆😄 (or better yet, make the library do this automatically and let us override the setting if anyone should ever want to)

wiledal commented 2 years ago
Screenshot 2022-07-28 at 10 50 06

Nevermind, now this happens. ☝️

bridge: true - ⚠️ You are not in the editor! bridge: false - 🚫 The bridge is not enabled!

Assuming this is because we are using useStoryblokState?

It would make sense that useStoryblokState would just act as an immutable useState proxy if the bridge isn't enabled, or we are not in the editor. Again, due to the nature of React, it's quite cumbersome to make hooks conditional.

In the ideal scenario we would just initiate Storyblok, have the bridge load if we are in the editor, and have the state update if it's triggered.

wiledal commented 2 years ago

Unfortunately both @storyblok/js and @storyblok/react are inadequate for use to me in their current state due to their limited bridge loading capabilities.

The only way I can see this working is by rolling your own bridge loader, and your own state manager for editor events.

This was how we had it before using the old storyblok-js-client. I was hoping that these new libraries would alleviate some of the boilerplate, but the current state does not solve anything, and just adds sugar for component rendering, which I won't be using in any of my advanced apps anyways.

The docs in this library suggest you can use new window.StoryblokBridge(), but we cannot be certain that the script is loaded, and the docs do not specify a way of listening for that event.


Here's how I ended up solving it:

  1. Check for "editor like"-conditions using window.location, load the bridge, and initiate a single instance
  2. In my page component, listen to the bridge loading, then bind the events (currently there is no way to unbind events in the bridge (https://github.com/storyblok/storyblok-js/issues/99), which is also a problem for React as all effects should be symmetrical)
Screenshot 2022-07-28 at 12 36 31 Screenshot 2022-07-28 at 12 52 20

Since we cannot unbind events, we cannot re-bind the events on page change, therefore we cannot verify that the updated page corresponds to the current content being updated. I'd say that's a blocking issue on advanced pages with multiple editable stories visible at the same time. And it's not an unlikely scenario at all.

sendy34 commented 2 years ago

thanks @wiledal this solution works great!

fgiuliani commented 2 years ago

Hey @wiledal @sendy34 thanks for your input, for testing the SDK, working with it, and providing feedback about it. We, Storyblok's DevRel team, are willing to improve the SDKs and the tools provided to the developers, and the community feedback is super helpful and more than welcome.

Do you think your code and ideas can be included in the SDK? So it can support more custom scenarios and make the work easier for the developers. Pull Requests are more than welcome, and Storyblok's DevRel team will appreciate that.

wiledal commented 2 years ago

Hey @fgiuliani,

For sure, I could contribute, but seeing as these issues stretch across 2 open source and 1 closed source project, it's a bit of a hassle.

Turns out this package didn't actually provide anything useful to me, so I'm back to using @storyblok/js with a custom bridge loader.

There are a few problems:


In order for us to use Storyblok in an SSR Next.js setup, we:

fgiuliani commented 2 years ago

Thank you for the insights @wiledal. If you can share some code on how you are solving your scenario, with the steps you described in the message above, that would be super helpful to see how we can improve the React SDK and other SDKs we maintain at Storyblok.

Pandan commented 1 year ago

Any progress/updates on the issues @wiledal are describing? I am also experiencing the problem with useStoryblokState when bridge is disabled.
Also getting warnings in the visual editor, saying "Story ID is not defined. ..."

As @wiledal is saying, the desired solution would be to just initiate Storyblok and have everything taken care of.

samlof commented 1 year ago

Very annoying that disabling storyblok bridge causes an error and enabling it prints a warning. At the very least an explicit bridge: false should not print an error that bridge is disabled

fgiuliani commented 1 year ago

Hello @Pandan @samlof useStoryblokState has a parameter called preview: https://github.com/storyblok/storyblok-react/blob/main/lib/index.ts#L62

If you set it to false, you shouldn't get the warning outside of the Visual Editor:

  let sbParams = {
    version: "draft",
  };

  story = useStoryblokState(story, sbParams, false);

Can you confirm that's what you are doing? Or what's exactly the issue you are having?

fgiuliani commented 1 year ago

Hello everyone, We just released Storyblok React SDK v2.0.0: https://github.com/storyblok/storyblok-react/releases/tag/v2.0.0

With this PR we're removing the axios dependency. You don't need to install it anymore in order to use the Storyblok React SDK. We are also adding other changes and fixes: https://github.com/storyblok/storyblok-react/pull/345

Your feedback is appreciated

konsti commented 1 year ago

This is still not working in the newest version if this library. You also removed the preview parameter of useStoryblokState. Any advice?

fgiuliani commented 1 year ago

Hi @konsti thanks for your feedback. Can you share with us some steps to reproduce the issue you are having?

We're working on updating the docs about having removed the preview parameter. The idea is basically enabling or disabling the preview based on the value of the bridge parameter sent when initializing the Storyblok connection using storyblokInit https://github.com/storyblok/storyblok-react#initialization