Originally posted on Formcake’s blog.
We are huge fans of Nuxt at Formcake. It's everything developers like about Vue, having a solid and easy to understand feature set, but applied to the complicated world of Server Side Rendering and static generation. There is one aspect to Nuxt however that is a bit confusing and hard to grapple with for beginners. In this blog post we will go into how to effectively integrate Nuxt into a build pipeline.
For those who have not used Nuxt, here is a very high level description. Nuxt is a project in the Vue ecosystem that makes it very simple to create Vue based apps that run as a SSR application using node or as a static website. Configuring SSR and static site generation correctly with a javascript framework are notoriously hard problems to roll on your own and Nuxt makes creating a Vue based app insanely simple for the hobbiest or the enterprise user.
In this article we are going to focus on integrating a Nuxt application that generates all of it's pages before deploying to a static site hosting platform. If you follow our blog at all, then you may have also caught onto the fact that we are huge fans of static sites and the JAMStack paradigm. One of the many benefits that we love about static websites is that each build of your site is like a health check of the entire site. If you have ever maintained a large website then you may have had the experience of stumbling upon a broken page from time to time. This is far less likely to happen with a static site generated with the correct build configuration.
Example Nuxt Project
To help illustrate this guide I created a simple boilerplate Nuxt project. This is nothing more than a npx installed version of Nuxt with just a few changes. I also went ahead and hooked this project up to Netlify in order to get a simple build process for deployment. Any build process would work the same way whether it be Github Actions or AWS Codepipeline. You can find the Netlify site for this project here.
The Setup
In order to have something to build I first created a "blog" page type that expects a title path in Nuxt within the pages directory.
pages
/blog
_title.vue
The idea behind having a blog page content type is that I now have something to build that would theoretically come from an api or a flat file system. This source of data may not always be configured properly and if it is not, then we want our build to fail.
The next thing I did was build a mock api endpoint as a simple javascript file that exports an object located within the mock-api directory.
mock-api
/blog-pages.js
The data within the endpoint simply contains an array of "blog posts" with each post being represented as an object. Each post only contains two keys, a "route" and a "title". The "route" is used to match which post is tied to which page and the "title" is simply the title of the blog post. A real blog api would also contain a post description, the content for the post, and maybe an image for the header but this data works well enough to get my point across. You may notice that the last blog post does not contain the title of the post. This is where we are going to hang our deployment failure on when it comes time to build the site since this should be considered required information for rendering a blog page.
export default {
posts: [
{
route: 'how-to-use-nuxt',
title: 'How To Use Nuxt'
},
{
route: 'nuxt-performance',
title: 'Getting The Most Out Of Nuxt'
},
{
route: 'nuxt-vs-next',
title: 'A Comparison of Nuxt vs Next'
},
{
route: 'nuxt-ssr-guide',
}
]
}
In the blog post page, pages/blog/_title.vue, we simply query our mock posts api, match up the route using the array find method, check to make sure the title exists, and return the page data to the component if it does. If the post does not contain the title then we throw an error. In our example a post page simply renders the title.
import mockApi from '~/mock-api/blog-pages.js';
export default {
asyncData ({ params }) {
const pageData = mockApi.posts.find(post => post.route === params.title);
if (!pageData.title) {
throw new Error(`Blog API call for ${params.title} did not return required blog information`);
}
return pageData;
}
}
The Build Process
By default Nuxt provides great production build commands. It generates pages that are well optimized and has some nice logs that can help with debugging when things go wrong. The problem however is that a Nuxt build will not return a non zero exit code when its fails to build a page. Let's take a closer look at the boilerplate yarn generate
command. The contents of this command are a combination of the nuxt build and nuxt export commands
nuxt build --target static && nuxt export
The yarn command generate first builds the project for static and then exports the build into the dist directory within the root of the project. for those playing along, the only configuration you need to setup to get this project running within Netlify is setting which build command to run and which directory has the built site. As you can see in the screenshot below, our build command is set to the default Nuxt production build command yarn generate
and our publish directory is set to "dist".
This setup works great until you have a build where a page fails to generate. This could happen for any number of reasons. Perhaps your CMS or Database is missing a field like in our example or perhaps a request simply timed out. The screen capture below further illustrates the issue with using Nuxt's default production build. The page /blog/nuxt-ssr-guide failed to build as we expect, but the build succeeded!
In order to make production builds properly fail, we must add the --fail-on-error
flag to the nuxt export
command.
nuxt build --target static && nuxt export --fail-on-error
This single flag fix gives us the build result we expect. The screen capture below shows that after changing the build command within Netlify to yarn generate-prod
, we now have a build that fails properly.
And there you have it, a one flag fix to a potentially very serious problem if ignored.
Notes
Until very recently the nuxt generate
command was the standard way to build a production version of a static Nuxt site. This just changed in 2.13 on June 18th 2020. The documentation currently states that a combination of nuxt build
and nuxt export
should be used for any version of Nuxt >= 2.13. I still like having a convenient generate command and so I created the yarn generate
and yarn generate-prod
commands myself within the package.json file. Feel free to organize your production build commands however you like within your Nuxt project but just know that these are not boilerplate.
I would also probably not use this exact setup for generating pages in a Nuxt project but I wanted to show this process with the use of the asyncData method. I would most likely do all of the generation logic within the nuxt.config.js and pass the page's route along with it's data to the generate option.
Top comments (1)
Having the same trouble!
I like the new way for deploying full static (no calling apis) but what if I want a SSR that fetch some API's.