How I built a Content Management System for a React app in one day

Written by lilychendances | Published 2017/09/16
Tech Story Tags: react | firebase | software-engineering | software-development | front-end-development

TLDRvia the TL;DR App

DYI content management system with Firebase & React

Firebase + React = Quick DIY CMS

There are two ways of handling website content:

  1. Use a CMS.
  2. Hard code in the copy/image urls in the code itself.

Option number 2 is quicker at first, and is fine for an early stage startup operating in one country. However, two big problems will surface and grow as companies scale.

In fact, I have personally experienced multiple times the first of these two problems at work.

Problem 1: time wasted by engineer

Every time there needs to be a content change, the product team would need to ping an engineer, and the engineer would in turn need to:

  1. stop what they’re doing
  2. dig into the code
  3. change the copy
  4. create a pull request
  5. have the PR reviewed
  6. merge to master
  7. deploy

This whole process takes at best half an hour to forty-five minutes. However, the opportunity cost is much more because the engineer could have spent that time on more important tasks.

Wouldn’t it be amazing if changing copy is instantaneous instead?

Problem 2: internationalization

Website can only be displayed in English if the English copy is hard-coded in. This will definitely be a problem if the company ever goes international in non-English speaking countries.

Solution

The solution to these two problems is a good content management system.

Pillow, where I’m currently working, had a Hackathon last week. The theme was productivity. I thought that building a CMS to solve problem number 1 would make both the product and the engineering team more productive.

Additionally, I wanted my CMS to not only solve problem number 1, but to also offer a way of handling problem number 2 in the future.

A day? Yup, that’s all it takes to set up a simple and effective CMS.

Technology: React + Firebase

Firebase is a real-time NoSQL cloud-hosted database. Anyone can signup for an account with their gmail, create a project, and add data to the database.

Because of the NoSQL structure, I thought it would be a great way to store website copy. This is what I did to structure Pillow’s landing page copy during the Hackathon:

Screenshot of json data structure

Pillow’s website is already built with React, and that made my job a lot easier.

All I needed to do on that front is install re-base, set up some configuration, and replace the hard copies. re-base is an npm package that offers handy methods to easily sync data with Firebase. The repo has good set up documentation, so I won’t go into too much detail here.

I used the listenTo function to sync with Firebase. Then, I used dispatch to load the data into the state. Thus,re-base works well with Redux.

componentWillMount() {const { dispatch } = this.props

base.listenTo('en', {  
  context: this,  
  then(copies) {  
    dispatch( loadCopies( language, copies ) )  
  },  
  onFailure(error) {  
    console.log('error', error)  
  }  
})  

}

My loadCopies action calls a reducer to return a new state with the copy loaded.

In the render method of my component, I used the copy stored in the state rather than anything hard coded in.

I also built a separate Rails app with an UI for editing Firebase data. This CMS is thus completely separate from the main app, preventing the main app from becoming an even bigger monolith.

Screenshot of my Rails app for editing content

Once again, I used React and re-base for handling Firebase sync.

componentWillMount() {const that = thisfirebase.auth().signInWithPopup(provider).then(function(result) {

const user = result.user

if (user.email.indexOf('[@pillow](http://twitter.com/pillow "Twitter profile for @pillow").com') > -1) {  
   base.syncState(EN, {  
      context: that,  
      state: EN,  
      onFailure(error) {  
        console.log('error', error)  
      }  
    })

    base.syncState(FR, {  
      context: that,  
      state: FR,  
      onFailure(error) {  
        console.log('error', error)  
      }  
    })  
  }  
}).catch(function(error) {  
  // Handle Errors here.  
  console.log("ERROR", error)  
})

(Please forgive some of the “hackiness” here, I did do this in one work day.)

syncState function is a “two-way street.” It listens to changes in Firebase, which then update the state of the component. If the component state gets updated (by this.setState for instance), the change gets synced to Firebase automatically.

In my Firebase editor app, each value stored inside Firebase is displayed within a textarea. Thus, this whole DOM structure is dynamically generated based on Firebase data. When the value within a textarea changes, it triggers a change in the component’s state, which in turn updates the database.

In summary, this is what the CMS logic looks like:

Check out my mad powerpoint skill

Watch the screen recording of my CMS at work:

https://www.youtube.com/watch?v=SNDvfpr3r1s

Now, you may ask, why did I build my own CMS?

There’s no magic reason really, I did it because:

  1. Minimal effort is needed to make it work with our existing setup, a React front-end web app.
  2. There’s no need for third party service.
  3. It’s free and free is good. Technically, Firebase is free for 1GB of data, but I’d love to see the day when Pillow has more than 1GB of text on the website.
  4. And lastly, I simply thought it would be a great learning opportunity. And it certainly was!

If you like this story, give me some claps! :)


Published by HackerNoon on 2017/09/16