Skip to content

How real developers use a CMS to build a showcase website with Netlify, Nuxtjs, and Contentful

Jérémie Chauvel13 min read

A CMS driven static website with Netlify, Nuxtjs, and Contentful

Why build a CMS driven showcase website?

Here you are, you just started a project to build the latest shiny showcase website for your client. Now comes the difficult part: you want to offer your client the best bang for his bucks, not wanting to redo part of the website each time the content changes. In the same way, you are probably not in charge of coming up with the shiny design but coding it, why would you lose time adjusting wordings, coming up with translations?

That’s where a Content Management system (CMS) becomes handy, giving your client an interface to edit the content of his site without wasting its precious developers’ time. Now you might be thinking ‘A CMS, last time I gave a go-to WordPress, I wasn’t convinced !’ and I agree with you. Today CMS fall into 2 usages:

Why use a server-rendered static website for a showcase website?

Doing so leverages the advantages of using a progressive web application with server-side rendering (more about SSR here) without the cost of running a server since you just need to serve your files. Furthermore, we leverage the following advantages for a showcase website:

Why use Netlify & Nuxtjs

Netlify

Infrastructure wise our requirements are very small, we only need a CDN to distribute our site. We could use any major cloud provider directly, however, I decided to go with Netlify service for the following reasons:

Nuxtjs

Nuxtjs is a server-side rendering framework built on top of Vuejs. For our case, Nuxtjs allows for dead easy creation of a server-side rendered static website.

Building a CMS driven showcase website

contentful logo

Creating a Contentful CMS

First, as the website is content-driven, we will start by creating the CMS using Contentful to provide content to the website.

Start by creating an account on https://www.contentful.com/sign-up/ (use free trial for this tutorial) Once you sign up, you can create a new space (which is Contentful way of creating a project)

Create a new project in Contentful step 1/2

Create a new project in Contentful step 2/2

In the popup dialog set the type of space (you can upgrade later), the space name (the project name):

You have successfully created a new contentful project 🎉

Creating the first content

Contentful is organized between:

Create the content model

To create our first content we will use the Content model tab, click on add content type

When creating a new content type, we have to fill in some important information:

Create a new content type in contentful

Finally, confirm to create the new content type.

Now, we have a new empty content type. To fill it, we will add some fields:

To do so, first, click on add field:

You successfully created the first field, we will create a second one for the paragraph:

Once you created both fields, you can now hit save on the top right corner of the content type as we finished creating our content type.

Contribute the first section

As we now have the first content type, we can contribute to creating new content. To do so, in the main contentful header, head to the tab Content.

By default contentful filter with the current content type, we can create a new section hitting the button Add Section

Contribute a new section

You end up on the form to edit the entity. You need to provide a title and you can provide some text for the paragraph. Then hit publish.

You are done for the CMS part (keep it open for latter).

Nuxtjs logo

Installing Nuxtjs

First, we are going to create a Nuxt application.

To do so, you need to have Npm installed and type in:

npx create-nuxt-app <project-name>.

Once you launch the command, you will need to answer a few questions:

recap of the install configuration Nuxtjs

You can run the Nuxt dev server using:

cd cms_driven_static
npm run dev

First npm run dev Nuxtjs

You are done installing Nuxtjs 🎉

Fetch the section content in Nuxtjs

We will now display the Section content in the Nuxt frontend. To do so, we need to install the contentful module: npm install contentful --save.

Then to use the contentful package in Nuxt, we will create a plugin. Plugins are the recommended way to use javascript libraries globally.

Finally, we will use this plugin to fetch content in the application pages.

Creating the Nuxt.js plugin

In the plugins directory of the project create a new file: contentful.js

Add the following code in the file:

// First we import the contentful node module
const contentful = require('contentful')

// Those are set via `env` property in nuxt.config.js or environment variables
const config = {
  space: process.env.NUXT_ENV_CONTENTFUL_SPACE,
  accessToken: process.env.NUXT_ENV_CONTENTFUL_ACCESS_TOKEN,
}

// Create a client to setup fetching content
const client = contentful.createClient(config)

// Our first method to fetch all section content type
client.getSectionContent = () =>
  client.getEntries('', {
    content_type: 'section',
  })

export default ({ app }) => {
  // Add the function directly to the context.app object
  app.contentfulClient = client
}

Now we will register the plugin in our Nuxt config, head to the file nuxt.config.js. In this file you will find an empty plugins array. Add { src: '~/plugins/contentful' }, in this array:

-  plugins: [],
+  plugins: [{ src: '~/plugins/contentful' }],

That’s all for the plugin configuration. 🚀

Finally, we need to specify the contentful credentials, to do so, we will use the dotenv module:

  buildModules: [
    '@nuxtjs/eslint-module',
+   '@nuxtjs/dotenv'
  ],

Using the prefix NUXT_ENV_ enables Nuxtjs automatic injection of environment variables into process.env.

To fill in those values go back to contentful. Go to the settings tab and find ‘api keys’. If one already exists, use it, else create a new one. (specify any name and description)

Use both Space ID and Content Delivery API - access token to fill in your .env variables.

Restart your server (interrupt and npm run dev), the webpage should load errors free.

You should be set to fetch your content on your Nuxtjs page.

Display the section content

Let’s make this API call and display the section content.

Head to the file pages/index.vue. It’s the entry-point of your nuxtjs application, namely the landing page.

A brief introduction to Vuejs single file component syntax

A single file Vue.js component is organized in 3 parts:

<template>
  <p class="paragraph">{{ greetings }} World!</p>
</template>

<script>
  module.exports = {
    data() {
      return {
        greetings: 'Hello',
      }
    },
  }
</script>

<style scoped>
  .paragraph {
    font-size: 2em;
    text-align: center;
  }
</style>

Fetching the section content

First, we are going to fetch the section data and we want to fetch it server-side to be able to render the full HTML before sending it to the client.

To do so add an asyncData method below the component in the script HTML element, ending with the export looking like this:

export default {
  components: {
    Logo,
  },
  async asyncData(context) {
    const sections = await context.app.contentfulClient.getSectionContent()
    console.log(sections.items)

    return {}
  },
}

Reload your page http://localhost:3000/, you should see your Section item in the console.

Then we will add some logic to the contentful plugin to map the interesting properties for the landing page Vuejs component:

// First we import the contentful node module
const contentful = require('contentful')

// Those are set via `env` property in nuxt.config.js or environment variables
const config = {
  space: process.env.NUXT_ENV_CONTENTFUL_SPACE,
  accessToken: process.env.NUXT_ENV_CONTENTFUL_ACCESS_TOKEN,
}

// Create a client to setup fetching content
const client = contentful.createClient(config)

// Our first method to fetch all section content type
client.getSectionContent = () =>
  client
    .getEntries('', {
      content_type: 'section',
    }) // map the interesting properties from section
    .then(({ items }) => {
      return items.map((section) => {
        return {
          title: section.fields.title,
          paragraph: section.fields.paragraph,
        }
      })
    })

export default ({ app }) => {
  // Add the function directly to the context.app object
  app.contentfulClient = client
}

And use it in the asyncData of pages/index.vue:

 async asyncData(context) {
    const sections = await context.app.contentfulClient.getSectionContent()
    console.log(sections)

    return {}
  }

Display the section

Finally let’s display our data, first make the sections available in the state of the component:

async asyncData(context) {
  return {
    sections: await context.app.contentfulClient.getSectionContent(),
    }
}

Update the template to use the new data from the asyncData:

<template>
  <div class="container">
    <div class="logo-container">
      <logo />
    </div>
    <div v-for="section in sections" :key="section.title" class="section">
      <h1 class="title">{{ section.title }}</h1>
      <h2 class="subtitle">{{ section.paragraph }}</h2>
    </div>
  </div>
</template>

Update the style of the component:

<style scoped>
  .container {
    margin: 0 auto;
    min-height: 100vh;
    display: flex;
    flex-direction: column;
    justify-content: center;
    align-items: center;
    text-align: center;
  }

  .logo-container {
    height: 50%;
    width: auto;
  }

  .section {
    margin-top: 20px;
  }

  .title {
    font-family:
      'Quicksand',
      'Source Sans Pro',
      -apple-system,
      BlinkMacSystemFont,
      'Segoe UI',
      Roboto,
      'Helvetica Neue',
      Arial,
      sans-serif;
    display: block;
    font-weight: 300;
    font-size: 60px;
    color: #35495e;
    letter-spacing: 1px;
  }

  .subtitle {
    font-weight: 300;
    font-size: 21px;
    color: #526488;
    word-spacing: 5px;
    padding-bottom: 15px;
  }
</style>

Then reload your homepage, you will be able to see your new section content: Display our first section from cms

Congratulations 🎉

Let’s add one more section content in Contentful to check that our page works correctly.

Once you add the new section content and publish it you should see both sections on your homepage: Display both sections from cms

Netlify logo

Deploy the website using Netlify

Setting-up automatic deployment

Finally, we will deploy the website, making it available on the Internet.

First of all, create a repository for the project on Github or Gitlab and push your project.

Once you are there, you can head to Netlify website: https://www.netlify.com/, create an account using your favorite authentication: https://app.netlify.com/signup

Once on the project page, I recommend using ‘New site from Git’ to setup up a static website deployment with the added benefit of an out of the box working CI, building your site with every new commit on your production branch. Netlify project selection page

Select your repository: Select your repository to publish with Netlify If it doesn’t appear in the list click on Configure the Netlify app on Github

For your site settings, go for:

Nuxt settings with Netlify

Your site is now online! 🎉

You can find the Netlify generated URL (ending in .netlify.com) on the Netlify project overview. Access your netlify website

Using your own domain name

Here again, Netlify eases the process, you simply need to have a domain name registered.

Once you have a domain name, you can carry on the settings:

Using TLS (HTTPS)

Once you can access the website using your domain, you will want to use https for security, SEO and performance purposes, you can and should use netlify https functionality:

Head to https in domain settings of your website:

Deploy on content change

One last interesting feature is the ability to rebuild the website when content changes. As of now, if we add a new section on contentful, it’s not reflected on the website. Let’s change that so that any modification on the site triggers a rebuild of the website:

Wrap-up words

Building a showcase website is mostly about content, presenting the products, services, the company goal/mindset. In this regard, using a CMS is the best way to enable your client to update their contents, keeping them happy 🎉

This article, was a simple introduction, to the currently available technologies enabling developers to build such a site. There are much more great features enabled by those tools, namely:

Thank you for getting this far and happy coding!