Create a Preview Environment for Your Nuxt 3 Website
Storyblok is the first headless CMS that works for developers & marketers alike.
This tutorial will explore deploying our Nuxt website on Netlify using two different approaches. First, as a static site, taking full advantage of the Jamstack approach and Nuxt 3, seeing how to generate a preview for our web by creating a Nuxt plugin to refresh the content, enabling live editing on our statically deployed environment. Then, we will see a different approach with a separate deployment for our preview and production environments to make it more optimized and efficient (recommended).
If you’re in a hurry, you can explore or fork the code from the Nuxt Ultimate Tutorial GitHub Repository.
Requirements
This is the last part of the Ultimate Tutorial Guide for Nuxt. The previous part shows how to add and manage multiple languages in Storyblok and Nuxt. Check out the previews parts!
We will use the code from the previous tutorial as a starting point. You can find it in this StackBlitz.
1st Approach: Full Static with Preview Mode
Nuxt 3 has the possibility to deploy a pre-rendered application using Static Site Generation (SSG) with ssr: true. By running the command nuxi generate Nitro will pre-render the routes of our application at build time. Check Static Hosting in the official Nuxt 3 docs for more details.
Let’s prepare our project to use this rendering method while being able to preview changes in our Headless CMS.
For this workaround, we will only need the Storyblok Preview Access Token.
Adding Preview Mode
In Nuxt 3, to refresh the static content on a page when we are editing inside the Storyblok Visual Editor, or showcasing the draft
content to an external reviewer, we shall set up a plugin. This preview plugin will allow retrieving the draft
content while keeping the published
version at build time, bypassing the Static Site Generation.
This workaround was inspired by the suggestion of Jonathan Doelan at Nuxt 3 Preview mode discussion.
Inside the plugins
folder, add a preview.js
file with the following code:
This plugin checks if the website is rendered inside Storyblok by reading the query parameter _storyblok
(line 3). If it’s present and the page has finished loading, it will automatically re-fetch the data, even if it is static (line 5).
Having added the preview mode, let's now configure the content versions to work accordingly.
Loading the Draft Version only in Preview Mode
Once we add the preview mode, we can use $preview
, available inside useNuxtApp()
, to fetch different versions of data: draft
for the preview mode and published
otherwise.
The Preview Access Token has access to both types of content draft
and published
.
Replace the code inside [...slug].vue
with the following:
Here, we are using the $preview
parameter from useNuxtApp()
to decide when to fetch the draft
or the published
content by providing the version
parameter to the request (line 7 & 16). As you can see, we are only loading the bridge if $preview
is enabled, to avoid extra code in production (line 26).
In order to rerender the nested components, is important to listen the pending
value coming from the useAsyncData
in the conditional (line 39), otherwise we won’t be able to see the draft
content.
Now, let's deploy the website.
Deployment
We are going to use Netlify for our deployment. If you don't have an account, you can create a new one for free. But of course, feel free to choose any static-friendly provider that you like for the deployment.
Before deploying, let's set up our environment file as well. This is needed because the access token shouldn't be present in the code. For this, create a .env
file in the root of your project, and add the access token: STORYBLOK_ACCESS_TOKEN=<YOUR_ACCESS_TOKEN>
. Then, in your nuxt.config.js
file, update the module with the following code:
Now push the code to a git provider, like Github, and let’s deploy it.
After logging into Netlify, you should land on the dashboard {1} that shows an overview of all the projects you have. We need to create a new project, click on Add new site {2} button in the Sites section, and select Import an existing project {3}.
Then, follow the steps:
- Connect to git provider: GitHub (or equivalent)
- Select repository:
nuxt-ultimate-tutorial
(your frontend repo) - Configure site and deploy: After importing the repo, we will need to configure the commands and variables needed to pre-render our site. Add the
npm run generate
command {1} anddist
as the publish directory {2}. Finally you will need to include the environment variable {3} by clicking the New variable button {4} and adding the respective key and value {5}.
Afterwards, click on deploy, and your website should be built and deployed soon. Once it is deployed, you will see a small screenshot, a random Netlify generated URL and a published green tag.
Congratulations, you just deployed your full-blown multilingual website made with Nuxt 3 and Storyblok.
Adding a preview URL
Now, we can add the URL for our production environment to our Visual Editor. Inside the Visual Editor, click on Change URL {1} and on Add or change preview URLs {2}.
This will take us to the Visual Editor Settings {1}. Here, we will add a new preview URL to our just deployed environment: Nuxt 3 Prod {2}. The preview URL will be https://nuxt-ultimate-tutorial-ssg.netlify.app {3}, but feel free to add the production URL as default, once you’re ready {4}. Then hit the Save button {5}.
You can always customize the Netlify random generated URL or add your own domain.
If we access the newly added preview URL inside the Visual Editor, we will be able to see the dotted lines. Moreover, draft
content instead of published
as in development. This setup will help the content editors do live edits, add new stories, and see the changes in real time without publishing the content to production when accessing the preview URL inside Storyblok.
The deployed URL can also be used as your production URL. When it is being accessed by a website visitor, the preview mode is not enabled, and they will only see the published content.
Although this is a possible solution, we always recommend having two separate environments for Preview and Production, so as not to overload your hosting provider's usage and have a clear separation of concerns. Let's see how this can be done.
2nd Approach: Preview and Production separate environments (recommended)
In an ideal world, it would be great to be able to use the same code but have two different deployments on our trusted hosting, one for previewing changes, and one for the end user.
Luckily, with frameworks like Nuxt, and its versatility to switch from one rendering mode to another, with a couple of environment variables we can control how we want to render the page and, therefore, be able to display draft
or published
content depending on those variables.
For this approach, we will need two tokens, Storyblok Preview & Public Access Token.
Setting up the Preview Mode
In this type of approach we don’t need a client plugin to refresh our static site as we will directly serve a Client Side Rendering (CSR) application for the preview mode.
The only thing we have to do is to create a new environment variable called NUXT_PUBLIC_NODE_ENV
and give it the value preview
. This variable will be the one we will use to load the draft
or published
content and define what kind of rendering we want.
Adding the Rendering method conditional
To build our application as Single Page App (SPA) when the NUXT_PUBLIC_NODE_ENV
doesn’t have the value production
, add this line in nuxt.config.js
:
Loading the draft content in the Preview environment
Now, we need to tell the [...slug].vue
page when to load draft
or published
data. We can do it by using the same environment variable, we just need to add it as part of the public runtimeConfig
in nuxt.config.js
:
Once we have it available, we can override the […slug].vue
with the following code:
Surely you are thinking, it looks quite similar to the previous approach, and it is totally true, we add the same conditionals to load one type of content or another (line 13) and to load or not the bridge (line 28), the difference is that now we use the environment variable to determine which content version should be fetched (line 5).
Deploying the Preview and Production sites
Now that we have modified our code to work in both environments, we only have to deploy the project in Netlify for both cases:
Preview environment
We will need the Preview Access Token and activate the preview
mode.
Prod environment
We will need the Public Access Token, which only have access to published content, and activate the production mode.
To create a Public Access Token, check our FAQ How to retrieve and generate access tokens
Both will use the npm run generate
command {1} and the dist
folder {2}:
For the preview instance, as is CSR it doesn’t matter if you use the npm run build
or npm run generate
command to build your site.
Congratulations!! You have been able to deploy your production site and create an internal only environment to edit your pages and test them beforehand. Don't forget to add the Preview URL in the Settings of your Storyblok Space and you'll be ready for takeoff 🚀
Adding a Build Webhook
Netlify rebuilds and deploys the project automatically when you push any changes to the code, but what about when we publish our pages inside the Visual Editor? Right now, if you make any changes and publish the content, to see them you will need to redeploy the website from Netlify. However, doing this every time, can be annoying. Let's see how we can make this process seamless.
You can trigger webhooks from Storyblok if you want to react inside any other services depending upon the events happening in the space. Storyblok by default gives you the option to add webhooks for a few events. We will take a look at those in a bit.
You can read more in the Storyblok Webhooks docs.
Netlify allows you to create build hooks which can be added to Storyblok for the story events. These build hooks are URLs that allow you to trigger the deployment in Netlify. To generate a build hook, go to the Site configuration {1} of your project and select Build & deploy {2}. If you scroll inside the Continuous deployment section {3}, you will find Build Hooks {4}. You can create a hook there by giving it a name {5} and specifying the branch {6}. Hit Save {7} after filling in the details.
Once the webhook is created, you will get an option to copy the hook's URL. Let's now add it to Storyblok. Go to the Settings {1}, and select Webhooks {2}. This is the place where you can add webhook URLs for Storyblok events. Click on New Webhook {3} to add one.
Add a name for the webhook {1}, and then paste the URL of the Netlify’s build hook in Endpoint URL {2}. You can select the Triggers {3} here for which the webhook should be fired. In this case, we want to rebuild our website whenever something is changed with a Story. Let's select all the Story events {4} and click the Save button {5}.
And that's it, now whenever a story is published, moved, unpublished or deleted, the project will be redeployed and rebuilt again automatically without any extra effort.