storyblok / storyblok-react

React SDK for Storyblok CMS
MIT License
122 stars 37 forks source link

Storyblokinit bridge option change and preview context #414

Closed pedrosousa13 closed 1 year ago

pedrosousa13 commented 1 year ago

Expected Behavior

We would like to control the loading of the bridge by getting the context.preview in nextjs. Before we were checking for context.preview in the useStoryblokState. with the new v2 of @storyblok/react we can't do so anymore.

We are initializing like so in _app.tsx:

storyblokInit({
  accessToken: process.env.NEXT_PUBLIC_STORYBLOK_ACCESS_TOKEN,
  use: [apiPlugin],
  components: allComponents,
  bridge: true, // We want to control this
});

Current Behavior

it's outside the component so it has no concept of context at this point. Is there a workaround to allow bridge to be controlled via context again?

fgiuliani commented 1 year ago

Hi @pedrosousa13 thanks for creating this issue. We're actually working on looking for a proper solution for that scenario. We removed the preview param of the useStoryblokState hook since we thought it was redundant/repetitive with the bridge parameter used in storyblokInit. Any idea or suggestion is welcome.

cc @arorachakit @alexjoverm

pedrosousa13 commented 1 year ago

I'm currently working on a solution, I might try to refactor everything in storyblokInit to react context. I think following the react way is best here.

Another quick option, that I'm not sure would work for everything would be to use the global Objects prop. Like Prisma here: https://www.prisma.io/docs/guides/database/troubleshooting-orm/help-articles/nextjs-prisma-client-dev-practices#solution

fgiuliani commented 1 year ago

Hey @pedrosousa13 thanks for sharing your updates and ideas! Happy to discuss any proposal or recommended approach you have 😄

alexjoverm commented 1 year ago

Hi there @pedrosousa13 looking forward to see what you find out!

Also FYI - we're planning to add a feature about loading the bridge 100% automatically only when is in the visual editor, as a default. That should fix this issue with no effort from your side ;)

alexjoverm commented 1 year ago

Wait, I'm wrong about my previous comment. Still being able to have the token set dynamically is required. I mean, we have 2 type of tokens:

Thing here is to figure out how to dynamically choose one token and the other depending if you're in preview mode or not. Of course this condition shouldn't be in the app code, otherwise both tokens will end up in the code. Should somehow come from the server and be universal (work on server + client).

Any ideas @pedrosousa13 ?

fgiuliani commented 1 year ago

Adding some details:

arorachakit commented 1 year ago

Hey @pedrosousa13 ! It seems a bit difficult to switch the token or get context inside storyblokInit function with the implementation we have for the reasons you already mentioned. From now on we will be working on making it work with the new Next.js 13 app directory. As the preview mode is legacy now, we will be making solutions around using the new draft mode.

Though from an overview, I am not yet sure if we will be able to achieve (get context to disable to bridge and switch token) it even with that. My recommendation for now would be to use two different deployments, one with public token and disabled bridge, and the other one with preview token that enables the bridge and uses the draft content along with preview mode.

I see that you were working on a solution, please let me know if you have any ideas. All ideas and suggestions are welcomed :)

pedrosousa13 commented 1 year ago

Thank you @arorachakit . For now we have a solution. It does make sense to start work on app router. We're internally experimenting with it and will phase out legacy preview as you said :).

fgiuliani commented 1 year ago

Hi @pedrosousa13! Just out of curiosity: What solution did you find? :)

pedrosousa13 commented 1 year ago

@fgiuliani nothing good honestly. I just re-did the storyblok client implementation to have access to all the data. It's not pretty :)

import {
  storyblokInit as sbInit,
} from '@storyblok/js';
import { apiPlugin, storyblokInit as sBStoryblokInit } from '@storyblok/react';
import { allComponents } from '@/components/component-list';

let storyblokApiInstance;

export const storyblokInit = ({ preview = false }) => {
  const { storyblokApi } = sbInit({
    accessToken: process.env.NEXT_PUBLIC_STORYBLOK_ACCESS_TOKEN,
    use: [apiPlugin],
    bridge: preview,
  });

  // Initialise components here. Can't initialise myself without refactoring <StoryblokComponent>
  sBStoryblokInit({
    components: allComponents,
    bridge: false,
  });

  storyblokApiInstance = storyblokApi;
};

export const useStoryblokApi = () => {

  if (!storyblokApiInstance) {
    storyblokInit({});
  }

  return storyblokApiInstance;
};

export { useStoryblokApi as getStoryblokApi };
pedrosousa13 commented 1 year ago

Feel free to close this issue since you're working on a new solution anyhow 😄 .

fgiuliani commented 1 year ago

Thank you @pedrosousa13!