How my previous Progressive React Web App blog Nestjs-backed was created
Guilherme Rossato, June 2023
The previous version of this blog that you are reading was created with all the features a web developer would need to create interesting experiences in his posts. This blog describes how I created it, the thech stack, and the reasoning behind the choises I've made while building it.
The original post was dated so I have revised it greatly as it was originally written in June 2023, and the blog you are reading now replaced it on December 2023 (6 month later) because I wanted to experiment with a better tech stack. You can read about the modern one here.
The benefits and the problems of creating a blog as a Progressive Web App
I always liked the speed of page transitions in progressive web apps, it is the main reason why I choose to implement my blog like a frontend-rendering React PWA. It bundles posts on the build phase and lazily loads all the assets for all the pages as time goes on.
To have the absolute fastest page load I use service workers to cache the downloaded files, including the content. After the first load this blog loaded as fast as accessing it on your localhost! The best part is that my server didn't have to be expensive or fast for it to work like that.
The problem of creating a blog as a progressive web app is that the rendering occurs on the frontend. A rendering phase done in javascript lightens the load for the backend tremendously but makes it difficult for search engines to crawl and index your blog and its content, which means I wont be getting a lot of visitors from services like Google, Kagi, or Bing, even searching exact text matches which is a little problematic.
I don't mind too much my content being undiscoverable because I tend to share my posts organically where I think it will be apreciated.
Style, Tailwind and Code Highlighting
There's some conversations about how TailwindCSS is the best styling framework as of late, it promises you can rapidly build and implement designs by using a collection of utility class names (once you memorize them). I decided to use it to test this and also to learn
Turns out you need to use vite for bundling, and using tailwind over time made a difference on my ability to use it after a somewhat step memorizing curve.
I strongly suggest you use Tailwind if you are not using MaterialUI. Material UI provides you with the <Box /> component that already solves a lot of the problems a CSS framework would use.
I've also used prism and remark to highlight code snippets. Most of what I write here will need some code snippets to explain. Here's the html formatting:
The code above used to be dynamically styled on build as formatted text on the previous version of this blog, I just took a picture and saved as a static image to get same visual for you to see see how it used to look.
I choose to write my blog posts in markdown files that are converted to React components and bundled with my frontend. This allows me to add all sorts of dynamic features to my posts, all while making writing them a breeze since markdown files are simple.
Markdown files are interpreted with the help of the gray-matter package and then transformed to html with the previously mentioned remark package, which has multiple plugins to help transform the markdown to html. The tutorial I used for the parsing and handling of the markdown file was this one: Using Prism with Next.js, even though its not targeted for the same framework it was easy to adapt.
I also use jsdom on the build step in the formatted code to add some styling and to the generated outputs.
Anyways here's the code of a react component to test the javascript highlighting from:
Dynamic content - Adding scripts and react components to the blog
In some rare but important occasions I need to add interactivity in posts like this. I created a pre-build step that checks for special components that can be included with the page. Remember the code above? I put that in a special code block that is injected right where I need it on the resulting page. For example, the code from the react component above can be placed in the markdown to compile it and include it as a live component on the blog post:
This was loaded from the markdown that was exactly like this:
And I implemented a way to add raw html using different header (html-inject) on the code block, it works similarly.
Red text
And finally, I added a js-inject header that allowed me to add actual javascript that ran outside the react environment in case I wanted to do something fancy or have more flexibility. Anyways if you click the above text the code below would change its content. Remind that this is running on the new blog environment so I had to do some adaptations.
Building / Deploying
I didn't want to complicate things so I left this process manual: The repository is stored on github and when I want to update production I have to enter on the server through ssh, do a git pull from github, then run npm run build, a custom service script would automatically stop and replace the server process (it would run npm run start in the background). It's not the best experience so in the next version of this blog I implemented my own automatic CI/CD process that you can read on the post about my modern blog!
Conclusion
These features allowed me great flexibility to create some interactive experiences in posts, I also learned how to self host and keep SSL certificates updated, and I can also showcase my future projects with live demos whenever I need to, which was one of the most important features I was seeking! These things will make my blog stand out once I get around to put it to use more often!
That's it, my blog is this dynamic react project bundled with vite, styled with tailwind, hightlighted with prism, linted by eslint, and formatted by prettier.