My blog & its documentation

May 1, 2023

I really like writing stuff, I don't think this is my passion though but I keep documenting things I work on. Long story short, I'm a web developer & a self-proclaimed web designer. I love working with things that are new to me, this inspired blog is my yet another project dedicated to exploring what vanilla-extract can offer!

This is an end-to-end documentation about the usage of my blog & setting it up. The post includes all of the features blog offers & provides an explanation to how you should manage its contents & assets.

The post will contain some of the very smart words, so be aware that you may understand nothing but abracadabra boom bam badam brrr...


Releases

This blog unlike my other works support GitHub releases & each version is considered stable. There's a small list of things in a post-like format for each version, some things mentioned there will be copy & pasted here for further documentation purposes.

This post does not include a documentation on setting up all of the versions released, make sure to checkout the changelog before upgrading or downgrading to any other version.

Configuration

The README.md file says the basics of the configuration but let's dive into some detailed information about what you should have in mind while configuring things.

Make sure you have Node.js installed on your machine, preferably v18 as it is the version the blog was tested on.

As of now, blog is hosted on vercel, a cloud platform that enables developers to host websites & web services that deploy instantly. It does not require any additional configuration but setting up Enviornment Variables.

While it's stated that it's safe to expose credentials of firebase, I still find it much more convenient to have them stored in the environment file either called ".env" or ".env.local". These credentials are necessary for future support of all of the newer releases of the blog. I highly recommend on setting them up properly.

An average list of Environment Variables looks like this:

API_KEY=PIxbSyDxZK0hbAQCbeCMKpwmD0BthIir_l3emIY
AUTH_DOMAIN=[...].firebaseapp.com
DATABASE_URL=https://[...].firebasedatabase.app
PROJECT_ID=[...]
STORAGE_BUCKET=[...].appspot.com
MESSAGING_SENDER_ID=68100932522
APP_ID=1:38180972112:web:d0b1d9d3cf722598dab06a
MEASUREMENT_ID=G-JRZDNGLFE0

These are fake look-alike values, make sure to include correct credentials. Also you could copy & paste definition line in vercel and it will parse automatically in Environment Variables tab of the project.

How to make posts

To make posts setup Firebase Firestore & create a collection called "posts". Then you can create a document, its Document ID (simply document name) is the slug of the blog post.

Other than that, there are fields that you need to fill for the proper work of the post: "content", "title" & "createdAt".

Content stays for the inline markdown of the post. You can use some CLIs like md-minify for minifying your markdown post. Do not hesitate pasting or escape characters in the string as blog unescapes firestore's double backslash issue by itself.

Title takes non-markdown string. Blog doesn't format the title, so you should capitalize it yourself, luckily there are tools like title by vercel for correct capitalizing!

The createdAt field is a timestamp field, where you select the create date of the post.

Example of the panel

Some of the features

There are a looooot of features out there you should have a look at. I tried my best at describing all of them. Some are basic, some are too advanced but overall you end up with a lightning fast Next.js enriched site that you can be proud of.

Static Site Generation

Posts and post list are statically generated (SSG) which brings a massive speed boost on load unlike the old Server Side Rendering (SSR) approach. With that being said posts now are revalidated automatically each month.

Static Site Generation basically means that all posts and post list are rendered and parsed in build time before the deploy.

The old and bulky way was Server Side Rendering (SSR). It was used for blog posts in home page & the post itself. Post is fetched & parsed in runtime. This approach is not effecient in case you have a lot of posts.

- Hey but what if I don't want to rebuild my entire blog on each new post. What shall I do?

There we have ISR - Incremental Server Regeneration.

Incremental Server Regeneration

Not only posts and post list are being revalidated, or simply rebuilt, every month, but there's also a great way on handling manual revalidation. The process of revalidating content in-runtime is called Incremental Server Regeneration and the manual process is called On-demand Revalidation.

To run the manual process, there's an API endpoint to call it - /api/post/revalidate.

It, of course, includes some safety parameters as well as optional path parameter - "token" & "path".

Token is an equivalent to API_KEY environment variable mentioned in .env.local-example. Without the token API will throw a 401 Unauthorized response.

If the path is not provided, it will revalidate all posts, otherwise it will take path query as the path. If an error occurs, API will throw a 500 Internal Server Error response.

So to call a revalidation for revalidating this post, you'd make a GET request to such endpoint:

https://blog.domin.pro/api/post/revalidate?token=PIxbSyDxZK0hbAQCbeCMKpwmD0BthIir_l3emIY&path=/post/my-blog-and-its-documentation

Of course it won't work due to the mismatch of the API key but still, this is an example of the rebuild is present.

API

The project supports some limited Rest API for external usage purposes. It includes routes from /src/pages/api with a base path of /api.

To list all of the posts, its names, slugs & creation dates, use /api/posts endpoint. It takes no paramaters but needs GET request.

To get all firebase assets from Firebase Storage, use /api/assets endpoint, it lists full recursive paths in an array accessible from paths key.

The /api/storage/... endpoint is similar to /api/cdn/... returns a firebase asset by providing url. It works similarly to re-piping as stated below but instead returns an object with a full Firebase Storage link to access file directly from it.

CDN endpoint on the other hand, the /api/cdn/... one, is the re-piping endpoint is explained below in details.

There is a whole post API endpoint for returning contents of the post. To work with it, provide a slug at the end of /api/post/... endpoint. That returns either 404 Not Found response or a post content, slug, name & creation date object.

Markdown support

Blog uses remark to parse your markdown in a graceful HTML, that is then rendered on user's screen. Other than that, it supports some of the flavors and additional formatting like, img absolute path setting, GitHub Markdown Flavor & Highlight.js parsing.

Image & Font optimization

Blog provides a support for optimized images & fonts.

Image optimization doesn't work for post contents but it includes Humanities and other assets. This means that Next.js takes an image & downscales it, then converts it to the optimized webp extension to make sure user load it as fast as possible. This process is done statically in build time.

Font optimization, similarly to image optimization, optimizes fonts in build time. It installs corresponding font files to exclude external network requests for improved privacy & performance.

Meta tags support

Blog provides partial support for Open Graph tags. Those let it be enriched with embeddings on social medias! A small example of a post on discord:

Description & Title embedding

There are 2 supported meta tags - "og:title" & "og:description". Banner and its sizing is not included due to no support for banner images as they are not necessary for the blog.

To set the title & description head to /public/config/site.tsx file that contains following variables: "ogTitle", "ogDescription". Those can be set to a string with some content for the home page.

Post page on the other hand does little different. Since the static post page gets "rawContent" key, there is a markdown string that can be used as the description sliced to 183th character. Make sure your introduction text does not include unusual artifacts from markdown as not every social media supports markdown in the description e.g. [this link](/that-leads-to-cool-site) won't be rendered correctly by discord.

The title is preset with "title" key by the properties so no worries about the correct rendering.

White theme (embed color) cannot be changed without monkey patches due to blog being light themed.

Rewrites

The blog includes a small rewrite support for /cdn/... to /api/cdn/... for shortening purposes. With a bit of a configuration you can setup Multi zones.

Re-piping

Native re-piping from Google Cloud also known as Firebase Storage to a custom /cdn/ base path. Requires "STORAGE_BUCKET" to be provided as the environment variable. It is stated in .env.local-example.

For every request to /api/cdn/... or /cdn/... API fetches the same file with the path provided after, then if a file does not exist it returns 404 page, otherwise it pipes a file with node:https native get method.

The custom re-piping caches images and files but cannot statically generate them therefore it's Server Side Rendering (SSR) only.

The reason it can't is because of file format piping issues. Middleware and rewrites are not statically generated. However, there is a s-maxage header which stays for server side caching thus with a proper setup, such as Vercel, API will cache the response. The first request can take some time to respond.

Not Found page

Custom not found page with the contact information and customizable content.

You can configure some of the content with the configuration provided in /public/config/not-found.tsx. This includes meta tags as mentioned above & of course title & description. There you can change a contact link or even the entire content of a description just make sure it is type of react node.

Illustration pack compatibility

Humanities component with rgbDataURL placeholder. Silver gray is set before the image is loaded.

Requires Firebase Storage to have transparent humanities uploaded to /humanities/ folder!

Humanities files should be named as they were first archived - 1.png, 2.png, 3.png etc.

Ikota & linters

For the people who want to make changes to the blog, repository supports linters.

The project supports ikota and has an initial configuration for it including the vanilla-extract plugin.

Project includes Next.js' eslint configuration as well as prettier for the code formatting.

Reduced motion support

Blog supports reduced motion support for all browsers. Links' transitions will be immediate. This also includes the transform transition of cat humanity illustration on home page!

Strongly & globally typed

As does everyone, this project uses typescript for further easier support of it.

Unlike most Next.js projects, this blog uses global namespace that isn't mentioned in the official documentation but everything under /src/types folder is exported globally, make sure there are no static imports or export keywords in the file, otherwise it won't work.

All of the properties for components include special definition typescript .d.ts file in /src/types/components folder. This also includes API, utilities & page types.

Complete JSDocumented

A lot of uncommented things are commented with JSDoc. This brings some notes and explanations to what is going on in the project.

JSDoc is currently supported for all types, interfaces & its keys as well as components & utilities.

Huge favicon support

There's a big support for favicons on every device & browser. This is a thing due to this amazing service. In /public/favicon folder you can find some bitmap & vector images made especially for some devices & some operating systems.

End-to-end customization

While I could hard-code things, I instead made a /public/config folder with some fancy texts you can replace with your information :)


This must be it, I listed all of the major features of this awesome project. Find more in my repository.