I have recently been building a few websites using Eleventy. This is a static site generator, built using Jamstack methodology.
This is a great way to get a simple website built, as it gives you static HTML files which you can serve from anywhere. The downside is there is no database and therefore no traditional content management system to administer the content.
There are tools which help you add a CMS to websites built this way. This is done by using a headless CMS with two options; API-driven and Git-based. I am not using an API to build the content – the content is driven by markdown files, so using a Git-based solution was needed.
Netlify CMS is a drop-in Git-based CMS solution built in React. You create a configuration file and a static HTML file pointing to the JavaScript and you can start editing your content using a nice UI.
Setup with Eleventy
As I have an Eleventy-based project, I used the tools it provided to add the required files.
I added a simple /src/admin.md
file which generates the /admin/
HTML.
---
title: Content Manager
layout: admin
---
The markdown file uses the /src/layout/admin.njk
template. This is very similar to the default
Netlify CMS example.
<!doctype html>
<html>
<head>
<meta charset="utf-8"/>
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
<title>{{ title }}</title>
</head>
<body>
<script src="{{ "/js/manifest.js" | url }}"></script>
<script src="{{ "/js/admin.js" | url }}"></script>
</body>
</html>
In my .eleventy.js
configuration file, I added the following.
This copies the Netlify CMS configuration YAML file to the /admin/
folder.
config.addPassthroughCopy('src/admin/config.yml', 'admin/config.yml')
Setting up Netlify CMS
I setup the Netlify CMS as described in the Add to Your Site guide. However, if you look at the example template above, I am actually using local JavaScript files.
After getting the basics working, I moved the integration to use locally provided JavaScript. I installed the CMS script using NPM, as per their example. I also required the Netlify Identity widget using the same method.
npm install netlify-cms --save
npm install netlify-identity-widget --save
I have a build step for JavaScript using Laravel Mix, which
is based on Webpack. The admin.js
file requires
the two dependencies imported above.
require('netlify-cms')
require('netlify-identity-widget')
Running locally
The default setup for Netlify is to integrate with an OAuth provider. This is solved using the Netlify Identity which can connect to your GitHub repository.
However, locally, I didn't need this complexity, instead I wanted the CMS to talk to my local repository. Thankfully there is a beta feature called Working with a Local Git Repository which does exactly what I needed.
To enable the local development and authentication, you need update the configuration YAML file and add the following;
local_backend: true
This works by communicating with a local server. You need to install and configure this to make it work. As documented, I used the Netlify CMS Proxy Server
npm install netlify-cms-proxy-server --save-dev
I then updated the package.json
scripts, so when starting my Eleventy project, it also started
this proxy.
"scripts": {
"start": "npm run proxy-server & npm run serve & npm run development -- --watch",
"serve": "cross-env ELEVENTY_ENV=development npx @11ty/eleventy --incremental --serve",
"development": "cross-env NODE_ENV=development node_modules/webpack/bin/webpack.js --progress --config=node_modules/laravel-mix/setup/webpack.config.js",
"proxy-server": "npx netlify-cms-proxy-server",
"build": "npm run production && npx @11ty/eleventy",
},
Now running npm start
gives me a hot-reloaded Eleventy website, with JavaScript and assets
built using Laravel Mix and a proxy server to use with the local Netlify CMS.
Development configuration…
The final piece of the puzzle was altering the configuration when running the site locally, in development mode.
I updated the admin.js
file, to override configuration based on the current Node build environment.
By default, the Netlify CMS is automatically initialised. However, we need to override that. There are some
beta features which document exactly
what was needed.
import CMS from 'netlify-cms'
require('netlify-identity-widget')
window.CMS_MANUAL_INIT = true
let config = {}
if (process.env.NODE_ENV === 'development') {
config = {
local_backend: true
site_url: 'http://127.0.0.1:8080',
publish_mode: 'simple'
}
}
CMS.init({
config
})
The idea was to set local_backend: true
only when needed, in development. However,
this only seemed to work when set in the config.yml
file, even when other properties
such as site_url
were successfully overridden correctly.
However, after much investigation, the local_backend: true
configuration
is only applied on local development.
This means that leaving the configuration in the config.yml
only affects development.
Although the solution I documented above works, it’s not intuitive to someone looking at the code. There are two issues;
-
local_backend: true
in the JavaScript doesn’t get used. - Setting
local_backend: true
in theconfig.yml
could frighten/confuse developers who don’t know this only applies locally.