How I crafted my own portfolio and put it on the Internet
Tags: webdev, nextjs, career, showdev
Published: 2022-10-10 14:39:23

## Hello there 👋

This is the first time ever I post anything on [Dev.to](https://www.dev.to). I've been lurking in the shadow, reading all kind of interesting posts here and finally I think it's time to write my own post to contribute something to the forum.

![Me reading the comments from posts on dev.to](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/hvmwqb0r7pm0a94zbx5s.png)

What I planned was to create my own portfolio and put it on the internet, so HR and other developers can find me easily. Howerver, since I was ~~lazy~~ busy at work, it stayed on my backlog for a long time. Until last week, I finally decided to start working on it after reading [this nice article](https://dev.to/naomipham_/how-to-create-darklight-mode-with-react-and-tailwind-59e0) on the forum. Shout out to **Naomi** for the motivation and inspiration.


## How I choose techs for my portfolio 👀

I decided to start working on the portfolio with my most favourited framework: [NextJS](https://nextjs.org/). The reason why I chose NextJS instead of writing my portfolio using normal React is [the ability to SEO](https://blog.logrocket.com/how-next-js-can-help-improve-seo/). Also since I kinda hate to do the routing in React using `react-router-dom`, NextJS routing system is my go-to. For now, my portfolio only have one route, but I'm planning to add a new blog page to my website, so it's better to get prepared first. 

Also, let's not forget about [TailwindCSS](https://tailwindcss.com/). The first time I used it, I felt in love with the library almost immediatetly. TailwindCSS helps me to create a very well-structured CSS in the codebase, and I'm using it in almost every projects I'm working on.


## Steps to make my dream portfolio comes true

Let's get started by running the command to create the initial project

```
yarn create next-app
```

![Project initiation](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4l8ke9qdg7uruyzlyaid.png)

By default, NextJS will come with `eslint` pre-installed. I will add another library called `prettier` and use it along with `eslint` to control my code's quality. Also, I install a plugin called `prettier-plugin-tailwindcss` to auto sort my TailwindCSS classes. 

```
yarn add --dev prettier eslint-config-prettier prettier-plugin-tailwindcss
```

This step here is my own preference, you can skip it or follow it. But I think it's always good to have a barrier preventing you from falling into the abyss. 
My Prettier and ESlint configuration will look like this:

![Prettier](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/o4d1x093sdaswig3nuar.png)

![ESlint](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/y0noiz982ijx1tv6n049.png)

Next step we need to install TailwindCSS. More commands 👀

```
yarn add --dev tailwindcss postcss autoprefixer
npx tailwindcss init -p
```

The first command will add the library into `devDependencies` inside your `package.json` file. You can check out the different between `dependencies` and `devDependencies` [here](https://docs.npmjs.com/specifying-dependencies-and-devdependencies-in-a-package-json-file). The second command will create 2 files: `tailwind.config.js` and `postcss.config.js`. We need to add some lines of code into `tailwind.config.js` file and import `@tailwind` directive into the global css file to make it works.

![Tailwind setup](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4cukxpy7dryjpmf46ec2.png)

Also, I will add property `darkMode: 'class'` into `tailwind.config.js` to control my portfolio's dark mode using classes.

Let's talk about the font. I found that the font **Inter** looks attractive and clear, so I used it as the main font for my portfolio. Let's open google font and grab the font we need, created a file called `_document.js` inside our project and put the tags into our file.
![Google Font](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/e4dq2jxpi4zi8gfm13p4.png)

![_document.js file](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/cct32etz15dnz0t66ca2.png)

After that, we can setup the absolute import function for our project to prevent ugly `../../../../components/OurNiceComponent.js` thingy. Luckily, NextJS starts automatically support `jsconfig.json` "paths" and "baseUrl" options since Next.js 9.4, so we just need to create a new file called `jsconfig.js`, add the configuration like this and it will work nicely.
 
![Absolute import](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/i8rv8mwyjtdr9airima4.png)

The result after we have absolute import working

![Absolute import result](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/vcr1zfs1wqqea4sa01ix.png)

This looks much nicer in general, isn't it? 

Now, we start coding. I won't dive too deep in my codebase, since you can check it out in [my Github repo](https://github.com/Mangor1no/russ-portfolio). However, I do have some points that I found they are quite interesting, and will share with you guys how I handled them.

1. Flash of unstyled content
2. Website optimization

## Flash of unstyled content
The most important thing you need to do when setup dark mode for your website is to keep the theme selected by the user. Normally, you can save a key to localStorage to identify the selected theme.

```js
const [darkMode, setDarkMode] = useState(false)

const initDarkMode = () => {
  const isDarkMode = localStorage.getItem('your-theme')
  if (isDarkMode === 'dark') {
    setDarkMode(true)
  } else {
    setDarkMode(false)
  }
}

useEffect(() => {
  initDarkMode()
}, [])

const changeThemeHandler = (theme) => () => {
  if (theme === 'dark') {
    document.documentElement.classList.add('dark')
    setDarkMode(true)
  } else {
    document.documentElement.classList.remove('dark')
    setDarkMode(false)
  }
  localStorage.setItem('your-theme', theme)
}

return (
  <button type="button" onClick={darkMode ? changeThemeHandler('light') : changeThemeHandler('dark')}>
    Change theme
  </button>
)
```

The code block above will help you to set the theme base on the value of the key `your-theme` in localStorage. However, when you refresh the browser, you will start notice a problem: Your website will flash a white screen before it changes to dark theme. This problem happens because the function `initDarkMode()` is being placed inside `useEffect()`, which runs after the content has been rendered.

![useEffect timing](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/g7wn0h34yyh24gtv8e3o.png)

The solution for this problem is quite simple. Open the file `_document.js` and add the script below inside the `<Head />` tags.

```js
<script
  dangerouslySetInnerHTML={{
    __html: `
      (function () {
        const themeKey = 'your-theme';
        const classNameDark = 'dark';
        const classNameLight = 'light';

        function setClassThemeOnDocumentBody(darkMode) {
          if (darkMode === 'dark') {
            document.documentElement.classList.add(classNameDark);
          } else {
            document.documentElement.classList.remove(classNameDark);
          }
        }
          let localStorageTheme = null;
          try {
            localStorageTheme = localStorage.getItem(themeKey);
          } catch (err) {}
          const localStorageExistsTheme = localStorageTheme !== null;

          // Determine the source of truth
          if (localStorageExistsTheme) {
            // source of truth from localStorage
            setClassThemeOnDocumentBody(localStorageTheme);
          } else {
            // default theme is light theme
            localStorage.setItem(themeKey, 'light');
          }
      }());
    `,
  }}
/>
```
By adding this small script, we are able to block the browser rendering and set the theme before browser paints our page. No more flashing 👌.

## Website optimization
There are plenty of ways to check how optimized your website are, but my favourite way is using [Google Audit](https://web.dev/measure). The tool will give you an insight about your website, including website's Performance, Accessibility, Best Pratice and SEO. On my first audit, the performance score for my portfolio was 84, which was kinda bad for a simple page.

The first thing I did is to compress my images. But since my portfolio only have one image, there was no significant change. Back to the audit report, I noticed that my First Contentful Paint (FCP) time was long, and the tool said I should avoid chaining critical requests. A little bit more inspection and I found out that the font size downloaded from Google Font is too large. In fact, the requests size for this font was more than 136kB per font type, added up to more than 340kB in total!

As every normal developers, I started begging Google for help. I bumped into [this article](https://www.labnol.org/internet/reduce-google-fonts-size/21057/), and after applied this method to my portfolio.

```js
<link
  rel="preload"
  href="https://fonts.googleapis.com/css2?family=Inter:wght@400;600;700;800&display=swap&text=1234567890qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM%22%27%28%29%2C%2D%2E%3A"
/>
<link
  href="https://fonts.googleapis.com/css2?family=Inter:wght@400;600;700;800&display=swap&text=1234567890qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM%22%27%28%29%2C%2D%2E%3A"
  rel="stylesheet"
/>
```

By adding `text` query to the url and use only needed characters for the font, my total requests size for the font was less than 40kB in total. It means I have reduced nearly 90% of requests size. Stunning result! 😳

Here is my portfolio audit score after the optimization: 

![Final result](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/c8zwi95acrvrg4pugfbq.png)

## Put the portfolio on the Internet
I bought a cheap domain and used Vercel to host my portfolio. The integration was quite easy and fast, I just updated the CNAME and IP Address of Vercel to my domain and it did the rest of the works for me. Thanks Vercel for bringing such an amazing deployment experience to the developers!

## Final words
Thank you for spending time to read my long article 🙇‍♂️.

You can checkout my portfolio [here](https://www.russdev.net).

If you want to find the codes, please checkout my [Github repository](https://github.com/Mangor1no/russ-portfolio)