Assortment moves to JAMstack
With a move towards Gatsby, Emotion and Netlify, things are changing for Assortment. Here’s an overview of the platform's architecture moving forward.
By Luke Whitehouse on
Assortment is changing, big time. Whilst there's a few tweaks to the design and user experience, the biggest changes are to the architecture powering the website itself. Moving away from it's Laravel roots, Assortment has found a new home for itself in the land of JavaScript, static site generators and serverless application development.
Enter: JAMstack
After reading about the success Smashing Magazine had with their 2017 redesign onto a JAMstack architecture, and the Industry buzz about the methodology in general, I knew it'd be a great fit for Assortment.
The JAMstack represents a methodology for building websites which promotes better performance, security and scalability. As shown in the diagram above, "JAM" is split into three areas: "JavaScript", "APIs" and "Markup":
- Markup is prebuilt static HTML pages, usually created through a Static Site Generator such as Gatsby, Hugo and Jekyll;
- which is then helped along by dynamic programming from client-side JavaScript, generally through a Front-end framework such as React or Vue, but you could always use bog-standard JS.
- Finally, any server-side processing is done via abstracted services in the form of reusable APIs or hosted function platforms such as AWS Lambda and Google Cloud Functions.
Based on the way you actually use it, I guess it should be renamed MJAstack, but that's not nearly as catchy.
Site generation with Gatsby
In order to bring Assortment onto JAMstack, I opted to use Gatsby, a free and open source platform for building React applications and websites. Gastby has exploded in popularity within recent years, and for good reason. It allows you to develop your websites in the same React workflow you're used to, whilst providing all the benefits a static HTML file would have over it out of the box, namely: speed, security, hosting costs and SEO.
How does it work then? When developing your project, you'll be creating React components in combination with a GraphQL powered query system for any data you're looking to expose (be that markdown files, API calls or something completely different). For your users, they'll download a static version of your website through flat HTML files, which are then rehydrated into React components for any client side specific logic you have. This union allows you to create fully fledged applications within a static html builder. Pretty powerful stuff, and I'm sure many large organisations are going to jump on board before too long.
For an extensive list of Gatsby's capabilities, check out their features page.
Serverless deployments with Netlify
To host my newly created static site, I opted for Netlify, which has been an absolute gem to work with. Boasting an Application Delivery Network (another name for a Content Delivery Network, but for applications), distributed globally throughout the world to increase the likelihood that a user will be able to download your website from a server hosted in their country. This is a massive boost for site speed, by reducing the potential latency for your users when requesting your website's code.
Where Netlify really shines though, is the built-in Continuous Deployment workflows at your disposal. With Git integration out of the box, it was super simple to create a robust deployment strategy which triggers a gatsby build
(Gatsby's command to create your production ready code) whenever I deploy to the master
branch. I've even got Pull Requests deploying to preview environments for testing purposes too.
Whilst any deployment is in progress, the current version of my site will continue to be fully operational and will only be overridden by the new version if it is successfully built. If not, you'll have some sexy-ass logging to help you figure out what went wrong.
In addition, you can setup other services such as Slack, Emails, Github PRs and even custom webhooks to notify you when a deployment starts, succeeds or fails.
Netlify can do a whole lot more than I require for Assortment, such as deployable AWS Lambda functions (the 'a' in JAMstack, remember), managing form submissions, asset delivery and A/B testing. I'd urge you to take a look through their features page to see for yourself.
Did I mention everything I'm doing above is within their free tier package? Including hosting!
Content Management with Netlify CMS
Speaking of Netlify, let's talk about the company's open source Content Management System (CMS), aptly called Netlify CMS.
Now I'm not ashamed to admit that my content workflow on my Laravel stack was piss poor. I knew I wanted to use Markdown files, but I didn't push my lazy arse any further than parsing Markdown from a MYSQL database. This meant that any changes had to be manually uploaded from a local markdown editor. I did have every intention of creating a little admin area to automate a lot of this, but let's be honest, who's really got time for that? Needless to say, I needed a better workflow.
One of the features that intrigued me most about Netlify CMS was that it's a CMS designed to work with your Git workflow, and Markdown files.
Content is stored in your Git repository alongside your code for easier versioning, multi-channel publishing, and the option to handle content updates directly in Git.
Posts are read, saved and updated in Markdown files, allowing Git full control of not only my codebase, but my content as well. As you might imagine, this complimented my deployment workflow with Netlify splendidly. To give an example, let's say I wanted to update my "Building an accessible Modal component with React Portals: Part 1" post. Going into the admin area, I'd save my changes.
This will then automatically create a new Pull Request in Github, showing the changes to the markdown file in question.
As Netlify is setup to create Deploy Previews of Pull Requests, it'll kick in and assuming it succeeds, will give me a unique URL to test my changes. Once I'm happy, I can then merge my PR into master, kicking off the production deployment.
This is only the tip of the iceberg. With an extensible React GUI, flexible collaboration tools and config system built to tinker with, I'm looking forward to seeing what the future holds for this CMS. I'd recommend it to anyone looking for a simple CMS to blog with. Perhaps I'm in the honeymoon period, but honestly, with a bit of love I could see this being a contender with the likes of WordPress, Ghost, et al.
Trying out CSS-in-JS with Emotion
It's not just my deployment and content workflows that's seen an improvement either. As part of the redevelopment, I wanted to try out Emotion as a CSS-in-JS solution, as opposed to the BEM/ITCSS methodology I've been moulding my projects around for the last 5 years.
Now, I know CSS-in-JS is a pretty hot topic at the moment so I don't want to go too in-depth on this one, as I'll be saving that for a separate post. Instead, what I will say is that by having my own project to trial the idea of CSS-in-JS solutions, I've found it to be a real benefit to the component based architecture that React lends itself to so well. Graned, it's not without drawbacks, and it's very easy to lose what makes CSS so great. You need to be careful not to get drawn into the all-or-nothing points of view such as "CSS is crap", "You just need to learn CSS" or "The Cascade is the devil". There's a place for both, in my opinion.
As I say, I'd like to go into more detail on this in a future post, but for now, here's a nice little Button
component I created for this website.
import React from 'react';
import { Link } from 'gatsby';
import { css } from '@emotion/react';
import { baseColors } from '../../constants';
const Button = ({
children,
href = '',
onClick = () => {},
type = 'button',
isFullWidth = false,
...props
}) => {
const ButtonStyles = css`
display: ${isFullWidth ? 'block' : 'inline-block'};
padding: .5rem 1rem;
text-decoration: none;
color: ${baseColors.white};
background-color: ${baseColors.link.base};
${isFullWidth && 'text-align: center;'}
cursor: pointer;
transition: background-color .15s ease-out;
&:hover, &:focus {
background-color: ${baseColors.link.dark};
}
`;
if (href) return <Link to={href} css={ButtonStyles} {...props}>{children}</Link>;
return <button css={ButtonStyles} type={type} onClick={onClick} {...props}>{children}</button>;
};
export default Button;
A small component, with a few variations. All in one file. I think there's something pretty cool about that, regardless of how you feel about CSS-in-JS techniques. I appreciate it won't be for everyone, and as I've said, in my opinion shouldn't be an all-or-nothing solution, but I've found it a nice compliment to my CSS toolbelt, so I'll be continuing to explore it moving forward.
Less hot takes, more Performance cakes
Moving away from the hot drama in Front-end Development, let's talk performance.
New technologies are all well and good, but they shouldn't be introduced at a detriment to the performance of the website itself. Whilst I wasn't happy with a lot of things on my old Laravel platform (through nothing but neglect on my part), performance wasn't one of them. I needed to ensure that throughout this redevelopment, site speed was constantly tracked and monitored against the Laravel stack, and of course, improved where possible. Spoiler: there was a lot to improve.
To test my work, I used benchmarks from WebPageTest and Google's Lighthouse to check for any bottlenecks and issues that could arise from the new stack. They were carried out on a Nexus 5 device, using a Chrome browser on a Slow 3G connection.
For the old Laravel stack, the performance wasn't too bad at all for decent connections. The problems arose when viewing the website on a slow 3G connection due to the lack of caching, resulting in excessive server side calls and thus a poor Time to First Byte score.
You can look through the full results on the WebPageTest website, though here are some highlights:
- First View (without cache)
- Load Time: 9.482s
- First Byte: 5.198s
- First Interactive (beta): >15.102s
- Repeat View (with cache):
- Load Time: 10.142s
- First Byte: 9.151s
- First Interactive (beta): >10.926s
Interestingly, the results suggest that repeat views on slower connections are slower. This may be due to server configuration. Regardless, comparing this with the new redevelopment, and there's a stark difference.
As you can see, Netlify has given the website a major boost in performance due to it's CDN network and caching capabilities for statically generated websites. It shows in the figures too.
Once again, you can take a look through the full results on the WebPageTest website, though here's the highlights:
- First View (without cache)
- Load Time: 8.253s (12% improvement)
- First Byte: 1.945s (62% improvement)
- First Interactive (beta): 2.597s (82% improvement)
- Repeat View (with cache)
- Load Time: 5.240s (48% improvement)
- First Byte: 1.803s (80% improvement)
- First Interactive (beta): >3.480s (68% improvement)
Not only is the site much quicker to load on first render, but the addition of a Application Delivery Network and the caching of static content thanks to Netlify means repeat visits for users are that much quicker. Getting in under that 3 second mark for First Interactive of a user's first visit using a slow 3G connection is a win in my book.
Bear in mind, Assortment is a pretty simple website. Imagine the performance boosts you could get on more complicated application.
Becoming a Progressive Web App
That's not the only area Assortment has seen performance improvements in either.
In today's day and age there are so many ways to consume content online, but what about offline? With the dominance of mobile devices and on-the-go browsing, the chances of someone coming to Assortment with a spotty wifi connection are pretty high. I wanted to ensure that Assortment can still surface at least a partial experience for those users. Nobody expects an error page when you go offline on a native mobile app, so we shouldn't allow that to be an excuse on the web either.
That's why I'm pleased to say Assortment now meets all the baseline criteria set out by Google's Lighthouse tool to be classified as a Progressive Web App.
Not only does this confirm I have offline support, but it also ensures: you are able to save the website to your home screen on a mobile device; the website is responsive as you'd expect in 2019, and it meets the minimum page speed on slower networks.
Performance is, and always will be, a moving target. As you can see from the list above, there's a lot that can still be done, including that annoying PWA warning you can see in the image above about viewport size differing to the window size (give me a shout if you've got any ideas). That being said, I'm pleased with the results so far, and will continue to aim for further performance improvements with the likes of caching and taking the rendering off the main thread. More on that at a later date.
Costs and thoughts
Before moving onto the JAMstack, Assortment was hosted on a custom built Digital Ocean droplet costing roughly £15p/m all said and done. I then had to install my own LAMP stack, build my own deployment process with Capistrano and setup my writing workflow (or lack thereof).
Comparing that to now, where I have the power of a global CDN, a Git based deployment process that supports deploy previews, DNS management, hosting and SSL certificates, all for free thanks to Netlify. I've got an improved development workflow thanks to Gatsby, allowing me to build my application with the latest techniques in Front-end Development thanks to React and GraphQL, whilst still benefiting from static deployables to increase page speed and simplify caching requirements. Thanks to Netlify CMS, I've finally got around to creating a writing workflow that I can be proud of. One which allows me the flexibility to write in Markdown, or in a Rich Text Editor, but ultimately utilising Git for version control and content publishing, hooking in with my deployment workflow above. I've even had time to update the website itself, getting a few visual improvements and finally adding in Site Search thanks to Lunr.js. All in all, I'm a happy bunny.
My hope with this post is that it spurs you on to create your own JAMstack application, maybe even rewrite some of your current applications whilst you're at it. From my time working with Gatsby and Netlify I can honestly say I've not enjoyed web development this much in a long time, and I'm sure you'll feel the same way. Give JAMstack a try, you won't regret it.
If you have any questions on anything I've wrote in this post, on JAMstack; Gatsby, Netlify or Netlify CMS then fire me over a tweet on @assortmentio.
Until next time 🍓