Redesign 2023

The landscape of Frontend development has undergone significant changes in recent times, with the React team introducing Server Components (RSC), which has brought about a wave of transformations. In line with this, the Next.js team has also embraced this direction by making it the default behaviour when utilising their new App folder routing solution.
Eager to explore these new developments and with pending improvements in mind for my website, I saw it as the perfect opportunity to test these fresh approaches firsthand. By applying these new techniques to my own website, I aimed to evaluate the results and assess the developer experience (DX) they offered.
This are some of the main issues I’ve faced when preparing this new version of my website:

Domain change

As part of the new version of the website, I decided to make a domain change. To ensure consistency and improve visibility, I recently aligned my username across major social media platforms to @hugocxl.
With this in mind, it made perfect sense to reflect these changes in the domain of my website, transitioning it to "hugocxl.me."
notion image
This shift not only enhances visibility but also establishes a unified and consistent online presence.

Design

One of the main objectives that I wanted to target on this new version was giving more importance to the content. A minimal, text-first design that would focus on the content over the presentation, aiming for a clean and uncluttered user interface. I focused on essential elements and removed any unnecessary embellishments or distractions.
The design features a simple color palette with subtle accents to maintain visual interest. Moreover, I prioritised ample white space, allowing content to breathe and facilitating a sense of clarity and ease of navigation. The typography follows a minimalist approach as well, with a clean and legible font choice.
notion image
By adopting a minimal design, I aimed to create a streamlined and elegant user experience that highlights the core content and functionality of the website, ensuring a seamless and visually appealing interaction for visitors.

Design system

I used PandaCSS (comments on it below), to implement a comprehensive design system that would ensure consistency, efficiency, and scalability throughout the project.
In case you’re interested, you might find this guide helpful.
By establishing a solid design system, I achieved a cohesive visual identity and a seamless user experience across all pages and interactions. The system includes a well-defined color palette, typography guidelines, spacing and layout rules, and standardised components that maintain a unified look and feel. This allows me for easier maintenance and updates.
const tokens = defineTokens({ colors: { primary: { value: '#76d9e6' } }, lineHeights: { normal: { value: '1.6' } }, fontWeights: { medium: { value: '400' }, bold: { value: '500' }, bolder: { value: '600' } }, radii: { sm: { value: '8px' }, md: { value: '12px' }, lg: { value: '16px' } }, shadows: { sm: { value: '0 2px 6px rgba(0, 0, 0, 0.12)' }, md: { value: '0 8px 16px rgba(0, 0, 0, 0.12)' }, lg: { value: '0 16px 32px rgba(0, 0, 0, 0.12)' } }, sizes: { sm: { value: '4px' }, md: { value: '12px' }, lg: { value: '20px' } }, spacing: { xs: { value: '4px' }, sm: { value: '8px' }, md: { value: '16px' }, lg: { value: '32px' } }, fontSizes: { sm: { value: '12px' }, md: { value: '15px' }, lg: { value: '18px' } }, borders: {} })
const semanticTokens = defineSemanticTokens({ borders: { primary: { value: '1px solid {colors.border.primary}' }, secondary: { value: '1px solid {colors.border.secondary}' } }, colors: { bg: { primary: { value: { base: 'hsl(0 0% 100%)', _dark: 'hsl(0 0% 0%)' } }, secondary: { value: { base: 'hsl(0 0% 97%)', _dark: 'hsl(0 0% 11.3%)' } }, button: { value: { base: 'hsl(0 0% 94%)', _dark: 'hsl(0 0% 15%)' } } }, border: { primary: { value: { base: 'rgba(0,0,0,0.07)', _dark: 'hsl(0 0% 25%)' } }, secondary: { value: { base: 'rgba(0,0,0,0.04)', _dark: 'hsl(0 0% 15%)' } } }, text: { primary: { value: { base: 'hsl(0 0% 0%)', _dark: 'hsl(0 0% 100%)' } }, secondary: { value: { base: 'hsl(0 0% 20%)', _dark: 'hsl(0 0% 85%)' } }, tertiary: { value: { base: 'hsl(0 0% 40%)', _dark: 'hsl(0 0% 60%)' } }, dimmed: { value: { base: 'hsl(0 0% 60%)', _dark: 'hsl(0 0% 40%)' } } } } })
With the design system in place, I could swiftly create new pages or features while maintaining a harmonious design language. Overall, the implementation of the design system has significantly contributed to the website's professionalism, aesthetics, and overall usability.

Next.js v13.4

The Vercel team introduced several changes on several issues over their previous existing API with v13.4 of Next.

App folder

I’m not a super fan of the file-based routing, but I must admit that the changes from the older “pages” structure has been for good.
Overall, the new "app" router of Next.js offers advanced features, improved performance, enhanced code organisation, and a streamlined development experience. It is recommended to utilise the "app" router for optimal results in terms of flexibility, performance, and development experience.
A good thing was that my previous project structure was not coupled to the implementation details of the Next.js router, making things much easier in terms of migration.

Server-side Rendering (SSR)

Despite the Next team's recommendation for incremental migration, I made the bold decision to go all-in the change, recognising the potential challenges. My goal was to achieve Server-Side Rendering (SSR) for a major portion of the project, so using the "use client" directive everywhere was a no-go for me. However, I quickly realised the wisdom behind the recommendation for incremental migration 😅.
Out-of-the-box, all components utilising "client" code no longer functioned seamlessly. This meant that any components relying on hooks, browser APIs, browser-specific styles solutions, and more, needed to be explicitly converted into "client-side components."
In the previous version of my project, I had relied on MantineUI as my components library, but that had to be discarded in light of these changes. This compelled me to rebuild my entire components library, ensuring compatibility with SSR and exploring styles solutions that could adapt accordingly. During this process, I took the time to thoughtfully structure my new components, aiming to minimise the number of components that had to be designated as client-side (surprisingly, I only had to designate the navigation dock as a stateful component).
About the benefits: The benefits of this new API are indeed remarkable, particularly in terms of reducing the amount of code required to generate SSR pages. Let's take a closer look at the code for my projects page as an example:
export const revalidate = 86400 * 7 export const metadata: Metadata = { title: PROJECTS.title, description: PROJECTS.description } export async function Projects() { const projects = await notionClient.getPages( process.env.NOTION_PROJECTS_DB_ID ) return ( <Page> <Stack> {projects.map(({ id, name, content, description, cover }) => { return ( <Stack key={id} mb={40} gap={'md'}> <Image border={'secondary'} height={'20vh'} src={cover} alt={name} /> <Typography textAlign={'center'} color={'text.dimmed'}> {description} </Typography> <NotionRenderer content={content} /> </Stack> ) })} </Stack> </Page> ) }
The resulting solution achieved through Server-Side Rendering (SSR) is indeed simple and clean, providing developers with an easier way to seamlessly integrate this approach into their projects.
The benefits that come along with SSR further enhance its appeal: It streamlines development, improves performance, and enhances the overall quality of web projects.
Also, since this is the direction in which the frontend landscape is heading, I recommend that you give it a try.

Performance and DX

 
Light house screenshot
 
As of today, the developer experience (DX) in the development process is far from optimal. Slow reload times, cryptic error messages, and compatibility issues are just a few of the challenges faced.
However, I am aware that the Next.js team is diligently working on addressing these issues. Being the first official version, I understand that improvements will be made in the not-too-distant future. While the current situation presents difficulties, I have confidence that the ongoing efforts will ultimately enhance the development process and make it more streamlined and user-friendly.

PandaCSS

During the migration of my project to Server-Side Rendering (SSR), I encountered a significant challenge: many CSS-in-JS solutions would break in this new setup. However, for version 2 of my website, I had already been utilizing MantineUI, a compelling competitor to MaterialUI with intriguing features that leverages Emotion under the hood. Since making nearly all pages "use client" was not a viable option from the start, I began exploring alternative solutions.
Coincidentally, the ChakraUI team had recently released PandaCSS, an exceptional new styling-in-JS solution. Its CSS-first approach at build time allows seamless usage in any context, including SSR. Moreover, PandaCSS provides a remarkable API for declaring styles, and its composition and tokenization systems work flawlessly.
Therefore, I decided to give it a try.
Overall, my experience with PandaCSS has been nothing short of wonderful. I opted to rely on styled native web components, avoiding reliance on any components library, and create the few custom components that my project would need. Understanding the library was quick, which made the implementation super easy, and I could progress in styling the project without worrying about anything else.
By implementing your custom design system with the best API for styling (CSS-based) and a wonderful developer experience (DX), Panda has the potential to become the industry standard in a few years.