Nuxt.js freelance project for Operations Manager in Events Industry

Visit project website

Building things for other people has always been a motivator for me. Reframing a problem from “I wonder if this will work?” to “this needs to work, now” can change 6 hours of pointless noodling into solid action.

Reframing a problem from “I wonder if this will work?” to “this needs to work, now” can change 6 hours of pointless noodling into solid action.

At the start of this project, I knew there were some key ideas I still needed to get down. Namely: state management, Nuxt.js and setting up a headless-CMS “the right way”.

Having spent several months with these concepts on my todo list, I set myself a 1 week timeframe for this project. Rather than fall back on any technologies I’d used before, I went out and asked some developers what they would recommend.

This was the list they helped me put together:

  • DatoCMS for content
  • GraphQL for API queries
  • Nuxt.js for server-side rendering
  • VueX for state management
  • Vercel/now for hosting

Having already completed 50% of the work in vanilla Vue by the time Nuxt.js was floated, I ended up having to port the existing build.

Whereas previous projects tended to make smaller API calls in each component, this was my first experience creating a single data store.

By injecting an $apiRequest plugin straight into the app’s Context, I could pass GraphQL queries directly from the store - where I dispatched a series of “fetch and set” promises (which called the individual state modules) from a nuxtServerInit hook.

The main api.js plugin:

Here all the API logic is wrapped up neatly. The GraphQL Request package lets me connect with endpoints and send queries from one function.

import { GraphQLClient } from 'graphql-request'

export default ({ app }, inject) => {
  inject('apiRequest', ({ query, variables, preview }) => {
    const endpoint = preview
      ? 'https://graphql.datocms.com/preview'
      : 'https://graphql.datocms.com/'

    const client = new GraphQLClient(endpoint, {
      headers: {
        authorization: `Bearer ${process.env.DATOCMS_API_TOKEN}`
      }
    })

    return client.request(query, variables)
  })
}

The main store/index.js file:

This was a new one for me. Having started learning about object destructuring recently, I was interested to see how destructuring a function’s argument gives us direct access to Context’s properties.

nuxtServerInit is useful as it runs once at the start of server-side rendering, meaning you can pre-populate your stores with data before the client has to build the site.

export const actions = {
  nuxtServerInit ({ dispatch }) {
    return Promise.all([
      dispatch('navigation/fetchAndSet'),
      dispatch('pages/fetchAndSet'),
      dispatch('contentblocks/fetchAndSet')
    ])
  }
}

Example of a store/module file:

export const state = () => ({
  contentblocks: []
})

export const mutations = {
  set (state, apiData) {
    state.contentblocks = apiData
  }
}

export const actions = {
  async fetchAndSet ({ commit }) {
    const apiData = await this.$apiRequest({
      query: `
        query {
          allContentblocks {
            title
            content
            image {
              id
              url
            }
          }
        }
      `
    })

    commit('set', apiData)
  }
}

This might be a rather simplistic way to use state management

This might be a rather simplistic way to use state management (as a glorified data store), but I really loved the freedom it gave me to work with the data.

In previously projects, I've been writing API requests in components - passing limits and filters in those calls. Now the data is pre-loaded. I can whittle it down as needed.

I used this project to solidify my ideas

In terms of the design, I used this project to solidify my ideas. I think I’d always been reaching for a design like this, but could never get the colour scheme right.

Having worked with the client previously, I knew her as an approachable, sharp and diligent operations manager. I tried to inject the designs with as much warmth as possible, rounding out some of the more clinical aspects using rounded edges and a warmer pastel colour scheme.