How I Built My Personal Website
Mat Jones
Posted on January 22, 2021
I had a lot of fun building my personal site, because I used it as an opportunity to learn some new tech. Let's take a tour of what's in it.
Core
At it's core, the site is powered by Next.js and React. I used Next.js because the content is mostly static, which is a use-case Next excels at. Next enables Server Side Rendering (SSR) by default, but also supports Server Side Generation (SSG), which generates static HTML pages at build time. You can read more about the differences between SSR and SSG in this great article by the Vercel team.
Code Style
In the project, I used React functional components with hooks almost exclusively because I find I can write much cleaner and more concise components using the hooks API vs. traditional class-based components; the only exceptions being _app.tsx
and _document.tsx
, which extend base classes from the Next framework. A _document.tsx
file allows you to customize the base HTML template that the React app is injected into, while _app.tsx
allows you to use shared layouts, add an Error Boundary, import global stylesheets, and more.
Build Customization
Markdown Copy Content
I've also added @mdx-js/loader
and @next/mdx
to my build configuration, which allows me to import markdown (*.md) files as React components. Using this technique allows me to keep some of my copy text (such as the "about" page) in markdown rather than having to manually write out the JSX for it, which is just simpler and easier to maintain.
Working with SVGs
I'm using SVGR to transform my SVG files into React components, rather than loading them via <img src="/my-image.svg"/>
. This means my SVGs will be loaded with the markup, rather than being loaded asynchronously, which can help eliminate Cumulative Layout Shift (CLS) issues. It's as simple as customizing your next.config.js
file to use the @svgr/webpack
loader for *.svg
file types, then importing them in your components, a la:
import SvgAvatar from "/avatar.svg";
const MyComponent: React.FC = () => (
<MyComponent>
<SvgAvatar/>
</MyComponent>
);
DEV Blog
I previously wrote another article about how we can use the DEV API to load your articles in order to embed them in your own website.
I combined this technique with Next's getStaticProps
method to load all my DEV articles at build time, and statically generate the blog pages for my site. To keep the pages up-to-date, I configured the GitHub Action that builds and deploys my site to run periodically. I configured it to run every 30 minutes, however in practice it seems like for some reason it actually runs closer to once every hour. If your CI/CD pipeline is actually time-sensitive, I recommend not using GitHub Actions.
Design
UI Framework
On a recommendation from a friend, I decided to learn Blueprint.js and use it to build my website. After building lots of components using it, tweaking it, and styling it, I think it has become my new favorite React UI framework.
Right out of the box, everything looks amazing, cohesive, and enterprise-quality. Their component library is pretty extensive, and includes just about everything you'd want in your base toolkit, from simple stuff like navbars and buttons, to layout things like cards, to more complex components like interactive menus, progress bars and drawers. It's pretty easy to customize and compose the built-in components to make more complex designs. My only complaint is that there are a select few places I had to use the dreaded !important
CSS directive to override some specific styles from Blueprint's stylesheets.
Stylesheets
My go-to language for stylesheets has been SCSS for a long time, because, well, let's face it, writing vanilla CSS just sucks.
One of the greatest features of CSS preprocessors like Sass is the ability to write nested styles; if your markup can be nested, then why can't your stylesheets?!
You can also easily re-use bits of common styles via mixins, and even run compile-time logical operations to further customize the generated stylesheets. It's incredibly powerful and extensible.
Deployment
My site is hosted statically on GitHub Pages, configured to deploy from the gh-pages
branch of the repository. Deployment happens automatically on push, periodically, and can be manually triggered via a GitHub Actions workflow. The date of the most recent build is injected into the app at compile time via an environment variable in next.config.js
.
Posted on January 22, 2021
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.