This may get a little technical, but hey that’s probably why you’re here!
Minafi started as a regular blog in WordPress (the .org version – the one you download and host somewhere). Initially, I hosted Minafi over on Dreamhost, since it’s free to have a bunch of sites and my wife hosts her blog there.
Over time I changed things around, tried a bunch of other hosts and themes, but never was able to customize WordPress quite the way I wanted to. It’s possible, for sure, but I was constantly battling WordPress.
In December of 2018, I left my job to retire early. After a career as a dev manager, full-stack web developer, and product manager I knew I wanted to do something fun with Minafi – which led to a somewhat ambitious plan to overhaul the entire site to what you see today.
It’s nowhere near done, but it’s now possible to iterate on in ways that were previously out of the question. Here’s a look at the tech behind the scenes.
My background as a developer is in full-stack web development, with a leaning towards Ruby on Rails for the back-end and Vue.js for the front-end.
At a high level, the site works like this:
The main site, which you’re viewing now is a Ruby on Rails application. It connects with a WordPress server via a REST API to pull in posts, pages, categories tags, affiliate links and store them in a Postgres database that Rails uses.
From the Rails side, every page is a Vue.js application with minimal interactivity (ex: dropdowns in menus, activity badge, progress). Pages like the interactive guide, or custom calculators, use Vue.js more, but any page on the site has access to that same functionality. Rails uses Webpacker to organize and serve up JS after tree shaking and compiling it.
For styling, the site uses Tailwind.css with Font Awesome SVG icons. PurgeCSS is used behind the scenes to slim down the size of the CSS files.
Hosting for the WordPress app doesn’t matter too much since it’s not accessed by end users. It’s currently on WP Engine, but I plan to move it off there soon. The Rails app is hosted on Heroku. Eventually I’ll move it over to Digital Ocean to cut costs, but for now, it makes things much easier despite the higher price tag.
With that in mind, I iterated to a tech stack that includes them and a few other pieces:
Ruby on Rails
The page you’re reading now, and everything on the minfi.com/* domain is served from Ruby on Rails. It’s a custom app that handles everything from user registrations and sign-ups to comment and news notifications and more.
- Sidekiq for background jobs (emails, syncing, etc)
- Devise for auth (including social logins and guest users)
- Memcache for optimized partial caching across pages
The Rails app is relatively small but will be the main piece that grows over time. I’ve been getting back up to speed on Rails by watching some great videos over at GoRails.
There is a 2nd site that visitors of Minafi can’t see (it’s hosted on a subdomain) that hosts the Minafi WordPress instance. All posts and almost all content (with the exception of the Interactive FIRE Guide and FIRE in the News) are all created as WordPress posts or pages.
There is a rake task on the Rails side that goes and hits the WordPress app to grab all posts and cache them in the Rails database. This means that if WordPress were to go down, end users of Minafi wouldn’t know (unless it were down long enough to impact new posts).
This WordPress installation is mostly accessed using the WordPress REST API from the Ruby on Rails site. This API is amazing and allows for getting any data needed.
There aren’t too many plugins being used on the WordPress side either since Rails is handling the bulk of the work. There are a few that are useful though including:
- Coschedule – Set social media posts automatically
- Pretty Links – Affiliate link tracking
- Social Warfare – Tracks social media shares
- Wp Offload Media – Save all uploaded media to a CDN.
- Tablepress – Create tables of data easily
- WP Review – Easily review products
- Elementor – Reusable components across posts
There’s a lot of concerns you have to figure out when you leave WordPress. I wouldn’t recommend it to anyone who isn’t OCD about this stuff because it’s a lot of work.
I’ve tried just about every CSS framework out there. Bootstrap, Foundation, Bulma, Material Design – but from a project-wide code level I think Tailwind has been the cleanest. It’s a utility CSS framework, which means you write very little CSS and instead apply a lot of classes to your HTML.
While that may seem like more work than adding a class of “card” and letting Bootstrap do its thing, it allows for a level of organization and CSS maintenance that’s far easier than anything else I’ve tried.
The CSS file for this site is a whole 12.5k as of this writing – with another 24k for all of the icons (which are all SVG icons).
I backed the Font Awesome Kickstarter a few years back and have been a fan even longer. They have a few ways of using their huge library. The easiest way is to include a CSS file that then grabs every icon in the library.
I went another route and downloaded every SVG icon and created my own icons file that is then referenced everywhere using this approach.
There are a few icons that are included in CSS as well that are hardcoded in there.
Programming with Vue.js has been so much fun. Being able to create a component then just drop it in anywhere and reuse it is great. I’m using the WordPress Elementor plugin to create little reusable widgets that are themselves Vue.js components. That allows for controlling the code in one place, but reusing it across the site.
I’m not using that many JS libraries with Vue.js either. Vuex is used for data, Axios for making server calls, a v-tooltip library that I didn’t want to write myself, lodash for a few things, numeral.js for some number formatting, autonumeric for better input fields and a few others. Most everything else is custom.
Various little parts of Minafi are Vue.js components. For example:
- Activity Badge – The little badge that tracks if you’ve read a post.
- Progress Bar – The bar at the top of the page that tracks how far you are.
- Comment Form – The whole comment process uses Vue, which allows for a faster commenting experience.
- Dropdown / Menu – The dropdowns and the responsive menu are both Vue.js components.
- Social Shares – The left side over there is it’s own widget.
The common thread here is that if something is an enhancement it can use vue. If it’s a core part of the page – like the content, the nav, etc – then its rendered by Rails.
I love d3.js. It’s a data visualization library with an extremely high learning curve. It took me months of research on it to be able to build something as simple as a bar graph.
The Interactive Guide uses it for its graphs, and I have hops to creating more visualizations using it. If you just want to create a few graphs I wouldn’t recommend d3.js. It’s complete overkill unless you’re planning on creating unique visualizations from scratch.
Clicking around Minafi you’ll notice that the pages load very fast. One reason for this is because of Turbolinks. This is an approach to loading pages, where the DOM is maintained across requests but overwritten with the new page navigated to.
The user will see the URLs change as they click around and if they refresh the page they’ll see the same thing.
What I like about this approach is that I can create individual pages that render on the server – an important part of SEO – but get the benefit of a fast-loading client application.
But Why Though?
The reason to go this route rather than the typical WordPress route might be tough to explain. The single biggest reason is information architecture.
Information architecture is a fancy word for how your pages connect with each other. In the WordPress world, this typically means creating a nice nav then including widget sidebars on each page.
After years of working on learning products at startups, I wanted to take that a step further and try to deeply connect subjects in ways that would be harder in WordPress. For example:
- Organizing posts and articles into courses.
- Autolinking in posts to keywords, funds and other things.
- Embedding interactive components throughout, not just in specific posts.
- Being able to tailor a user experience to a user based on their activity
- Tracking progress in courses, in future interactive posts and more.
That last one is a big one. If someone is a frequent visitor here, I don’t want to bombard them with email sign up forms, ads, login forms or other CTA’s. Instead I want to give them what they came here for so they can get on with their day.
By creating a registration system and moving everything to Rails, that opens up a bunch of options that I’m excited to explore!