10.08.2019

Building a small "offline" CMS for a static portfolio site

Tired of running wordpress, or even a server for a CMS. Gitlab CI/CD and Nuxt.js for a new solution.

Why

I love static websites. They're fast and they make perfect sense for a portfolio website, that is updated maybe twice a year. There's no need for a dynamic website with a backend server. (Also... It saves a little energy, for whatever that is worth.)

However, CMS systems make sense for people without too much tech knowledge. They're convenient and hopefully simple to use.

That's what I wanted for this project, too. No JSON file editing, no git commands, no dependencies. Simple.

Overview

This isn't supposed to be a developer blog, so I'll focus on some key features or hiccups I came across. Namely:

  1. The general concept of this project
  2. Golang Backend Server
  3. Gitlab Pipeline
  4. Screenshot for people who like pictures (me).

Simple CMS concept

First up: Here's the repo link. Second: A quick diagram, to get an overview:

Simple CMS Diagram

As you can hopefully tell from the diagram, the editing process is as follows:

  1. Start the CMS. A config needs to be provided beforehand. Check the repo for variables I used. The Data Repo is cloned / fetched as necessary.
  2. A Nuxt / Vue SPA is opened in your browser. This is just for visuals. Manage your projects here.
  3. On Update, the app sends a request to the go server to update and write the data.
  4. After you're done, hit a Generate all button. Additional files are written and the repo is pushed. After that, it triggers a webhook for the gitlab pipeline (see Gitlab Pipeline).
  5. The static site is generated with the new data and pushed via lftp to your hosting provider.

So much for that. Now some details.

Golang Backend Server

All in all this is a straight forward "Backend" with a small REST API.

It supports list, get, new, create, update and delete, as is the case quite often.

The "database" is just JSON files, that a read and written on the fly, so there's no caching. Could be implemented, but there were no performance issues yet.

Project have a "tag" called "Position", which are written to a file for the static site and management. They are however pulled from the data and only generated on the final Generate all. On the frontend they're managed in a nuxt store.

The git management in go is quite nice. It allows me to setup a git account with necessary write rights and pushes the repo with basic HTTP Auth.

Gitlab pipeline

Now this is where the magic happens. After some small hiccups it all quite simple (heh), though. To setup a gitlab pipeline, all you have to do is add a .gitlab-ci.yml file to the root of your git repo.

Here's the one I'm using:

image: node:latest

before_script:
  - git clone https://gitlab-ci-token:${CI_JOB_TOKEN}@gitlab.com/JSHSJ/gise_portfolio_data.git
  - mkdir -p static/data
  - mv gise_portfolio_data/* static/data/
  - npm install
  - apt-get update -qy
  - apt-get install -y lftp

cache:
  paths:
    - node_modules/

stages: 
  - build
  - deploy

job1:
  stage: build
  script: 
    - npm run generate
  artifacts:
    paths:
      - dist
  only: 
    - master


job2:
  stage: deploy
  script:
    - lftp -e "open $FTP_USERNAME.kasserver.com; user $FTP_USERNAME $FTP_PASSWORD; mirror -X .* -X .*/ --reverse --verbose --delete ./dist/ /181degree.com/; bye"
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33

Let's see what it does, because that's what was new for me.

image: node:latest specifies the docker image to use. As we're using only node, this one's quite obvious.

before_script: Clone the Repo. Important (It was confusing to me...). You do not have to specify ${CI_JOB_TOKEN} anywhere. Just clone https://gitlab-ci-token:${CI_JOB_TOKEN}@link-to-your-repo. The rest is straight forward: copy files to your directory and install dependencies.

cache This should speed up your rebuilds.

stages I needed to stages, so the jobs don't run in parallel. That wouldn't work.

job1: Build Generate website and specify the artifact you want to keep.

job2: Deploy Copy the generated static site to your webhost using lftp. This isn't about how to use lftp, but this command copies the data to the given directory and deletes unnecessary files. Set $VARIABLES in your repo's CI/CD settings.

You can set up a pipeline webhook there, too. Mine triggers a rebuild, but there's a lot of things to explore or integrations to use (slack & co).

For more info, check out the official Gitlab CI/CD Documentation.

Screenshot

Just to get an idea to see the SPA without having to run it.

Simple CMS Frontend