This portfolio has come through a lot of changes recently - and it was well worth it. Follow my lead in this article as we will go through why I did it in the first place, and most importantly - how.
Prerequisites
- My old plain html/css/javascript portfolio was a bit annoying to work with - that alone is a well-justified reason to change it. It lacked modularity, didn't follow best practices and felt a bit on the hacky side. It was very fast to load though, which is something I wanted to preserve if possible.
- You most definitely came across some unity WebAssembly builds here 2D or here 3D . Having those wrapped in an
<iframe>as per Unity documentation is really bothersome. I desperately needed some custom "components-centric" framework. - Markdown blog - the one you're reading now! It's completely written with Markdown, a pretty simple markdown language. This saves a ton of time and is really handy, as I don't need to write html, style it and thoroughly test.
- Try how easy/hard it is to do implement it from scratch, without paid subscriptions, generic site builders or, the worst of them all, wordpress.
With these points in mind, I started researching the options, which were traditional at this point React, Vue, or Next. Even though Next apps are notorious for being slow, seems like I wanted a bit of a challenge. Out of the box Metadata support, tailwind css plus page/layout approach were looking like neat features as well.
Tools overview
Next.js - web framework, which I've chosen to use. In my personal experience, its features appear to be more hidden away and magical in terms of how they work under the
hood, but I like it. Also no need to worry about compressing all the images to webp format, as Next does it automatically with Image component.
Tailwind CSS - a css framework which saves a lot of time writing pure css. It also has screen size css rules, very condensed and informative, can be used inline with html tags.
Radix UI - another simple but powerful framework, which helps with theming and has a collection of UI primitives (toasts, tooltips, badges, ...), that can be overridden.
Shiki - code syntax highlight in markdown. Can be modified to show code diffs or highlight only relevant portions. The language support is impressive - more than 250.
ESLint, Prettier - handy for development. With git hooks, I've set Prettier to trigger before commit as opposed to run on every file save. You can see the changes to files without Prettier clutter, and once committed - all changes are prettified:
#!/bin/sh
FILES=$(git diff --cached --name-only --diff-filter=ACMR | sed 's| |\ |g')
[ -z "$FILES" ] && exit 0
# Prettify all selected files
echo "$FILES" | xargs ./node_modules/.bin/prettier --ignore-unknown --write
# Add back the modified/prettified files to staging
echo "$FILES" | xargs git add
exit 0Lastly, Netlify - which is a hosting server for this portfolio. With every deploy, I can monitor the Lighthouse performance scores, choose which deploys I want to use, easily setup functions/content header, and not worry about down time of self-hosted solutions.
An interesting thought to add here: my experience with AI was pretty much horrible. Most of the cases, it's better and easier to check documentation - I decided to not use it much for implementation, mostly for routine tasks like helping with layouts.
Easter eggs
No easter eggs in this portfolio wink-wink
Showcases
As mentioned before, this portfolio uses custom Unity WebAssembly builds as personal projects showcase. They are not wrapped in iframe and styled completely on the Next side. This also allows me to utilize Brotli compression.
Alongside Unity, Rive is used for micro-animations here and there. Those are very easy to create, but not that straightforward to make them work in Next. I ran into several issues with loading, vector feathering, input events and performance down the road. These were solved with using a heavier @rive-app/react-webgl2 library. And believe me, it's waaaay heavier. There are quite a lot of optimizations required to load rive assets without a visible delay.
Bugs?
Don't even ask.
Project overview
And now to the more technical side of things. This is my first time working with Next and it was quite an experience. I was really fascinated by the way the project structure is handled. Like in this blog directory:
+---src
| +---app
| | +---about_me
| | +---blog
| | | \---[slug]
| | +---three_d
| | \---two_d
| ...
...Basically, every folder is an app route. But what to do if I need a blog post as a route itself? I can use dynamic route segments like [slug] and have a blog post become a page route. A page/layout approach means I can split the whole app into chunks, where parent chunks wrap children chunks. This minimizes writing boilerplate code and can actually speed up your app if you only need to only re-render one child of the parent.
Another thing I enjoyed is SEO, as many of the html meta properties are represented with Typescript types (like Metadata, MetadataRoute.Robots, MetadataRoute.Sitemap). This allows Next to generate those out of your project structure without hardcoding relative paths.
Next steps
I have quite a few things planned! Some of them are:
- Automated bug reports
- More interactive 2D/3D Unity builds of tools I implemented in commercial projects.
- 3D environments (Unreal, Blender, Adobe Substance)
- More easter eggs ( ノ ゚ー゚)ノ
That's all folks! Thanks for reading and many more articles will follow soon.