Back to Blog
Blog

How to Build a Jamstack Website

Tony Spiro's avatar

Tony Spiro

March 21, 2017

cover image

Update

Check out the Jamstack CMS knowledge base page to learn how you can use Cosmic to build a Jamstack site using Gatsby, Nuxt.js, Gridsome, and more.



Continue reading for an example using Metalsmith.


Introduction to Jamstack

There’s been a recent surge of interest in static websites because they offer benefits including fast page loads and security.  And a new term for this new way of building websites, coined by the folks at Netlify, is JAMstack(not to be confused with the most addicting way to play the electric guitar). If you are new to this concept, the JAMstack is comprised of a JavaScript-powered frontend for page interactions (J), APIs to connect to various APIs to get 3rd party functionality (A) and plain old Markup (HTML) which gets deployed to your instance (M).

Smashing Magazine has recently raved about creating their new JAMstack website and is currently undergoing a massive renovation of their existing web properties.  They are drop-kicking their bloated, pain-point-prone WordPress monolith that they currently maintain in favor of a JAMStack-powered website with help from Netlify and the Netlify Open-Source CMS.

Cosmic Jamming

In this article, I will show you how you can use Cosmic to deploy your own JAMstack website in just a few clicks.  When you JAM with Cosmic, you not only get the benefit of a fast, optimized static website, but your content is also available in the Cosmic API.  This gives other applications easy access to your content which could include landing pages, microsites, or native iOS and Android applications.

TL;DR

1. Install the Cosmic Static Website.
2. View the code on GitHub to see how the app is built.
3. Deploy your app to the Cosmic App Server by going to Your Bucket > Deploy Web App.
4. Set up your Webhooks located in Your Bucket > Webhooks.

Getting Started

We’re going to install the Static Website App available in the Cosmic App Store.  As you do this, you should also fork the repo to your own repository on GitHub.  This way you can make all the customizations you need to JAM in your own way.

Let’s take a look at how this application is put together.  To follow along, go to the GitHub repo.  Here is the app.js file:

// app.js
var buildSite = require('./build-site')
buildSite()
var express = require('express')
var app = express()
app.set('port', process.env.PORT || 3000)
app.use(express.static('build'))
app.get('/rebuild-site', (req, res) => {
  buildSite()
  res.end('Site rebuilt!')
})
app.post('/rebuild-site', (req, res) => {
  buildSite()
  res.end('Site rebuilt!')
})
app.get('*', (req, res) => {
  res.redirect('/404')
})
app.listen(app.get('port') || 3000, () => {
  console.info('==> 🌎  Go to http://localhost:%s', app.get('port'))
})

First we start with a Node.js application that includes a few routes:

/rebuild-site (both a GET and POST for convenience)
/404
/build (to keep all of our static website build files)

Next let's take a look at how the site is built.

// build-site.js
var Metalsmith = require('metalsmith')
var markdown = require('metalsmith-markdown')
var layouts = require('metalsmith-layouts')
var permalinks = require('metalsmith-permalinks')
var sass = require('metalsmith-sass')
var metalsmithPrism = require('metalsmith-prism');
var Cosmic = require('cosmicjs')
var async = require('async')
var mkdirp = require('mkdirp')
var del = require('del')
var mv = require('mv')
var createPage = require('./create-page')
var config = require('./config')
module.exports = () => {
  async.series([
    // Create build-new folder
    callback => {
      mkdirp(__dirname + '/build-new', err => {
        callback()
      })
    },
    callback => {
      Cosmic.getObjects(config.cosmicjs, (err, res) => {
        var pages = res.objects.type.pages
        var cosmic = res
        // Create dynamic static pages
        async.eachSeries(pages, (page, callbackEach) => {
          var args = {
            page: page,
            pages: pages,
            cosmic: cosmic
          }
          createPage(args, callbackEach)
        }, () => {
          // Create markdown static pages
          var year = (new Date()).getFullYear() // make your footer year dynamic ;) 
          Metalsmith(__dirname)
            .metadata({
              cosmic: cosmic,
              year: year
            })
            .source('./src')
            .destination('./build-new')
            .clean(false)
            .use(sass({
              outputDir: 'css/',
              sourceMap: true,
              sourceMapContents: true
            }))
            .use(markdown( { langPrefix: 'language-' } ))
            .use(metalsmithPrism())
            .use(permalinks())
            .use(layouts({
              engine: 'handlebars',
              partials: 'layouts/partials'
            }))
            .build((err, files) => {
              if (err) { throw err }
              callback()
            })
        })
      })
    },
    // Delete build folder
    callback => {
      del([__dirname + '/build']).then(() => {
        callback()
      })
    },
    // Move build-new to build folder
    callback => {
      mv(__dirname + '/build-new', __dirname + '/build', { mkdirp: true }, () => {
        callback()
      })
    },
    // Delete build-new folder
    callback => {
      del([__dirname + '/build-new']).then(() => {
        // done
      })
    }
  ])
}

 This file holds all the magic, let's unpack what's happening here:
1. We're using Metalsmith to build our website files.  There's other build tools for this, but this is the best one (IMO) for JavaScript-built static sites.
2. The build-new folder is created as a temporary place for our new build.  This is so we don't get any down-time from users currently on the website.
3. Next we will get all Objects in our Cosmic Bucket using the Cosmic NPM Module and method Cosmic.getObjects
4. Then we will parse from our response all Pages.  Then begin a loop to create a new static page for each Page Object.
5. Each Page Object will then be passed to Metalsmith to build our Page.
6. After Metalsmith is done Jamming out our Markup to the build-new folder, the build folder is deleted.
7. Without blinking an eye the new build folder is created with the fresh build.

And that's it!  Your Cosmic content is now available in static form in JAMstack generated HTML files.  PLUS you have access to all of your content via the Cosmic API.  Also if you need someone who's not versed in Markdown to edit content, they can easily edit content via the WYSIWYG editors in the Cosmic Dashboard.

Using Webhooks for Automatic Rebuilds

Cosmic offers a great way to automatically rebuild your JAMstack static website on every content edit with Webhooks.  Setting up webhooks is easy.  Just go to Your Bucket > Dashboard > Webhooks and set the POST to the endpoint and action of your choice. In this example, you can set your Webhook to POST to [your-app-hostname]/rebuild-site.

In Conclusion

In this article we talked about a recent rebrand of static websites (Jamming sounds a lot more fun than static website building).  We talked about how you can install a JAMstack-enabled website in a few clicks using the Cosmic Static Website App. And we showed you how to automatically rebuild your website whenever content is changed via Cosmic Webhooks.  If you have any questions, join our Slack channel and reach out on Twitter.