Setting up a full static Nuxt site
When I start a project these days I usually choose Nuxt for it. Why? Because I can do all the things I do with plain Vue.js in less time, thanks to its conventions and the amazing Nuxt modules.
Some people think because of these conventions you lose flexibility. That's far from the truth: I've been using Nuxt for the last 2 years and I haven't found a case where I can't do what I wanted to do.
I've been using it even in Sprinter, one of the biggest Spanish sports E-Commerce. I spoke about the challenges we faced in this talk on Vue Day 2019.
But what I love the most about Nuxt is that you can produce 3 types of applications mostly with the same code:
- SSR (Server Side Rendered): they're rendered on the server for every request. Sprinter works like that.
- SPA (Single Page Application): client-only javascript based apps. Nowadays, they're quite well-known.
- Static Generated: a.k.a. Jam Stack. Similar to SSR, but the html is rendered at compile time, so they don't need a server while also being SEO friendly.
VueDose is built as a static generated site, for different reasons:
- SEO friendly
- Very fast: HTML is already rendered
- Saving on resources: it doesn't need a server, so you're saving money and the planet
Since Nuxt 2.13, we can create full static websites. In other words: you can generate a pure HTML + CSS + JavaScript site. All the Ajax calls to any API's are made at compile time, and then stored in json files locally.
What does that mean? Easy: huge performance boost.
But hey that's too much introduction, right? Let's start building NarutoDose!
# The Stack
# Nuxt.js
I think I showed enough love to Nuxt, right? Ok fine let's show Nuxt love once more 💚💚💚
# Storyblok (vs Nuxt Content Module)
Nuxt's recent release, @nuxt/content: an amazing module for creating your contents under a content/
folder by default. Your contents can be in Markdown, Yaml, JSON and other formats and it exposes an API where you can query those contents. Honestly, this was the missing part in the Nuxt ecosystem for indie tech bloggers.
You might think, couldn't you create VueDose with @nuxt/content? Yeah, I definitely could. But I didn't.
Why? Because, even though they both have things in common such as:
- A flexible API to query contents, including full-text search
- Ability to schedule content
- Ability to use rich text format, such Markdown
There are definitely different:
- @nuxt/content: it acts as a git-based CMS, meaning that people need to be familiar with git. That's ok for most tech blog cases, just something to be aware of.
- Storyblok: it's much more than that. Although easy to use, it's a fully cloud-based CMS product that has more features for working with content such as, being able to define a schema, relationships and even a visual editor. It can be extended with plugins, although by default you also have roles, on-the-fly image resizing service, assets managements, and more. It can be managed by a non-dev user.
Since I wanted to leverage the power of Storyblok on VueDose, that was an easy decision to make. No worries, soon you'll know how to do it too 😉.
# TailwindCSS
You know that there are many CSS frameworks out there... the well-known Vuetify, the new exciting Chakra UI for Vue, Buefy, Bootstrap Vue and of course the marvelous [INSERT YOUR NEW UI FRAMEWORK HERE].
But Aarón and I decided to design VueDose from scratch, creating our own Design System, carefully thought out for giving the best reading experience and a beautiful UI.
TailwindCSS is not opinionated and is perfect for this case. Check out the next article to find out all the whys and how-tos 😏
# Create a Nuxt project
The easiest way is to use npx (install it if you haven't) to run create-nuxt-app:
npx create-nuxt-app mini-vuedose
That will open a prompt where you can select the features you want. For this project we'll choose TailwindCSS and it's important to choose Universal (SSR / SSG) as a rendering mode and Static (Static/JAMStack hosting) as a deployment target:
Now let's clean up some things:
- Remove the folders
store
andmiddleware
. You don't need them for now. - Remove
components/Logo.vue
- In
pages/index.vue
, remove the<style>
tag and empty the<template>
.
Starting clean, now is a good time to create the ArticleCard.vue
component. Let's temporarily place it under the components
folder.
As you can guess by the name, the ArticleCard component is used for displaying the list (or grid) of articles in the home page. Create it with the following structure:
<template>
<div>
<header>
<nuxt-link :to="`/${slug}`">{{ title }}</nuxt-link>
</header>
<p>{{ description }}</p>
<footer>
<img :src="author.image" :alt="author.name" />
<span>{{ author.name }}</span>
</footer>
</div>
</template>
<script>
export default {
props: {
title: String,
slug: String,
description: String,
author: Object,
},
}
</script>
It's simple: it has a title, description, slug and an author.
Now go to pages/index.vue
and create an articles array in the asyncData
function. For now it will be static, but later we'll use Storyblok to get the real data. Use the ArticleCard
component we created to display the article data:
<template>
<div>
<h1>Articles</h1>
<div>
<ArticleCard
v-for="article in articles"
:key="article.title"
:title="article.title"
:description="article.description"
:author="article.author"
/>
</div>
</div>
</template>
<script>
export default {
asyncData() {
const articles = [
{
title: 'How to make your articles Vuetiful',
description:
'This article guides you through all the steps to make an article shine with your favourite framework, Vue',
author: {
name: 'Naruto Uzumaki',
image: 'https://wallpaperaccess.com/full/2866246.jpg',
},
},
]
return { articles }
},
}
</script>
Do you see the ArticleCard being imported? No, because from Nuxt 2.13 the @nuxt/components modules is built-in Nuxt and activated by default, meaning... no more component imports!
Let's make sure things work. Run npm run dev
in your terminal and open http://localhost:3000. The page should look like this:
Don't worry too much about the card design right now, you will see that in the next article!
# Recap
Up to this point, you have set up Nuxt with TailwindCSS in full static mode. Easy right? Yes, Nuxt does a lot of things for you out of the box, and based on the choices you made using the installer, things are configured out of the box. Later in this guide you'll see how to generate the production page but hold on for now.
This was just an introduction to get you started, but things are about to get fun 😎
Hold on there! In the next article you'll learn to design the app UI based on a Design System while following a simple yet solid component structure that I use on my projects.
You'll also learn why TailwindCSS fits so well for that purpose.
Pssst: you can find this article's code on Github.
How we built our blog as a full-static site with Nuxt, Storyblok and TailwindCSS
This article is part of an amazing guide.
- Setting Up a Full Static Nuxt Site
- Creating UI Components based on a Design System in Vue.js
- Setting up the blog content structure in Storyblok
- Show the Blog Content in Nuxt Using Storyblok API
- Tags and Search Functionality in Nuxt Using Storyblok API
- Optimize SEO and Social Media Sharing in a Nuxt blog
- Generate and deploy the blog as a full static Nuxt site
Related Articles
How to use script setup in Nuxt 2
If you love Vue script setup and want to use it in your current Nuxt 2 project, the Nuxt team has made it possible to start using it today!
Feb 14, 2022
How to use the new Fetch in Nuxt.js
The Nuxt team is on fire, releasing new stuff every week! In this tip Samuel shows you a feature that might've gone unnoticed... till now.
Sep 7, 2020
Advanced i18n in Nuxt using Interpolations
Internationalization it's necessary in a multi-language site. Learn how to do i18n the right way in Nuxt and Vue using the nuxt-i18n module.
Aug 17, 2020
Sponsors
VueDose is proudly supported by its sponsors. If you enjoy it, consider supporting it to ensure the project maintainability.