Create Nuxt.js Universal Apps using GraphQL on Postgres
TL;DR: Server side render websites using Nuxt.js and GraphQL APIs over postgres using Hasura GraphQL Engine. Instant setup. Tutorial/boilerplate -> nuxtjs-postgres-graphql
Building universal applications can be difficult, but Nuxt.js aims to make it easier. Nuxt.js is a performant and modular framework that enables you to develop Universal Vue.js Applications.
What is a Universal Application? A Universal Application, also known as an Isomorphic Application, is an application whose code runs both on the client and server sides.
This article showcases a Universal Application that uses Nuxt.js and Hasura GraphQL Engine. The application is a blog-like application that displays a list of authors and their articles.
Note: The article illustrates the most important parts of the application. You can view the complete code in this GitHub repository.
SSR with Nuxt.js
Nuxt.js is a Vue.js framework that allows you to build server-side rendered (SSR) Vue applications. In a universal app built with Nuxt, the pages are rendered on the server-side and then sent to the client.
Due to its capabilities of supporting both server-side rendering (SSR) and single-page application (SPA), Nuxt.js enables you to build universal applications.
How does it work:
Pages: Nuxt is opinionated on the project directory structure. It transforms the .vue files inside the pages directory into application routes. For instance, the file mypage.vue corresponds to mywebsite.com/mypage. In the boilerplate example, you can see how the pages are structured. For more information on the directory structure that Nuxt enforces, read more here.
Server-side data fetching: The Nuxt community has built the apollo-module that lets you use the Apollo Client with a GraphQL endpoint.
Project Implementation
In this section, you will see the server-side data fetching in action. You will use the apollo module to fetch the list of blog authors and their articles.
Before going further, create the Nuxt project as follows:
npx create-nuxt-app blog-app
After running the command, Nuxt asks a couple of questions to help you configure the project. Choose these answers:
Programming Language - JavaScript
Package Manager - npm or yarn (whatever you want to use)
Rendering Mode - Universal
Deployment Target - any of the two
For the other questions, you can omit them or leave the default answers.
Project Dependencies
For this project, you need a couple of packages such as "apollo", "graphql-tag", and others. See the complete list of dependencies:
The above plugin is a global error handler, and it's taken from the "@nuxtjs/apollo" documentation.
GraphQL Queries
For this application, you have two queries:
one to fetch the authors
one to fetch their article
Inside the same folder - "apollo", create a new "queries" folder. After that, create a new file called fetchAuthor.gql in the "queries" folder.
📂 blog-app
└ 📂 apollo
└ 📂 queries
â”” fetchAuthor.gql
Add this query in the "fetchAuthor.gql" file:
query {
author {
id
name
}
}
Similarly, create a new file named fetchArticle.gql to store the query for fetching articles:
query article($id: Int) {
article(where: { author_id: { _eq: $id } }) {
id
title
content
}
}
You will import the above queries whenever you need to use them in a page. With that being said, it's time to build the pages that display the authors and articles.
Fetch Authors
Open the pages/index.vue file and add the following code:
<template><div><h3>Authors</h3><ul><li v-for="item in author":key="item.id"><nuxt-link :to="`/article/${item.id}`">{{ item.name }}</nuxt-link></li></ul></div></template><script>import author from'~/apollo/queries/fetchAuthor'exportdefault{apollo:{author:{prefetch:true,query: author
}},head:{title:'Authors of Blog'}}</script>
In the above code, author is a GraphQL query that fetches the list of authors from the database and updates the author property in Vue.
After that, it loops over the array of authors and displays each author on the page. Clicking on an author takes you to their article.
How does it work?
This GraphQL query is executed on the server and the data is available in <template>, which allows the page to be rendered server-side. The same query is then executed on the client-side, making it universal/isomorphic.
Fetch Article
Create the file pages/article/_id and add the following code:
<template><div v-if="article"><div v-for="item in article":key="item.id"><h3>{{ item.title }}</h3><p>{{ item.content }}</p><p><nuxt-link to="/">
Home page
</nuxt-link></p></div></div></template><script>import article from'~/apollo/queries/fetchArticle'exportdefault{apollo:{article:{query: article,prefetch:({ route })=>({id: route.params.id }),variables(){return{id:this.$route.params.id }}}},head(){return{title:'Articles by Author'}}}</script>
Looking at the file name, you can observe the underscore (_). That means the page is dynamic - the "name" of the page comes from the Hasura backend.
If you go back to the index.vue file, you should see:
<nuxt-link :to="`/article/${item.id}`">
The "item.id" comes from the database, which means that each article has a different URL. Nuxt (and Vue) allows you to create dynamic pages for such cases.
Also, here you are using reactive parameters. Observe the following piece of code:
Whenever the parameter changes - the article id, it will re-fetch the query and thus update the page and show the requested article.
Other than that, it works like the previous query that fetches the authors.
Nuxt.js + Hasura + apollo-module = Universal Apps with GraphQL!
There is a boilerplate and a short tutorial to help you get started quickly! Check it out on Github.
Take it for a spin and let us know what you think. If you have any questions or run into any trouble, feel free to reach out to us on Twitter, Github, or on our Discord server.
This post was originally published on Jan 30, 2019 and updated on April 11, 2022.