Building the new Eaton Works website

Eaton

Welcome to the new Eaton Works website! This significant redesign has been in the works for some time and should fully resolve the performance issues that plagued the old version while also bringing a fresh new look. The last redesign was launched in May 2011, more than 10 years ago. Many different technologies were evaluated before settling on a combination that I deemed satisfactory and cost effective. Read on for more details about the site’s new tech stack and why certain decisions were made.

Hosting

Old: Everleap Reserved Cloud Server

New: Cloudflare Workers Sites

WordPress performance on Everleap servers is not satisfactory and upgrading PHP versions did not improve the situation, nor did uninstalling WordPress plugins. It would take up to 10 seconds to simply load the wp-admin dashboard. Authoring content and updating plugins became a chore and sometimes ran into timeout errors. A WordPress caching plugin (WP Rocket) made things better for public-facing content, but page load times were still in the hundreds of milliseconds. The goal of this redesign was to cut that down as much as possible, ideally to the low tens of milliseconds. Google recommends less than 200 milliseconds.

The first hosting alternative evaluated was Vultr, a VPS and dedicated server provider. I wanted to see if I could make things faster by setting up my own VPS. After fine-tuning an IIS PHP WordPress setup*, significant performance increases were achieved. The “fine-tuning” was basically going through every option in php.ini and IIS’ config files to ensure every setting worked in favor of the WordPress site. The performance problems were effectively solved, but it also brought new burdens of keeping the server up to date, and also managing a MySQL server and PHP installation. I ended up not hosting the site on Vultr, but I want to give credit to their amazing platform and support team. Their products are excellent, priced well ($24/month for the VPS I wanted), and support tickets were sometimes answered within minutes.

The next hosting alternative evaluated was Cloudflare Workers Sites. Cloudflare has been coming out with genuinely exciting features the past few years, and their Workers platform allows you to run code at the edge, closest to users. Workers Sites essentially serves your content from their edge PoPs, eliminating the need for your own origin server. This was extremely attractive to me because the actual site would be hosted very close to users, in hundreds of Cloudflare PoPs around the world. Since this site is basically a static site and everything can be cached, this proved to be the perfect fit.

There are other static site hosting services, such as GitHub Pages and Netlify, but nothing really comes close to Cloudflare’s network coverage.

*Why WordPress and PHP on IIS? Linux was never viable for .NET Framework server applications, which powered some internal website features for projects, such as licensing, updates, and order processing. As a result, Linux hosting was never seriously considered. This has changed in recent years with the introduction of the cross-platform .NET Core, but by that time I had already decided to eliminate a server from the new website setup. The .NET code in production today is now hosted separately on Google Cloud Platform (more on that in the Backend APIs section below).

Blog/Content Platform

Old: WordPress

New: Eleventy + WordPress

The site has run on WordPress since the very beginning (2010). The initial plan was to completely ditch WordPress in order to eliminate PHP and MySQL dependencies. I liked the WordPress authoring experience, but not having to maintain a PHP and MySQL server install was very appealing. I could export all posts to raw HTML and just serve them as part of the new static site.

Aside from the WordPress posts, the plan for the rest of the site (header, project pages, etc) was to craft them in raw HTML, CSS, and JS (where necessary).

The first attempt at the new site project was done in Angular. Angular was very enticing because it was a “batteries included” framework that set up everything for you, and I wanted to learn something new to further broaden my web skills. After working with Angular for a while, I realized that the site didn’t really benefit from being an SPA, and the download size for bundle files was rather large. There was also very little true JavaScript/TypeScript code, so I decided to drop Angular and just build a static site consisting of raw HTML, CSS, and little JS where it was needed. One of my chief complaints was how hard it was to set up a proper “404 Not Found” page in an SPA. It was easy to show people a not found page through an Angular wildcard route, but getting a proper HTTP 404 server response was tricky and that was one of the final frustrations that led me to abandon Angular for this project.

After deciding to not proceed with Angular for this project, I quickly realized I needed some sort of static site generator to make it easy to apply my header to various other pages. I looked at Jekyll, but didn’t want to have to install Ruby to use it. I had also heard of Next.js, Gatsby, and Nuxt, but they weren’t appealing for this project since they are just alternative JavaScript frameworks (vanilla JS for now, please!) I came across Jamstack.org and it had a list of popular static site generators. Eleventy stuck out to me because it had a lot of template options, was written in plain JavaScript (no dependencies), had great documentation, and wasn’t another JavaScript framework. I hadn’t heard of Eleventy before seeing it there. Reading over its documentation, I realized how much this would help with the site. It did exactly what I needed with layouts and offered native pagination support. I recreated the site using Eleventy and it was a perfect fit. Its feature set (pagination, layouts, front matter, etc) provided everything I needed. The site was finally starting to come together. Props to @zachleat for making an amazing static site generator. I am so satisfied with how well Eleventy worked for this project that I contributed $100 to support it.

Eleventy made it easy to put the site together, but it didn’t make it any easier to write new posts. After some searching, I came across this article, which was instrumental in solving the problem. Instead of ditching WordPress entirely, the old WordPress site would be converted into a staging site, and when the new site gets built, it would download the WordPress post data from the staging site and Eleventy would build posts from the data. It also solved the content authoring issue – instead of writing new posts in raw HTML, I can write a post on the staging site’s WordPress editor and just rebuild the site to download the new post’s data, and then publish the updated site. The only outstanding question is where the staging site will be hosted. At the time of writing, I haven’t come up with a good solution. For now it’ll stay on Everleap and won’t be publicly accessible. This section will be updated in the future once a satisfactory solution is found.

Images

Old: wp-content upload

New: Cloudflare Images, Cloudflare Workers KV

Some images were uploaded via the WordPress uploader and hosted on the server’s file system. These images were relocated to 2 places:

  1. Cloudflare Images – images used in posts were moved here. The Cloudflare dashboard has a simple upload area that can be used to easily upload new images to be used in future posts. Powered by the Cloudflare CDN, images served from here are quick to download, and will also download in a modern image format, such as WebP or AVIF.
  2. Cloudflare Workers KV – images used to construct primary areas of the website, like project and service pages, are uploaded here as part of the site’s build process. Workers Sites uses Workers KV to store content, such as images and HTML files. A single source image is processed into AVIF, WebP, and PNG formats. These 3 formats ensure the image can be viewed in any browser while also giving up-to-date browsers the option of utilizing newer formats that are smaller in (byte) size and faster for the browser to decode & render. Image processing is done during the site’s build process using eleventy-img – another part of the Eleventy ecosystem that is excellent.

Depending on the image formats your browser supports, you will see either AVIF, WebP, or PNG images. Also, I am keeping my eye on JPEG XL for the future!

Unfortunately there are a lot of externally linked images that have since died. From now on there will be an effort to reduce externally linked images so posts don’t lose essential content when other websites out of my control change or go down.

CSS

Old: CSS written by the WordPress theme creator

New: Custom CSS written with Tailwind

Experience with Angular made me a fan of SASS. I really liked partials, mixins, and other features it brought in. After moving to Eleventy, I added SASS to the build pipeline so I could author SASS for the site. I was happy with the setup, but then I stumbled on Tailwind.

Tailwind made writing CSS even easier by moving it all into inline classes. This has been controversial in the web community, and my main complaint is how some classes can take up significant horizontal screen space. For the most part, it made writing CSS easier. If I wanted to make a div wide, I could just add a class like w-32 to it. This eliminated the need to switch over to a CSS file and add a width property there. Most importantly, I didn’t need to think of an id for the div element!

There was weeks of back and forth between SASS and Tailwind. I had 2 site projects that I was jumping between in an effort to determine whether I wanted to choose SASS or Tailwind. SASS is appealing because I had full control over everything, but it doesn’t have the ease-of-use that Tailwind has. Tailwind has a bunch of utility classes ready to go, and it ensures you make consistent design choices throughout the website. I eventually settled on Tailwind because it was generally helped me build pages faster – I liked seeing content and styling in 1 place.

The site is also fully optimized for mobile, and even has a dark mode that syncs with your device’s setting.

Caching

Old: No formal setup/customizations

New: Fully tailored customization with cache busting

The old site had no caching customizations outside of any defaults set by IIS and WordPress. The new site takes full advantage of the HTTP Cache-Control header, and some of its more modern features, such as immutable.

The primary goal of this new site was to improve performance, and caching is a key part of that. A lot of time was spent researching the best Cache-Control setup for various resources, and ensuring a proper cache-busting setup was in place so any updated content would always download to visitors’ browsers without needing to clear caches.

HTML content is served with a Cache-Control header of no-cache, which means that the returned response can’t be used to satisfy a subsequent request to the same URL without first checking with the server if the response has changed (using the ETag). When publishing a new site version, updated HTML content will receive a new ETag, and visitors’ browsers will download the new page.

All other requested assets, like images, have a Cache-Control max-age of 1 year and immutable, which means that the browser won’t make another request for them until 1 year has passed (using the ETag). For these assets, a cache-busting query param is added. In this case, it’s just a CRC of the file’s contents, so whenever it changes, the browser will redownload it. The CRCs are calculated as part of the Eleventy build process, and added to the hrefs inside HTML of pages that reference the asset.

Security

The main security improvement was the removal of WordPress and its plugins. Without WordPress and plugins, the attack surface has been dramatically reduced. The site scores well in security scanners as well:

SSL Labs’ SSL Server Test – November 15, 2021
securityheaders.com Test – November 15, 2021

Backend APIs

Old: .NET Framework ASMX services hosted on-server, Everleap MS SQL database

New: ServiceStack .NET Web API hosted on Google Cloud Run, Google Cloud Firestore database

ASMX web services are ancient at this point and it was past time to modernize that code. I decided to use ServiceStack to create an API that my apps could use, and then host it on Google Cloud Run. I decided on Google Cloud Run because it lets you deploy a containerized version of your .NET app – without needing to configure a server. Cloud Run handles all that behind the scenes, alleviating a significant burden and that alone sold me on the Cloud Run product.

Cloudflare has stated that a lot of developers are moving their entire backend to Workers in order to take advantage of compute as close to users as possible. That is enticing, but at this time I prefer to have API code written in .NET/C#, which is not something Cloudflare Workers supports right now. It also lacks a true database option akin to MySQL and MS SQL. With the rate the Workers platform has been evolving, there is certainly a chance I may move the API from Google Cloud Run to Workers in the future.

Miscellaneous

There’s a few other modern features that have been implemented into the new site that are worth mentioning:

Wrapping Up

It was a long, multi-year journey getting to this point where I could finally call eaton-works.com my own custom-made website. I am very pleased with the results. It’s much faster, more maintainable, and includes new features like dark mode. This same setup will also be applied to fatxplorer.eaton-works.com. There is also some new content available on the new site that wasn’t there on the old, such as details on my old MW2 lobby services and various old/new projects that are fully documented and downloadable – all in 1 place.

I hope this documentation of my journey will also help others plan out their future websites! If you have any questions or feedback, the comments are open below!