/
Engineering Notes
Spoiler: I over-engineered it, but I learned a lot. Here are the hows, whys, and "oh nos."
In this post we’ll take a look at highlights of why this blog template was created. Why didn’t I use other templates? We will also review a handful of implementation details, though we will not be covering the entire development process from scratch — just a few things that I think would be interesting to include. And throughout the post you will see why the fantasy of creating your own blog template might be a mirage not worth chasing.
Well, it all started out from this post.
Basliq Labs consisted of many brilliant students and instructors of Islamic Azad University of Tabriz, each one specializing in their own fields of study ranging from mathematics to UI/UX and software engineering (or at least it was supposed to be like that).
People at Basliq Labs wanted to write their ideas. The issue was that we didn’t have a structured way for writing. For a time we tried writing in Markdown files, Telegram channels (shout out to all Public Repository subscribers out there), and WordPress templates but each one was missing something important. So we developed the blogging template of Qwill.
Our goal was to create a community for the tech people of North-Western Iran as there were no structured and prominent communities at that time. As a part of our strategy, we were writing lots and lots of tutorials, documents, guides, experiments, and essays in languages of Turkish, Persian, and English for audiences of different technical levels and we didn’t want these writings to be scattered.
To name a few of our typical writings for this community:
The Basliq Labs community needed a template that supported:
As we were writing in many different fields, we most definitely needed a good way to be able to categorize the blog posts. That’s why we added in the category and tag entities to our blog to help the users explore and find the articles they want.
We were also writing tutorials or closely related essays about a single topic where simple chronological order was not enough. We needed a way to collect and sort a set of articles that might even be from different categories together with the order we want and we thought the series concept on DigitalOcean was the correct way to handle this use case. Many templates did not have this feature, that’s why we had to either add support to an existing project or create our own blog from scratch.
We were writing in many different languages. Some posts might get translated into some other available languages later after the original publish, so we made an easy way for writing bilingual posts where each language is a Markdown located in the same directory. This made it easier to see what is available and what is not. It is a simple idea but other templates and frameworks (like Docusaurus) put contents of different languages in different directories entirely, which made things harder for our team.
Now bilingual blogs exist, but not many of them handle a right-to-left language like Persian gracefully. We reviewed many great templates that were written with Astro, Next.js, SvelteKit, and other frameworks but unfortunately many of them had not considered RTL users.
We wanted our content to be publicly available in a repository to encourage the community members to either write up their own ideas and file a pull request or fix the issues of previous articles. We also wanted the hosting to be done on GitHub Pages as it was easy, accessible, and free. We also thought other developers might clone our project and use it as their own personal blog so we wanted everything to be easy and without any costs.
These 2 reasons together made us move away from WordPress themes and architectures that require a backend for the blog. This forced us to take the static approach.
Long story short, things didn’t go smoothly with Basliq Labs and it dissolved.
Fast forward 2 years to 2026, I am trying to continue my graduate studies in systems engineering. I am doing lots of experiments with different tools at different layers and I need a place to to document my learning.
The courses are difficult, deep, and demanding and I think it is better to write my own understanding of systems in technical blog format to both validate that I have learned at the level that I want and help a few souls if possible.
So I cloned the Qwill repository and tried to customize it to my special needs. I made it more minimal and less pretentious to let the text and technical content be the main focus point of the blog. I also added custom Svelte component support to make Markdown more flexible.
From an implementation point of view, for Qwill I had to choose a stack that supported:
Hugo (Go) and MkDocs (Python) were written in other languages and ecosystems. I didn’t research them extensively but I was sure that I didn’t want to bring another language and ecosystem to Basliq Lab’s frontend stack so I ruled them out.
These two frameworks are awesome! Having worked with Next.js in many professional projects, I really knew the ins and outs of the framework but I didn’t want to choose the same tool over and over again.
At the time that I was starting to work on the Qwill template, I was hearing some new names like Astro and Svelte and I wanted to test them out. The blog was not a critical project and these two relatively new frameworks were already mature enough to be considered as a safe experimental choice.
Astro was my first choice to build the Qwill template. After building a simple mini blog and assessing the experiment, I figured out that Astro is a convention-heavy framework. Though these conventions can be configured and they wouldn’t necessarily prevent me from building the blog, but I didn’t quite like the developer experience. So I deleted the project.
I moved on to the second option, SvelteKit. Going through Svelte’s interactive tutorial, I had the first impression that I have found something new. The component model was pleasant. The markup syntax was sweet. And it had its own framework called Sveltekit. Did it support SSG? Yes. Did it support flexible “your project, your thing” kind of workflow? Yes. Did it support Markdown and custom components? Well yes, but actually no.

That was a trick question. These kinds of features don’t normally get baked into general purpose frameworks themselves. I searched and I found a library called mdsvex and it seemed fine. So I reinitialized the Qwill project with SvelteKit, and later I modified the same codebase for the Attempts template.
In this blog I just mention a few small parts of the project that I think would be interesting for you. To learn how you can build a blog with SvelteKit, you can follow the tutorials that I used to build this one:
The first step is to somehow convert our MD file to an HTML representation of it and since we are making the blog with Svelte, we somehow need to integrate it with the component model of Svelte.
We could do this manually by reading the contents of the Markdown file from the filesystem, trying to extract out its metadata and content into the format we need but this sounds way too much work and we are not getting paid enough to deal with that complexity so we use libraries.
We can use a library called mdsvex, that gets added to the Vite bundler as a plugin and defines some logic for the imports of .md extensions. We can install it with:
terminal
$npm i -D mdsvexIf you are interested in how we can import non-standard files like
.mdinto our code then take a look at this blog post (as opposed to being able to import only.jsfiles).After the installation, we plug it right in to the build system.
svelte.config.js
1 2 3 4 5 6 7 8 9 10 11 12 13const mdsvexOptions = { extensions: ['.md'] } const config = { preprocess: [vitePreprocess(), mdsvex(mdsvexOptions)], extensions: ['.svelte', '.md'], kit: { adapter: adapter({ fallback: '404.html' }) } }Now you can import
.mdfiles into your JavaScript code which gets resolved to an object that gives you access to that Markdown file’s metadata (a.k.a. frontmatter) and a Svelte component that contains the Markdown content as HTML.You can’t send a Svelte component over the network, because it cannot be serialized into JSON, therefore you have to use SvelteKit loaders (you can learn more about them in the tutorial that I mentioned earlier).
For SSG builds you have to define your routes as such that every page can be found and rendered at the build time (yarn run build). The only part that confused me a bit was the list and its pagination.
Often in client-side rendered applications we would set up the client routes for lists using query parameters like /blog/posts/list?page=1. However, for SSG websites we cannot use that format (we can, but the headache is not worth it). We must use routes that can be predetermined beforehand, because the SSG crawler will follow all the links in our applications to discover all the available pages and start rendering the HTMLs.
In this application I found this setup more useful:
Select a file to view its content
Things like logical CSS properties and component mirroring needed attention since day one. I have written a separate deep dive about RTL applications here:
I changed the colors and the overall theme of the previous template to create the new one in a matter of minutes. It supports light and dark mode and currently it has one theme though it can easily be extended to support multiple themes. If you want to learn more about the art of styling modern web applications then I strongly recommend you to read this post:
Standard Markdown features like headings, lists, tables, and links lets you write simple articles with no extra overhead. But sometimes you just want to be able to get out of that restriction. Maybe you want on specific image to have a certain width and be centered. Maybe you want to display an editor like view with many tabs. Or it is just that you want to display a Twitter message with more class and fanciness instead of using block quotes.
Well, you can write plain HTML tags inside the Markdown and most parsers will not escape the tags and copy them directly to the final HTML output. This way you can theoretically display anything you want, but for repetitive usage and complex use cases that gets out of control very quickly. The solution is to use the million-dollar-idea of the new frontend frameworks which is
mdsvex supports importing Svelte components inside the Markdown file. This helps us with encapsulating complex pieces of logic and UI in Svelte components and just use them in the .md files. In this article you can view some of the custom components that I have used, like:
If you are not a fan of adding framework-specific dependencies to your Markdown files, then you can extend the syntax of the standard Markdown by using remark plugins or writing them yourself if you are feeling brave. Highlight marks are an example of Markdown syntax extension (they work with double = tokens). Though I don’t recommend this approach too much, because the end result becomes some sloppy JS code.
The Longman Dictionary defines Svelte as:
thin and graceful.
That sounds very fancy and elegant but I can’t really lie. I didn’t enjoy the overall process. I also believe Svelte has its own great capabilities and will continue to grow. TL;DR: it wasn’t for me.
Svelte is trying to solve a problem that at least 10 other frontend frameworks are trying to solve it as well. But there are some things that Svelte does it better, and I really like them.
Unifying the three concerns of structure, style, and logic in one file and making it feel like the vanilla HTML file is really genius. Angular’s best practice is create 3 different files (and one more for module and one more for tests) and in React I make one file for logic and structure and one for the styles. This seems very little, but in the long run it helps with keeping the project structure simple and less nested.
This feature alone, significantly reduces the cognitive load while viewing the folder structure.
The reactivity system is simple and very clean. You can even move it in to raw JS/TS files. The technology is simple and everything feels very vanilla. I think this feeling is very valuable. When writing code in other frameworks/environments you have to constantly remember that this is JS but also not JS. Other frameworks often have their own special way of organizing components and states, which forces you write code in a very specific way. There is no such thing as React vs non-React files, it is just JS with superpowers.
The vanilla nature of this framework reduces the developer’s friction. They can even use JavaScript libraries and use them directly in the code, that’s something we can’t easily do in other frameworks.
The problem is not with the Svelte itself but rather with the tooling around it I think. You expect a flawless developer experience from a world class project like Svelte and then you get stuck at places where you didn’t even expect.
It takes 35 seconds for the yarn run dev to start the project and a simple change might take around 10 seconds to be reflected in the development webpage with HMR. The final build of yarn run build takes around 95 seconds to complete. This feels very very long.
To be honest, I have not written the most performant code on the planet. Throughout the build process, it reads the filesystem content multiple times (though I made some improvements by caching the results in a map), but this feels irrelevant when there is only 1 complete blog post in the filesystem. I don’t know which part takes the most time to finish, it might be the plugins that I have added to the pipeline, it might be my own bad code, or it could be the Svelte’s SSG adapter. I’ll write a followup article, when I find out something useful.
In the build process, I see some errors that have been printed to the terminal. The issue is that I have no idea what that error means. Neither the error message is useful nor the stack trace displays anything interesting. What have I done wrong? No Idea, just go fix your code.
This is very specific but it did happen. I was trying to import TypeScript files into svelte.config.js files (plugins and code highlighters) and I was getting an error that said something like: “you cannot import TypeScript files”.
I tried turning the config file into a .ts file. It was now giving me unrelated errors and because I was also moving things around at the same time, I didn’t notice that this change was the cause of that error. After testing everything out, I finally figured out that svelte.config.ts is probably not supported (at least in the way that my project was set up).
Time for a retrospective. Did I at least achieve anything along the way that makes me say it was worth it?
I think to create a good-looking blog UI, I spent so much time on small features that they made the whole process longer. Adding these features also caused some errors to surface that I mentioned some of them in The not-so-happy path of Svelte.
Features like code blocks with file names and language logos and components like code viewer forced me to add lots of relatively complex, not performant, and fragile code like manipulating the string representation of DOM and reading all the adjacent directories of blog posts to find code directories and show them in the code viewer component.
This made the process more complex. It also added a hidden cost of high maintenance to the project. Adding new features many months later won’t be as easy as it is probably going to conflict with the existing CSS or crash out the whole build process.
You probably should not develop your own blog from scratch if:
where it might make sense:
Long story short, I really like the end result. I have the blog template that I was dreaming of (mostly). The process had some errors and getting stuck situations that were unnecessary for a project like this but whatever. I don’t regret it and I think I’ve done a great job. I’ve eliminated all the excuses for not writing more.