Creating an Isomorphic/Universal website with React — part 1

If you are a developer, creating your own website should be an easy task, shouldn’t it?

So you start thinking, I can just use Wordpress, a theme and a bunch of plugins and I’ll be ok, FOREVER❤!

But after few seconds of excitement, the compulsive optimizer and performance nazi in you says: “Wordpress can be overkill for a personal portfolio…. Are you sure you want to have a database even if your website won’t be that dynamic?… Aren’t you afraid of possible vulnerabilities in the version of wordpress you’re using?”

So… that’s why you’re here…


This post is the first of a series that will guide you in the creation of an Isomorphic website with React. Actually, we are going to create MY website.

Features

  • Isomorphism
  • Static build, plain HTML.
  • File based “database”
  • Fully featured, Url-friendly navigation
  • and much much

Check the live demo here http://michaelcereda.com

or the source-code https://github.com/MichaelCereda/michaelcereda.com

Tools Used

I decided to use gatsby over a vanilla webpack configuration because gatsby already pre-packs a lot of cool features that will make our job easier both during development and during build.

Golden rules of an Isomorphic Application

When you start creating an isomorphic application you should remember that:

  • window doesn’t exists on server-side so, don’t put it in your render() method, if you do you will see the typical
ReferenceError: window is not defined
  • ReactDOM.findDOMNode has to be used outside the render() method or react will trigger an error/warning. Don’t use it unless you need to obtain “data” from the real DOM node.
  • Think that the first rendering cycle will be on your server.

Let’s get Started

After installing gatsby and creating a new website (please refer at the official gatsby readme file) and adding few folders we will find ourselves with the following structure.

MichaelCereda.com
|- components / Our react components will sit here
|- css / Stylesheets, oh yeah
|- loaders / Gatsby loaders
|- pages / Website pages
|- assets / Static Assets
|- *.md / Bunch of Markdown pages ...
|- utils / various utilities
|- wrappers / Gatsby wrappers

Please check the source code for the full project structure

Open your favorite terminal and type

gatsby develop

to start a gatsby/webpack server.

Website design

I decided to create a mono page website with the viewport split in two. When the user scrolls the webpage the left column will remain static while the left column will scroll.

In order to obtain this effect I had to understand how gatsby works, so I started a debugging session and discovered that, everything the developer puts in /pages ends up in an object passed as prop (props.route.pages) to the index page.

props.route.pages:[
0:Object,1:Object,2:Object,3:Object,4:Object,
...
]

That’s great, but props.route.pages contains an array that is not the best fit if you want to create a mono-page design.

Refactoring Gatsby data Flow

So I added the following code in the index page

/pages/index.js
var _ = require('lodash');
export default class Index extends React.Component {
constructor(props){
super(props);
  this.pageGroups = _.groupBy(props.route.pages, ‘file.dirname’);
this.pageGroups.root =
_.mapValues(_.groupBy(this.pageGroups[“”], “file.name”),
arr => arr[0]);

delete this.pageGroups[“”];
}

Now we have an additional attribute that will contain a hierarchical structure with all our pages.

this.pageGroups: {
projects:[0:Object,1:Object,2:Object]
root:{
404:Object,
about_me:Object,
contact:Object,
index:Object,
intro:Object
}
}

So I can create a fantastic “sitemap” with all the sections and the props I want to pass to the respective component.

let sitemap = [
{
section: ‘home’,
component: <MainSlider
{… this.state }
className=’color-one’
icon=’home’
{…this.pageGroups.root.intro.data}/>
},
{
section: ‘projects’,
component: <ProjectList
icon=’energy’
className=’color-two projects’
{… this.state }
projects={this.pageGroups.projects}
onProjectOpen={this.handleSectionOpen.bind(this)}/>
},
....
];

In the next part, I will show how I created the design and the navigation system