DEV Community

Cover image for Creating my JAM-stack site
Alex Edwards
Alex Edwards

Posted on

Creating my JAM-stack site

*Cover Picture by David Trivis on Unsplash


For the past two weeks, I've neglected to contribute to Dev because I've been hard at work trying to combine the tools I've learnt over the past month or two: Typescript, and Test-Driven-Development.

Since arriving back in the UK in September, I've been studying React, and it's various stacks ready to transition into a front end development job, and since Covid-19 landed early this year, I've been studying more and more. However, what's the point in studying if you don't put it to practice!


The Project Description:

Create a JAM-stack website utilising GatsbyJS (React), Typescript, and a CMS such as NetlifyCMS or ContentfulCMS.

Why Gatsby? Well, React is excellent, but with SPA (Single Page Applications), SEO and page speed can be a caveat. The way Gatsby overcomes this is to create static pages and then loads React in afterwards. That way, pages load quickly and accurately, and you still gain the advantages of a SPA.

Why a CMS? With Gatsby's incremental builds in Beta on Netlify, it can drastically increase build times for sites that have a lot of pages to render.

Typescript and TDD are the two aspects I've learnt recently, and that was the primary practice for the project. I've learnt to embrace Typescript with open arms; however, working with libraries can be difficult if they don't have Type declaration or feature it in their documents. It's mostly mitigated these days with the DefinitelyTyped project. And with TDD the idea is that you write tests (that initially fail) as a blueprint of the code, and later write code that fits within passing the tests. This way, you're not testing implementation, but you're testing how that particular function, class, or component will interact.

The Setup:

gatsby new new-starter https://github.com/lexedwards/starter-cypr-jest-ts

This starter was something of a bi-product of working with Gatsby. Once all the environment variables were in place, I saved it in another repo to use time and time again. It has Jest, Cypress, and Typescript fully supported, nothing more, nothing less. Since Gatsby uses a lot of configs under the hood, I imported my configs and tweaked them to get everything working together nicely. Partly workflow (Husky for Git hooks etc.) and somewhat getting Jest and Cypress working correctly together (Instrumentation injection for Cypress Code-Coverage)

The Content:

First hearing about Incremental Builds from Gatsby Cloud, later reading about it from a Netlify email, in beta. However, it's a significant change as with SSG (Static Site Generators) the major complaint is how slow build time can be. Hugo has gained massive momentum for how quick it's build time is. As of this time, only a handle of CMS' are supported, and that's what pushed me to use Contentful, including the option of writing markdown files within the Repo and importing them using Gatbsy.

Developer friendly, but with one pitfall, I couldn't quite get the Gatsby Contentful plugin to play nice with MDX. So, instead, I'm using Markdown with Remark-Rehype to convert to React Components rather than pure HTML. This way, if I wanted a component in my markdown, I would be able to write:

<my-custom-component></my-custom-component>

It's slightly different, however, having spent a day experimenting with Contentful and MDX with no avail, it's better than nothing.

One thing to note: With the Markdown on a CMS, there's no tie to what are valid components and so manual checking on the CMS would still be required. Rich-text might be an option here, but it's processing would be done by Contentful rather than Remark.

A TDD story:

It's all fun and games following tutorials, some of which I've followed in different forms, but first starting I had to remind myself so much to write tests first! It was a bit of a grind, to begin with, metaphorically slapping my wrists for diving into new components, however, a week later, writing unit tests was a dream for development as I was setting the behaviour and expectation before even thinking about tackling the problem. I'm still slightly nieve to how best to write tests, but the more I do it, the more I understand what's gaining better confidence.

test("Errrrrrr, I'm not too sure", () => {
  const {container} = render(<Component />)
  expect(container).ToBe('I don't know, that it exists?!')
})

Kent C Dodds' course was great for this, as this is my project, I've set the standard that my coverage of tests is allowed to be less than 100%. Testing Templates and Pages pool from components are End-To-End. Testing components as interacted with rather than implemented. Functions also, I don't need to know the function is adding 1 + 1 in a particular way, just that the result is deterministic and always equal 2.

describe('Navigate the Default Pages', () => {
  beforeEach(() => {
    cy.visit('/')
    cy.injectAxe()
  })

  it('Has no A11y Violations', () => {
    cy.checkA11y(null, {
      runOnly: {
        type: 'tag',
        values: ['wcag2a'],
      },
    })
  })

  it('Has Navigation', () => {
    cy.findByRole('navigation')
      .findByText(/about/i)
      .click()
    cy.findByRole('navigation')
      .findByText(/say hello/i)
      .click()
    cy.findAllByRole('heading')
      .findByText(/alex edwards/i)
      .click()
  })
})

*Test taken from my E2E test on my Index page


This post is an ongoing series along with my site development. All current process on my website and in the open-source repo is open for review. As I publish new features (Posts and Projects templates, changes in style), I'll continue to add to this series as a reflection of what I've learnt, and what reflections I have on the process.

Top comments (0)