Storyblok Multi Branch Preview Environment for Static Websites in Nuxt 3

Storyblok
Nuxt
May 27, 2023

Creating a preview environment for a static Nuxt website with Storyblok can be a challenging task. However, in this post, we will guide you through the process of setting up a multi branch preview environment that seamlessly integrates with your Storyblok-powered static website.

This post assumes that you have a basic understanding of the common concepts associated with Storyblok and its visual editor. However, if you are new to Storyblok or unfamiliar with these concepts, don't worry. You can refer to the following resources to familiarize yourself:

Concept

The strategy we're using to tackle this challenge involves using two separate branches within your website’s repository: the "master" branch and the "preview" branch.

Theoretically, it is possible to create a preview environment using a single branch. However, to do this, the preview token needs to be included in the client. As a result, it is advisable to utilize two separate branches to implement this approach effectively to not expose your preview token to the public.

Master Branch

This is the primary branch of your project. It contains the static and published version of your website. The master branch will be generated and deployed without the Storyblok preview token and without Storyblok Bridge. I will explain the advantages and reasons in a moment.

Preview Branch

This branch serves the exclusive purpose of previewing changes from Storyblok. It operates in SPA (Single Page Application) mode and contains the Storyblok preview token. By leveraging this mode, you can take advantage of faster build times as there is no requirement to pre-render the pages.

Benefits

Embracing this dual-branch strategy offers a host of benefits:

  1. Distinct Environment Separation: With the master and preview branches distinctly separated, you can easily deploy the preview version to a subdomain, maintaining an organized and clutter-free workspace. This clear separation helps streamline your workflow and reduces potential errors.

  2. GDPR Compliant master Branch: By excluding the Storyblok Bridge script from the master branch, you ensure GDPR compliance. When Storyblok Bridge is enabled, the script is fetched from Storyblok. No third-party scripts are allowed to be loaded in Europe without user consent.

  3. Enhanced Performance on master Branch: As the Storyblok Bridge script isn't loaded or executed on the master branch, you enjoy improved performance for your static site. This strategy can lead to faster page load times and a more seamless user experience, which can positively impact SEO.

  4. Secure Preview Environment: You can protect your preview environment with additional security measures, such as password protection or IP whitelisting. This feature ensures that your previews can only be viewed by authorized people.

Environment variables

Before we start, we need to add the public and preview tokens to the environment variables. Add the following variables to your .env file:

.env
STORYBLOK_PUBLIC_TOKEN=tobemodified
STORYBLOK_PREVIEW_TOKEN=tobemodified

Replace the placeholder "tobemodified" with the actual tokens from your Storyblok Space. To find your tokens, go to the settings and navigate to the Access Tokens menu. There, you will be able to see and retrieve your specific tokens.

Storyblok Access Tokens

Master Branch

When working on the master branch, we typically utilize the preview token for development purposes. However, it is important to restrict the visibility of the preview token solely to the development environment. Also, make sure you disable Storyblok Bridge to prevent the script from loading.

To achieve this, you can apply the following Nuxt configuration settings:

TypeScript
nuxt.config.ts
export default defineNuxtConfig({
  modules: [
    [
      '@storyblok/nuxt',
      {
        accessToken: 
          process.env.NODE_ENV === 'development'
            ? process.env.STORYBLOK_PREVIEW_TOKEN
            : process.env.STORYBLOK_PUBLIC_TOKEN,
        bridge: false,
      },
    ],
  ],
});

It's crucial to take the version into account when fetching data. During development, it's preferable to retrieve drafts, while in production, fetching published content is desired.

Vue
index.vue
<script setup lang="ts">
  const { data: story } = await useAsyncData('homepage', async () => {
    const storyblokApi = useStoryblokApi();
    const res = await storyblokApi.get('cdn/stories/homepage', {
      version: process.env.NODE_ENV === 'development' 
        ? 'draft'
        : 'published',
    });
    return res.data.story;
  });
</script>

Now the configuration for the master branch is complete.

Preview Branch

In the next step, we will create a new branch called preview that branches off from the master branch. Since this branch is specifically dedicated to the preview functionality, we can directly utilize the preview token.

It's important to ensure that the bridge is also activated in this branch, as the bridge serves the purpose of connecting the client with the Storyblok visual editor.

As explained in the concept, we will switch to SPA mode in this Branch. Therefore, we deactivate SSR (Server Side Rendering).

TypeScript
nuxt.config.ts
export default defineNuxtConfig({
  ssr: false,
  modules: [
    [
      '@storyblok/nuxt',
      {
        accessToken: process.env.STORYBLOK_PREVIEW_TOKEN
        bridge: true,
      },
    ],
  ],
});

In this branch, for data fetching, we can consistently set the version to 'draft'. Additionally, it is necessary to initialize the Storyblok Bridge in case we are in preview mode.

Vue
index.vue
<script setup lang="ts">
  const { data: story } = await useAsyncData('homepage', async () => {
    const storyblokApi = useStoryblokApi();
    const res = await storyblokApi.get('cdn/stories/homepage', {
      version: 'draft',
    });
    return res.data.story;
  });

  function initStoryblokBridge() {
    if (!route.query._storyblok || !story.value) return;
    useStoryblokBridge(story.value.id, (evStory) => (story.value = evStory));
  }

  onMounted(() => {
    initStoryblokBridge();
  });
</script>

For instance, you can deploy this branch on the subdomain preview.my-domain.com, while keeping the master branch hosted on the main domain.

Do not forget to change the preview URL in Storyblok settings to the website from the preview branch.