This was a big one... clocking in at 11,142 additions and 4,670 deletions in a little under 2 weeks of work. Let me start this by saying that having to refactor my own code from about 1 year ago felt like a punishment from god for being cocky and arrogant about my web development skills.
After 4 months of my first tech job, I decided to bring all my learnings back to where it all began and refactor the code for my portfolio website to make it more maintainable. Let me set the scene of what we were working with before the refactor. All my content and data was stored in unique JSX
components. Paragraphs, like the one you're reading now, existed as div after div hardcoded into components. Just criminal behaviour, really.
I was also allergic to making re-usable components. I was copy-pasting the template over and over again and just changing the content every time. This worked fine until I found a bug or wanted to change the styling of anything; then I scrambled to find every file that used an instance of it, wading through a sea of inline styles.
1<div 2 style={{ 3 display: "flex", 4 width: "100%", 5 flexFlow: "row wrap", 6 alignItems: "space-between", 7 justifyContent: "space-between", 8 gap: "0rem 1rem", 9 }} 10> 11 [...] 12</div>
But that's not all... It appears every second component is using framer-motion's motion
component. Let's not forget the hovered state; fortunately, I had thought that it would be a great idea to give each component a useState
hook that kept track of the hovered state.
In reality, some of the components were starting to look more like this:
1<Link 2 href={`/${title.toLowerCase()}`} 3 onMouseEnter={() => setMouseOver(true)} 4 onMouseLeave={() => setMouseOver(false)} 5 style={{ 6 textDecoration: "none", 7 color: "inherit", 8 }} 9> 10 <motion.div 11 style={{ 12 position: "relative", 13 width: "100%", 14 maxWidth: 1000, 15 fontSize: "calc(6vh + 3vw)", 16 overflow: "hidden", 17 WebkitTextStroke: "2px #F4EEE0", 18 fontWeight: "bold", 19 }} 20 initial={{ 21 fontStyle: "italic", 22 color: "rgba(255,255,255,0)", 23 }} 24 whileHover={{ 25 color: "#F4EEE0", 26 fontStyle: "normal", 27 }} 28 > 29 <motion.div variants={variants} animate={controls}> 30 [...] 31 </motion.div> 32 </motion.div> 33</Link>
This is not something I'm proud of, though I'm sure you can see that something needed to change in a big way.
The first order of business was converting all my ad-hoc inline components into reusable ones. So combing over around 20 almost identical .tsx
files, I tried my best to remove all repetition and abtract them into different components. Went a little bit crazy with my DRY principle and this led me to the next logical step of abstraction - dynamic routing.
Until this point, I had been using the Next.js
pages router, with each route in a directory having its own explicit page. This was not ideal. Even though my website was very very customisable, and reasonably fast, in the name of maintainability I knew I had to pivot away from these 16 individual pages. My initial idea and implementation for this was to store things in JSON
with the larger paragraphs stored in an array of strings. Doing so would have meant giving up on all of the styles and tags that I had applied inside the paragraphs.
I searched onwards, trying to solve a problem of a CMS
that has absolutely been solved hundreds and hundreds of times before, before finally stumbling open one of the example projects for Next.js
. A statically generated blog. Instantly my world was transformed by magical functions with 4-word names like getServerSideProps
and getStaticProps
. Given that I was using TypeScript, I implemented all the magic words like satisfies
and typeof keyof
.
Copying almost line-for-line, word-for-word of this example, I achieved a true statically generated site. NOT. All of the previous component state nonsense that I thought to be essential meant that my "statically-generated" actually needed to be hydrated with reactivity almost immediately... Thus undoing all of my work to make it fast.
I was just glad for it to be over.