About this website: Jamstack, Vue.js, Gridsome, GraphQL, TailwindCSS, ...

2021-03-30 6 min read

Let's talk a bit about this website.

Like most, I also like simple things do their job well. They are efficient, easy to maintain, good to consume, fast to build, sustainable. However, sometimes the simplicity one seek for should be in what is produced, not in the producer itself. The website serving the article you're currently reading is an effective example of that. If you are curious about the tech stack of this website, read on.

As some of you already know, I was using Hugo, a static website generator written in Go. It's almost perfect with its multilingual support. It does this very well. But it was too static, and oldschool. I wanted something new, fancy, and fast.

Jamstack

I adopted the Jamstack architecture a while ago and started looking for a new, better Jamstack based framework to build the website I wanted. By the way, "JAM" stands for JavaScript, API and Markup.1

"A modern web development architecture based on client-side JavaScript, reusable APIs, and prebuilt Markup"

— Mathias Biilmann (CEO & Co-founder of Netlify).

I discovered some good solutions. They are listed below for your curiosity.

  • Gatsby (React)
  • Vuepress (Vue)
  • Gridsome (Vue)
  • Next.js (React)
  • Nuxt (Vue)
  • and some more..

All these SSG's are amazing at creating a website. But I like to try new stuff. I tried many of them and created a simple blog site to see the result. They are very similar though. But I liked Gridsome more than others. It's like a Vue'd Gatsby.

Gridsome

Gridsome is a static website generator using GraphQL, Vue.js, PRPL pattern, smart link prefetching, progressive images. It aims to generate a SEO-friendly Vue.js SPA with pre-rendered HTML. It's PWA-ready.

Intersection Observer API

Gridsome claims to be fast by default which is important to many. It uses the Intersection Observer API2 to detect elements appear on your screen. For instance, check this post. The images in the article will be loaded lazily, only when they are in your viewport. This speeds things up. You only load the content you will see. It makes the initial loading lightning fast.

There's another topic related to this; pre-fetching & pre-loading3. Gridsome detects the internal links in the loaded page or in your viewport and loads them in the background or tells your browser that you may need these content in the near future. Once you decide to click on a link, things will be easier because the content located in that url is already in your computer and your browser will just open it.

Some adblockers like uBlock Origin disable pre-fetching to prevent any connection for blocked network requests. You need to turn off this setting to enjoy the benefits of my website.

GraphQL

Gridsome uses a GraphQL data layer in development mode. All of the data you are going to use in your Gridsome project is temporarily stored in that layer, like a local database. There's no real-time connection between your data source and the GraphQL data layer. The data in that layer will be generated into static content.

It also has a tool called GraphQL explorer to explore and test your GraphQL queries in development mode.

Vue-powered SPA

SPA = Single Page Application. With gridsome build command, you'll have a list of SEO-friendly HTML files. These files can be hosted anywhere, like Github pages, GitLab pages, or even on a CDN.

These HTML's are optimized to load fast. After your index.html file is loaded, Vue.js will take over the HTML and hydrate into a fully Vue-powered SPA.

Data sources

You can use any headless CMS, Wordpress, Drupal, any APIs, databases, YAML or CSV or JSON files, Markdown files, git-based CMS, etc. as your data source. It's up to you. Gridsome doesn't care about the origin of your data. It takes the data and gives you the output designed the way you want. My site uses Markdown files as the primary data source. I also use the component-based pages for my index pages. These index pages query data on the GraphQL layer.

TailwindCSS

The only CSS framework that would fit this tech stack would be TailwindCSS, so I used it.

GitLab CI/CD

Here's my .gitlab-ci.yml file for this website:

.gitlab-ci.yml
image: node:15.12

pages:
  cache:
    paths:
      - node_modules/
  variables:
    PATH_PREFIX: '/custom/path/'
  script:
    - echo "CW_USER=elmsec" >> .env.production
    - npm install
    - npm run build
    # Optional: this gzips all files, so GitLab can serve compressed assets.
    - gzip -k -6 $(find public -type f)
  artifacts:
    paths:
      - public
  only:
    - master

The customizations I made

Gridsome is awesome. But when it comes to creating a multilingual website with a variety of data sources, it is not as good as Hugo. So I had to make some changes in the core. I took over the control of how Gridsome creates the pages, in order to create my pages according to my needs. After that, I changed the gridsome-i18n-plugin for my specific needs.

This i18n plugin is a wrapper. Generates routes to your pages for each locale. If you have a blog post with a slug like /hello-world/, you'll have routes like /<lang>/hello-world/ for every locale you define in the configuration file. You wrote that post in a specific language but now you end up with bunch of URLs for each language. The same content, ONE language, many routes... It's not a problem if you use the component-based pages as you can use i18n helpers to show the translated terms for the current locale. But you don't have these helpers in your Markdown files.

What if you want to have the same slug for different posts, so you can translate one post into another language and make it available in the same slug but a different language prefix? It was impossible due to the paths need to be unique. I modified the i18n plugin and made it not render the pages generated with the Markdown data source. I took care of them in the gridsome.server.js. All other routes are being generated by this plugin. So, this approach made something possible. Guess what? Click on the flag in the upper right corner and see.

UPDATE: 2021-08-08
Now I'm using Nuxt instead of Gridsome. Read this.

Date: 2021-03-30
Categories: journal