Using Prismic with Nuxt.js
This article discusses how to use Prismic with Nuxt.js and how it's different than standard Vue.js. Migrating an old Prismic & Nuxt project? You can read how to do that here.
Nuxt.js is a hugely popular solution within in the Vue.js community when it comes to creating server side rendered or statically deployed applications.
This community project is built on top of the Vue ecosystem and handles all aspects of a production-ready server side rendered app. Here's a link to learn more about Nuxt.js.
With the help of James Pegg and the team at Nuxt.js we worked to create a plugin that makes creating Nuxt.js apps with Prismic a breeze.
The first thing to do is install the @nuxtjs/prismic module.
npm i @nuxtjs/prismic
Make sure you're using at least Nuxt 2.11.0
npm upgrade nuxt
This file is where all the settings and configuration for the @nuxtjs/prismic module for your project will go.
The @nuxtjs/prismic plugin
Read a full reference of the @nuxtjs/prismic plugin configuration.
Modules
Include Prismic in your modules like so:
{
modules: [
'@nuxtjs/prismic'
],
prismic: {
endpoint: "https://your-repo-name.cdn.prismic.io/api/v2",
linkResolver: //path-to-html-serializer
htmlSerializer: //path-to-html-serializer
},
generate: {
fallback: "404.html"
}
}
modules
This is where you add the plugin: @nuxtjs/prismic
prismic
This is where you add your settings in regards to Prismic
prismic.endpoint
This is where you define the link to your Prismic API to get all your content. You'll find your endpoint in your repo settings under the 'API & Security' tab.
prismic.linkResolver
Here you can either add directly or import your link resolver for your project. Learn more about the Link resolver.
prismic.htmlSerializer
Again here you can either add directly or import your custom HTML serializer. Learn more about the HTML serializer.
Generate
This small setting is for deploying sites statically on Netlify. This fallback will allow the 404 page to be loaded like a SPA so that previewing unpublished articles will function correctly.
Below is a full example of how this file should look.
export default {
mode: 'universal',
/*
** Headers of the page
*/
head: {
title: 'Prismic + Nuxt Blog example',
meta: [
{ charset: 'utf-8' },
{ name: 'viewport', content: 'width=device-width, initial-scale=1' },
{ hid: 'description', name: 'description', content: 'Prismic + Nuxt Blog example' }
],
link: [
{ rel: 'icon', type: 'image/x-icon', href: '/favicon.ico' },
{ rel: 'stylesheet', href: 'https://fonts.googleapis.com/css?family=Lato:300,400,700,900' }
]
},
/*
** Customize the progress-bar color
*/
loading: { color: '#fff' },
/*
** Global CSS
*/
css: [
'@/assets/css/resetr.css',
'@/assets/css/common.css'
],
/*
** Plugins to load before mounting the App
*/
plugins: [
],
/*
** Nuxt.js modules
*/
modules: [
// This is where you import the plugin
'@nuxtjs/prismic'
],
// This is where you configure your settings for the new plugin
prismic: {
endpoint: 'https://your-repo-name.cdn.prismic.io/api/v2',
linkResolver: '@/plugins/link-resolver',
htmlSerializer: '@/plugins/html-serializer',
},
/*
** Build configuration
*/
build: {
/*
** You can extend webpack config here
*/
extend(config, ctx) {
config.resolve.alias['vue'] = 'vue/dist/vue.common'
}
},
// Netlify reads a 404.html, Nuxt will load as an SPA
generate: {
fallback: '404.html'
}
}
One difference here between Nuxt and Vue is wrapping links from your rich text fields in the <nuxt-link> tag. Below is what a full HTML serializer for a Nuxt.js project should look like.
import linkResolver from "./link-resolver"
import prismicDOM from 'prismic-dom'
const Elements = prismicDOM.RichText.Elements
export default function (type, element, content, children) {
// Generate links to Prismic Documents as <router-link> components
// Present by default, it is recommended to keep this
if (type === Elements.hyperlink) {
let result = ''
const url = prismicDOM.Link.url(element.data, linkResolver)
if (element.data.link_type === 'Document') {
result = `<nuxt-link to="${url}">${content}</nuxt-link>`
} else {
const target = element.data.target ? `target="'${element.data.target}'" rel="noopener"` : ''
result = `<a href="${url}" ${target}>${content}</a>`
}
return result
}
// If the image is also a link to a Prismic Document, it will return a <router-link> component
// Present by default, it is recommended to keep this
if (type === Elements.image) {
let result = `<img src="${element.url}" alt="${element.alt || ''}" copyright="${element.copyright || ''}">`
if (element.linkTo) {
const url = prismicDOM.Link.url(element.linkTo, linkResolver)
if (element.linkTo.link_type === 'Document') {
result = `<nuxt-link to="${url}">${result}</nuxt-link>`
} else {
const target = element.linkTo.target ? `target="${element.linkTo.target}" rel="noopener"` : ''
result = `<a href="${url}" ${target}>${result}</a>`
}
}
const wrapperClassList = [element.label || '', 'block-img']
result = `<p class="${wrapperClassList.join(' ')}">${result}</p>`
return result
}
// Return null to stick with the default behavior for everything else
return null
}
When getting your content for your documents with Nuxt.js a good practice is to use the asyncData lifecycle function when requesting the data. When you do this you should pass the $prismic (this represents the @nuxtjs/prismic module) & error methods.
You can then create a try/catch block and use the $prismic method to query the API.
In the following example we use the getSingle helper function, as we would in standard Vue.js, to query a singleton type with the API ID of 'homepage'. Then we set the response as document and return the data to be used in the page template.
async asyncData({ $prismic, error }) {
try{
const document = (await $prismic.api.getSingle('homepage')).data
return {
document
}
} catch (e) {
error({ statusCode: 404, message: 'Page not found' })
}
},
When creating a query inside the asyncData method you cannot use the this keyword. Also when using Prismic Predicates to query your data you must use the all lowercase predicates.
So in the following examples:
this.$prismic.Predicates.at('document.type', 'post')
The query becomes:
$prismic.predicates.at("document.type", "post")
All other queries to the API remain the same. You can see these queries here.
Templating your data in Nuxt remains the same as vue.js except for one method where you deliver data from a rich text field as plain unformatted text.
In vue.js you can use richTextAsPlain to do this, but in Nuxt you will have to specify the method asText. You can see an example below which is templating a field with API ID title as plain unformatted text.
{{ $prismic.asText(title) }}
All other templating options are the same as Vue.js. You also have more extra helper functions, check them out here.
Thanks to the @nuxtjs/prismic module creating previews in Nuxt.js is really straightforward as everything is handled for you. All you have to do is set up your preview on the Prismic side.
We recommend deploying your Nuxt.js and Prismic application with Netlify, but there are lots of other options that the Nuxt website explains in detail.
Feel free to explore our fully working example website project using Nuxt.js and Prismic.