Portfolio Website
On Building Custom Websites
Building a website from scratch is not for the faint of heart, it took me 3 Months and 8 new technologies to recreate a website that can be made in an hour using a no-code website builder.
Along the way, however, I gained a deep understanding of how the internet works under the hood, and why technologies that offer even marginal improvements to the developing experience can be so valuable.
§ 1Motivation
Building a portfolio website that can adequately display my projects has long been a personal goal of mine. Unfortunately, my rather steep user requirements have prevented me from getting it together for several years.
My primary goal was to have a website that allowed me to add projects without requiring edits to the codebase. There are three ways one can go about doing it:
- Fully no-code website builders like Wix or Squarespace
- Hosted WordPress site
- Completely scratch build
Anyone that has used no-code builders knows all too well just how quickly costs can spiral (my college quantum club website on Squarespace was costing ~$170/yr by the end).
The next best option is the standard hosted server with WordPress. With 800 million websites, WordPress currently comprises almost 40% of the entire internet. The cost profile is better ~ between $60 and $120, but overall performance and customization options are still limited. Further, the ecosystem of paid plugins (e.g. for contact forms) is incredibly frustrating. Learning how to extend and customize the plugins did not feel worth it in 2023 as the underlying technology is not very transferable.
And so remains: the scratch-built website. Time to put that computer science degree to work. It took me 3 Months and learning 8 new technologies until I arrived at the goldilocks-zone product.
Would I recommend to anyone to do the same to avoid paying the high price tag for no-code solutions like Wix or Squarespace? Absolutely not.
Under the hood, the one-stop shops take care of a staggering number of boring, yet crucially important things like SEO and SSL, while making it significantly easier to make things look good enough with relative ease.
On the other hand, I am blessed (cursed?) with an unsubstantiated level of I can do it myself attitude that would only be satisfied by a complete ground-up build.
Ultimately, plabrum.com is a fast, inexpensive, and infinitely customizable website that exceeded my specifications.
§ 2Technical information
This website dynamically loads content from Sanity.io which is used as the headless content management system (CMS). You can see the components related to sanity in pages/studio/[[...index]].tsx.
All pages on this website are statically generated allowing for deployment on CDN, any content updates trigger a webhook that regenerates just the required pages using a serverless function. This allows the website to be incredibly efficient - running completely for free (save for the yearly domain name DNS fee), and highly scalable (in the vanishingly small event that my portfolio goes viral).
All images are using the next/image component and set with priority and sizes tags were necessary. The sizes tag triggers Next.js to generate images with only the resolution necessary for the device size, ensuring that unnecessary resolution does not hold back loading time. The priority tag keeps certain images from lazy loading so that any important large images will be ready for viewing by the time the user has scrolled down to them.
Google reCaptcha V3 protects the contact form at the bottom from crawlers submitting junk mail. The reduced user friction comes at a cost - the entire website is wrapped in a GoogleReCaptchaProvider higher-order component significantly impacting the page load times.
The contact form at the bottom uses nodemailer via a next serverless function, allowing for contact requests to be made without a dedicated backend. Very fancy!
All content styling is taken care of via Tailwind CSS which is deeply integrated into Next.js, compiling only the necessary utility classes at build time, reducing bundle size, and avoiding the dreaded task of css class design.
Lastly, all animation is completed via Framer Motion, a React animation library that has very appealing syntax but rather weak documentation. There are just a few animations sprinkled about to add a bit of an ooh and ahh factor.
§ 3Instructions for starting up a clone:
First, there are a few environment variables that must be set in a .env.local or equivalent on the server:
yaml######## For Sanity ######## # Available in Sanity.io project NEXT_PUBLIC_SANITY_PROJECT_ID= # Available in Sanity.io project NEXT_PUBLIC_SANITY_DATASET= # Date in the form yyyy-mm-dd NEXT_PUBLIC_SANITY_API_VERSION= # Token set in Sanity Webhook for ISR REVALIDATION_TOKEN= ######## For Recaptcha ######## # e.g. http://localhost:3000 NEXT_PUBLIC_BASE_URL= # Available in Recaptcha Console NEXT_PUBLIC_RECAPTCHA_SITE_KEY= # Available in Recaptcha Console RECAPTCHA_SECRET_KEY= ######## For Nodemailer ######## # Sending email Address GMAIL_EMAIL_ADDRESS= # Insecure App password from Gmail GMAIL_APP_PASSWORD=
Then you should be able to install the required packages and run a development environment:
yamlyarn add && yarn dev
Repo: github.com/Plabrum/website
Live: plabrum.com