Building this website

May 4, 2024

This is Matteo learning Gatsby

The goal of this repository is to led me to something I can call my personal website.

Along the path, I would like to study something new and build something from scracth. What better way to do so rather then building it while documenting what I'm doing?

Skills I want to improve by doing so

  • CSS, CSS Modules, maybe some styling library
  • Modern react
  • Gatbsy and its platform
  • Markdown writing
  • Graphql
  • Tooling and IDE

What I would like to see on my website

  • Nice presentation of myself
  • Something I can export as my CV
  • A list of projects I worked on
  • Some articles about technologies and learning

I need to set my expectations correctly. Whenever I'm too ambitious, I always end up spending more time on configuration than the actual project. Actually, the main factor on the success of something I'm working on are not my ambitions but the time I put in.

Day 1 🚀 The beginnings

  1. Initialization of the project

    So far everything looks good! I am following the Tutorial that should help me get up and running with Gatsby.

    The initialization is something like this.

    1# create a new Gatsby site using the minimal TypeScript starter
    2npm install -g gatsby
    1# create a new Gatsby site using the minimal TypeScript starter
    2npm init gatsby -- -ts

    And of course, to start the website in development mode

    1cd my-gatsby-site/
    2npm run develop

    First issue encountered! I cannot use Node 20. I need to use Node 18. It's ok, they say at least 18.

    A lot of things are done by yourself, like the first commit of the repository. I wanted to create a repository on the parent folder, but I guess if I want to keep the deployment simple I better stay with this.

    The only thing I'm not sure so far, is how can I have a .tsx file and typing correctly the props. So I temporarely converted the pages into .js and it seems to stop complaining.

  2. Plugins

    Now it's start to deep dive into the plugins. The ecosystems seem huge and even the smaller task can be delegated to a plugin. But I understand the concept. On a web increasingly complex, even the task of render a picture can be dependent on so many factors that is better to hide behind a nice abstraction.

    1npm install gatsby-plugin-image gatsby-plugin-sharp gatsby-source-filesystem

    3 new dependencies just to display a picture? I love it!

  3. GraphQL

    This is something I was curious about. How Gatsby is going to use GraphQL?

    First of all, when developing a website, it provides a great interface at

    http://localhost:8000/___graphql

    Looks like everything can be queried, from the site metadata to the structure itself.

    1query MyQuery {
    2 site {
    3 siteMetadata {
    4 title
    5 }
    6 }
    7}

Accessing data is used by the method useStaticQuery. This is cool, because it shows how all this queries are executed at build time and served statically.

I bet there is a method to do dynamic queries as well.

  1. SEO Compoonent

    The tutorial wants me to create a SEO component that queries the metadata and use it as default when a title is not provided as prop.

    This is interesting. This component is then used into Head component.

    I can also hide the useStaticQuery behind a custom react hooks.

    So instead oif having something like

    const data = useStaticQuery(graphql`
    query {
    site {
    siteMetadata {
    title
    }
    }
    }
    `)

    We can refactor into:

    const useSiteMetadata = () => {
    const data = useStaticQuery(graphql`
    query {
    site {
    siteMetadata {
    title
    }
    }
    }
    `)
    return data.site.siteMetadata
    }
  2. MDX Support

    Looks very cool!

    1npm install gatsby-plugin-mdx @mdx-js/react

    Interestingly, @mdx-js/react maps the implementation of the plugin into reacts component. I wonder why this cannot be a dependency of the plugin, since we are dealing with react in any case.

    The remark itself, can use plugins to enanche its features, like code coloring, ecc.

    A plugin makes available to GrapQL new data that can be queried! And I must admit that the graph explorer is quite cool to work with.

  3. Page routing

    Dynamic pages to route dynamic data. Looks similar to what NextJS does.

    Looks like that whener we enter into a page, a pageContext is populated

    1Object {
    2 // ...
    3 pageContext: Object {
    4 id: "11b3a825-30c5-551d-a713-dd748e7d554a"
    5 frontmatter__slug: "my-first-post"
    6 }
    7 // ...
    8}

And the exported object query is the ones that can use these info to query the data it needs to use.

  1. Gatsby picture Looks like that Gatsby allow to an even more dinamic version of the picture element. Not only we want to be dynamic on the loading of the picture, but also dynamic on how the picture is managed.

    Of course a new plugin is needed but they don't scare me anymore.

    1npm install gatsby-transformer-sharp

    This allow to import what we have on the mdx data into our page.

Day 2 🔭 Further explorations

  1. Having multiples, separate blogs?

    Yes, it's feasable, on a side we can have multible folders configured into the gatsby-plugins folder

    1{
    2 resolve: `gatsby-source-filesystem`,
    3 options: {
    4 name: `blog`,
    5 path: `${__dirname}/blog/`,
    6 },
    7}

    The issue is that we still need to filter the mdx values into the query, because they are all made available to graphql under the same "collection"

    1query {
    2 allMdx(
    3 filter: { fileAbsolutePath: { regex: "/second-blog/" } }
    4 sort: { fields: [frontmatter___date], order: DESC }
    5 ) {
    6 nodes {
    7 frontmatter {
    8 date(formatString: "MMMM D, YYYY")
    9 title
    10 slug
    11 }
    12 id
    13 excerpt
    14 }
    15 }
    16}

    This is not entirely bad, as I learned how I can filter stuff when dealing with mdx. Let's pretend I want to hide a blog post from the list, I can add a field in the markdown and filter based on that.

  2. Theming, dark mode and light mode?

    Implementing a dark mode was not so difficult after all.

    First of all, I needed to implement a theme on the css at all!

    So, how css can be implemented?

    By importing it on the components we are working on!

    // Import from a CSS file in your src
    import "../styles/index.css"
    // Import from an installed package
    import "bootstrap/dist/css/bootstrap.min.css"

    Setting the dark theme is not something absolutely impossible. A lot pass through the layout file, that imports the style and can also override some styles with the dark theme.

    {theme === "dark" && (
    <link rel="stylesheet" type="text/css" href="/dark-mode.css" />
    )}

    The variable theme can be changed as every other state variable in react.

    And just like this you get an amazing dark mode on request! Hurray! But, there is a problem

    If you do so, every time you change page you get a white flash while in dark mode.

    The issue is that Layout, used as wrapper element for every page component, is not wrapper enaugh and get reloaded.

    The solution to fix this is twofold:

    1 - add a gatsby-browser file like this

    const React = require('react')
    export function wrapPageElement({ element, props }) {
    const Layout = element.type.Layout ?? React.Fragment
    return <Layout {...props}>{element}</Layout>
    }

    2 - add a similar line on every page

    IndexPage.Layout = Layout;

    And of course, this is under documented and it's not clear at all. The page has a 'Layout' field ready to be set, but nobody told you so.

    How I found out this? Thanks to my inspiration for this project, the website of https://taniarascia.com

DAY 3 🚧 Simple issues, big headaches

Every time I commit, a new build is performed and my website is updated. This is cool, of course. But you know the uncanney valley effect? In my extended interpretation, a small issue on an almost perfect website RUIN COMPLETELY THE EXPERIENCE. And in my case, this issue was the fact that the CSS was applied 100ms after the page was loaded. I guess this is a problem for everyone suffering from epilessy, but it is a huge problem for me as well.

'About the impostore syndrome' Usually I tend to overthink the amount of obstacles I encounter everytime I fight a new issue. Whenever I working with a technology I'm confortable about, I'm a rocket. In no time I can find a solution to most of the issue or I can tell you whether a solution exists or not. When dealing with a new technology, I often look amazed to other people's results.

When developing this website, I've had a couple of inspirations I looked at. Calling some of them inspiration is reductive, since I've "adopted" a lot of the solution these people are using and adapted their code as well.

As I mentioned before you can see a lot of similarities with https://taniarascia.com.

Why I'm talking about impostore syndrome? Because it took me zero seconds to identify what the problem was about, I've used the right tools to assess the issue (lighthouse), I've used the right script to reproduce the issue not only on the remote deployment but on a local deployment as well. I identified the solution quite quickly, implemented it even quickier. By the way, the solution is the usual underdocumented file that Tania used as well on her website. Still, the feeling I got when dealing with this was not great. I felt I was blocked trying to solve something that I should alrady have known instead of learning something actually usefull. It didn't matter the speed I fixed this issue (it would have took me days some years ago) or the fact that the documentation for this specific matter was rather poor. I must admit though, writing it down helped me visualize how silly I am during these moments. There is another thing it helped a lot:

Tania commit history

This made my day :)

On setting up the projects page

I've created a project page with mdx files.

The idea is that I can showcase the project I'll be working on and, if I want, I can write some story about the project itself. I realized how little I shared so far of what I've been doing.

I am also getting more confortable with GraphQL queries within Gatsby. I would like to see how well it behaves on more complex use cases.

DAY 4 Finding some structure

At this point I think is important to find some structure. I would like to setup some light grid system and understand what options I can make use of.

CSS grid is something I've never really touched before. I've got some experience with flex layouts but I guess it's now time to explore something different.

grid-template-columns is cool, there's nothing I can say. Is quite declarative the way to use it. You just specify how many columns you want by declaring their size in the grid. Anything extra goes on the bottom.

But since I'm not planning into studyng too much of css today, I'll just use it to setup some basic grid inside some pages

DAY 5 Adding content

Most of my day has been spent adding logos of technologies I've used and doing some self discovery about my past. It's not easy to remember at first, but giving it several slots of your time and writing everything you remember is a great way to unleash new memories.

Also, it's another moment on which I tend to compare myself with the people that inspires me. That is very good for motivation, but sometimes you feel like you are not doing enough for your career. Needless to say that IT IS NOT WORKING LIKE THAT. It is called availability bias. I tend to value myself compared to what I've just seen, ignoring a vast bunch of experiences most of the people probably never had in their life.

DAY 6 Deep dive in Gatsby concepts

Do you know that you can have a graphql query per page and as long as you export it, it doesn't really matter the name of the variable?

It's written here!

Do you know that you can create pages programmatically by extending the function createPages?

actions.createPage({
path: slug,
component: require.resolve(`./src/templates/blog-post.js`),
context: { slug: slug },
})

This also helps to clarify how certain plugings must work under the hood.

The context is a very important part of generating dynamic pages based on markdown, for instance.

Also graphql is not really needed.

DAY 7 Kubernetes and Docker?

It's strange, but I wanted to include some stats about my garmin on my personal website. It's not an easy task: a solution would be to update manually the sum. On the opposite side of the spectrum, there's running kubernetes cluster to make this operations for you.

The steps are the following:

  • Run and setup GarminDb using my local machine
  • Create a script to update the database and a script to retrieve the data I need in JSON format
  • Create a docker image that runs the script and expose the JSON file
  • Create a kubernetes cluster. The Kubernetes provides a permanent storage for the database of GarminDb. I simply coulnd't load 200MB every day I run the script, and I needed historical data to make this process fast (~2 min instead of 60 min)
  • Create a cronjob that runs the script every day
  • Integrate with GH to periodically make pull request to the website

That's it! But since we are here, why don't look at deployment operations for this Gabsty image?

There is the official (Docker Image)[https://github.com/gatsbyjs/gatsby-docker] that should make things really easy! Let's try it!

Obviusly is not working with the stranges error ever

--------------------
1 | >>> FROM gatsbyjs/gatsby:onbuild as build
2 |
3 | FROM gatsbyjs/gatsby
--------------------
ERROR: failed to solve: failed to compute cache key: failed to calculate checksum of ref W2IA:VLAN:N3TJ:LZA3:UFSW:5DYT:XAW6:KNWW:WJLV:GPOQ:IBSF:ZWSG::idwbn00rwkquzq1e9fr5v4l09: "/public": not found

Not sure what this is about, when I tried to create a Dockerfile on my own I noticed that the node version used by the official one is 12. The current Gatsby version is happy when node is > 18.

So, I've created a Dockerfile on my own, and it's working! I've also added a multi-stage build to make the image as small as possible.

docker run -p 80:80 matteobucci:latest and my localhost have never been happier! The container works like a charm.

Now, is it Kubernetes the best way to deploy my website? If it weren't for the price, why not?

But pricing wise, I would like to spend as little money as possible. Since I don't need any permanent storage, I could deploy this on cloud run, why not?

Delusion and disappointment

Today I was inspired. I had in my what I needed to implement. The test of the day before worked fine, so it was just a matter of wiring the pieces.

After a couple of hour of adjusting, of course, the authentication of Garmin decides to require 2FA codes just to have fun. It is something it happened before, but I was hoping it was a temporary issue.

What to do? So far the cron job seems to work, so hopefully this is not going to be a recurring issue.

In the meanwhile, I'll just polish some content OR I can investigate about Kubernetes secrets!

Secrets are cool, but nothing amazing to be honest, it looks time consuming to setup. Let's see how many of them I'll need it.

Adding code highlight

The cool solution looks like it's not supporting Gatsby 5. Most of the solutions, instead of using gatsby-mdx-plugin are using gastby-remark-prismjs. The solution I have found Thanks to this guide is not compatible with my current code so I needed to adapt it. The code was different. The import as well. Welcome to the JS ecosystem.

TODO NEXT:

  • Investigate on how styling works
  • Fix first margin on navigation
  • Refactor a footer adding a linkedin link
  • Add a fade in animation when entering some pages

Eventual reading list: Introduction of react hooks

Adding comments capabilities

Main repo is (this one)[https://utteranc.es/]

Website itself is just a simple configuration manager that prints out the script to install on React.

May 2024 Update: Adding Notion Integration

You can now find in this repo a simple Javascript file that takes pages from a Notion database and convert them into nice blog articles for this website. Blog articles, such as this one, can also be added manually. To Gastby it makes no difference where this blog posts are coming from.

Special thanks to ()[https://www.maxpou.fr/blog/notion-as-cms-gatsby/] for the script content, that I simply amended for my needs.