written by Andre Liem
31/05/2018

Building a VuePress site with the Netlify CMS

In this tutorial, I will show you how to build a static site with VuePress and the Netlify CMS. If you are not familiar with VuePress, it's a static site generator built on top of Vue by Evan You (founder of Vue). Unlike Nuxt.js, the primary focus for VuePress is to build static sites with a fairly opinionated structure which takes care of a lot of the setup work. Netlify, a modern platform for static sites, has a CMS to manage static sites which makes it easy for anyone to manage the content via an editor.

Getting Started

The first thing you'll want to do is clone or download this git repo that I've created.

git clone https://github.com/andreliem/vuepress-netlify-cms

Once you have this setup, here is a review of the file structure.

.
├── LICENSE
├── README.md
├── docs
│   ├── README.md
│   ├── test.md
│   └── welcome.md
├── netlify.toml
├── package.json
└── yarn.lock

Lets's start by explaining the meaning of some of these files.

netlify.toml

[build]
  command = "yarn docs:build"
  publish = "docs/.vuepress/dist/"

This file is used by netlify on deployment. Netlify pulls code from your github repo, and will run command to generate your static site. Once it's complete publish tells it where the public directory is to launch your site.

package.json

{
  "scripts": {
    "docs:dev": "vuepress dev docs",
    "docs:build": "vuepress build docs"
  },
  "devDependencies": {
    "vuepress": "^0.9.0"
  }
}

This file is the standard VuePress settings that you would have if you followed the official Vue Press installation guide.

/docs

├── docs
│   ├── README.md
│   ├── test.md
│   └── welcome.md

Lastly, the docs folder contains actual markdown files that will make up the content of our site itself. These files are committed to github, and netlify's cms will work with these via a CMS that we will have setup by the end of this tutorial.

If you review these files, note that README.md is different than the other two because it's serving as the home page for the site. VuePress reads front matter to configure this post differently. There are a lot more options you can configure using these properties but I'll leave that to you to read the VuePress docs.

Installation

Following the recommendation of VuePress, we will setup the project using yarn instead of npm.

Below is straight from the VuePress docs on why.

It is currently recommended to use Yarn instead of npm when installing VuePress into an existing project that has webpack 3.x as a dependency. Npm fails to generate the correct dependency tree in this case.
(https://vuepress.vuejs.org/guide/getting-started.html)

Let's go!

yarn install

... and wait until it's all installed. Now take some time to review the the directory /docs/.vuepress in your project. Think of this directory as your Vue App as this is where you go if you need to extend VuePress.

.
├── components
│   └── PostLayout.vue
├── config.js
├── dist
└── public
    ├── admin
    │   ├── config.yml
    │   └── index.html
    └── images

Above is a snippet of the key files & directories within .vuepress.

Components is where we can store custom display components such as a custom layout view. We won't be using this in this tutorial.

config.js

module.exports = {
  title: 'Netlify CMS + VuePress',
  description: 'Netlify + VuePress',
  themeConfig: {
    docsDir: 'docs',
    repo: 'andreliem/vuepress-netlify-cms',
    sidebar: [
      '/',
      '/welcome',
      '/test'
    ],
    nav: [
      {
        text: 'Admin',
        link: '/admin/#/',
      }
    ]
  }
}

This file is responsible for the majority of the configuration for VuePress. As an example, sidebar will list the actual links which appear in the side and nav is responsible for the top header links. The sidebar links map to the markdown files contained at the root level of docs. These could be blog posts or more likely documentation for your project.

The nav contains a single link to the administration CMS. Note that this admin section exists within .vuepress/public/admin. The public folder is where you put static files or assets which are not generated by VuePress. In this case we have added some netlify specific code to setup a basic entry point to the CMS.

Lets look at the configuration file for the netlify cms in more detail.

config.yml

backend:
  name: github
  repo: andreliem/vuepress-netlify-cms
  branch: master # Branch to update (optional; defaults to master)
media_folder: "docs/.vuepress/public/images"
public_folder: "docs/.vuepress/dist/"
collections:
  - name: "doc" # Used in routes, e.g., /admin/collections/blog
    label: "Doc" # Used in the UI
    folder: "docs" # The path to the folder where the documents are stored
    create: true # Allow users to create new documents in this collection
    slug: "{{slug}}" # Filename template, e.g., YYYY-MM-DD-title.md
    fields: # The fields for each document, usually in front matter
      - {label: "Title", name: "title", widget: "string"}
      - {label: "Body", name: "body", widget: "markdown"}

There is a lot going on in here and I recommend you read through the netlifycms getting started guide.

Here is a quick overview of what's going on.

backend defines where our content will be stored, in this case we are storing it in the same repo on master.

media_folder tells netlify where to store images. We are storing them in the public folder where VuePress wants static assets to be stored.

collections defines the types of content on our site. If you come from a WordPress background, think of these like custom post types on steroids. It's fairly straightforward what is going on here, we can define some meta information on what these items are, and then the fields visible to edit within the editor. Please note that the markdown files follow frontmatter format.

Running it

Now that you understand the basics of how things are setup, lets try running this by going:

yarn docs:dev

If everything has worked out for you, then you should see the home page screen as below:

Home

This page refers to the README.md file that we have defined as being a homepage. This is a VuePress specific convention that lets you easily get a splash page up without any design work.

Next, if you click the main button you can see the main view like below which lets you browse the posts.

Home

Admin

In order to get administration setup locally, you can try clicking the admin link.

If you get a 404, try refreshing and it should bring up the netlify login screen as below.

Home

This problem does not happen when deployed on netlify, most likely because of default nginx settings. (I am not a server expert though)

If you try signing in with github it won't work as you need to do some work with netlify and github to enable access. The following sections will cover how to get setup with:

  • netlify deployment & hosting
  • netlify identity for CMS access
  • github to netlify access

Before we start this, it is assumed you have a netlify and github account. If you do not, then you'll need to do that first.

Create new netlify site

Login to netlify.com and create a new site. Then pick the repository for your project which in my case is the repo you're using. You'll want to create a new repo on github for this.
Netlify New Site

Define the deployment settings

Next, we tell netlify which branch to pull from, how to build your project and where the distribution files are located.
Netlify Settings

From this point you should test out deploying your app with Netlify and makes sure it works.

Setup Netlify Identity

Now that the site is live, we need to allow people to edit content online through the CMS. This is where we need to setup Netlify's identity settings for the site. From the main site settings page, navigate to "Identity" found on the sidebar near the bottom then make sure to enable identity as shown in the screen below.
Netlify Identity

Configure Identity Registration

Next, lets define who can register for the CMS and how they connect. Since this is just a demo, we will make it "Open" to anyone and use "GitHub" as our external provider for authentication.
Netlify Identity

Configure Identify Services

Ok, so we've told netlify that anyone can register. The next step is to configure a service or the gateway to github so that github lets netlify use it as an authentication platform. Go to the "Services" section under "Identity".

Netlify Identity

First we specify which repository will be used for the CMS, again it's the same one. We're leaving the Roles empty and lastly inputting a Github Access Token that you must retrieve from github. Click the "Generate access token in GitHub" button to begin the request which will ask you for permission.

Setting up OAuth App with Github

Lastly, we need to setup an OAuth App with Github which will let our VuePress Netlify app authenticate with github and redirect back appropriately. This is the same sort of flow you would setup for any 3rd party authentication system that supports OAuth like Facebook, Google etc...

On Github, navigate to Settings->Developer Settings then select New OAuth App.

GitHub OAuth

Update the form fields like above but obviously with your own URL and description details. The callback URL should stay as is and was not particularly easy to find in the online documentation.

Testing it out

Once this is all complete, you should be able to click the Admin link on your site and login via your Github account. If it all worked out then you will see an admin panel like below:

CMS

If you checkout the media section you should see the assets uploaded to the images directory that we setup before.

CMS

Wrapping Up

With this setup you can now manage your VuePress site content through the netlifycms! Any content you update via the CMS will update the repo appropriately while you can still make updates locally with your favourite IDE if you prefer. It's quite powerful when you think about this as you could share this with members of a team who are not developers.

I hope you enjoyed this post, please share if you do and leave any comments if you have any questions or requests for specific types of posts.