Site Devlog #1
This is the first development log entry for this site. Mainly about how I built the site, how I structured it and why I chose this approach. This whole ordeal to reach this stage took several months, so get ready for a long write-up on this first stage.
Idea
My idea was to create my own personal portfolio site to better showcase my projects, alongside any articles including development logs and guides for people to read. I also want to showcase my photos from my camera in a gallery.
In terms of rendering, I didn't want to use client-side rendering for a whole portfolio site like this, mainly so that I can get a good SEO score in the first place. This left me with two main categories, server-side rendering (SSR) and static-site generation (SSG). Both have their pros and cons, and the latter especially is popular for personal blog sites, but I opted for SSR instead. I originally used Hugo which is a SSG framework popular for building personal sites, but due to the shortcomings when it comes to interactive elements or server-based resources, I didn't waste time any further and migrated to the SSR approach.
And yes, I don't want to rely on pre-existing solutions like WordPress, partly as a challenge, but mostly so that I can manage everything that's on my site.
Project setup
For this site, I'll be using Solid Start, a
relatively young fullstack meta-framework amongst the plethora of JavaScript
frameworks out there. Its core, Solid JS, utilizes fine-grained reactivity,
which allows Solid to update only what has
changed
, thus improving performance and load times. I personally have read
numerous articles from the framework's author, which definitely convinced me to
try Solid JS when it's still in develoment. And Solid Start just hit v1.0 a
few months ago, so
this might be the perfect time to make use of it.
Setting up a new Solid Start project is simple enough according to
the docs. I'll be using pnpm
in
this case, and for the project I will be using TypeScript and start with the "with-mdx"
template.
Writing content
Using MDX is definitely a huge benefit. For those who don't know, MDX is basically Markdown but with JSX, allowing for placing custom components without relying on custom syntax. In addition, I can achieve much cleaner, readable source code for each page.
I tried using JSX, but since the content has to be wrapped in a fragment, which also should be returned by a function, plus an element's contents has to be wrapped with the element's tags, I had to deal with at least 3 levels of indentation, which does not look great. In addition, the nature of pre-formatted code meant that I could not just inline code directly in a code block, so that has to be extracted to a separate variable, which breaks the reading flow.
The huge downside to using MDX is losing control over exactly how these elements are rendered. You could customize what component to render for each element, but extending the syntax to attach certain metadata, like a title for a code block, is a bit tricky in its vanilla configuration. That's where plugins come in.
Plugins allow syntax extensions which opens up a lot of things such as custom
properties and elements. They could also transform existing parsed elements to,
for example, add syntax highlighting to a code block according to its language.
In my case, I had to rely on a lot of plugins, as you can see in the snippet of
my app.config.ts
file below. Both remark
and rehype
are used for MDX, so
that's why you can see two separate lists for plugins.
I also wrote a rehype plugin myself, rehypeCodeMetadata
, which just stores the
code's raw text and title in attributes, which can be referenced by my custom
components.
Speaking of which, defining custom components for MDX is easy enough. The
MDXProvider
component accepts a components
object which is basically
a mapping of HTML element names to custom components. All props of the
original element would be passed to its corresponding component.
Metadata
Another thing I want to implement is page metadata. Basically, each page should have information about itself, like the name of the page, the summary and publish date of an article, which could later be aggregated for a number of uses such as a list of articles under a certain path. Solid Start does come equipped with file-based routing, where the directory structure (under the routes directory) dictates the paths of the pages, but it doesn't do any other fancy stuff, so I had to implement the metadata system from scratch.
Defining data
After I gave it some thought, I came up with a tree structure of some sort.
The Basic
node is just a placeholder for any page that doesn't have any
templating, or children for that matter. The Index
node is a node that has
possible subpaths, and lastly the Article
node holds metadata about the
corresponding article. I can't seem to come up with a better name for
Basic
, believe me, I tried.
Each node would live next to its page as a data.ts
file. These would then be
referenced by their parent nodes, over and over until you end up with a single
root node, referred to as the metadata tree.
Getting data
The metadata tree definitely won't live client-side, it would only be referenced by server functions to process and provide the necessary data. If this whole tree is client-side, then that means loading any page loads metadata for every single page on the site, so that would unnecessarily add to load times. Speaking of which, we also need to make sure that we don't return the whole node, rather the metadata itself, so there should be separate data structures for the "client-facing" side.
I placed all server functions under the server
directory, although the data
itself resides under the routes
directory so that we can avoid two separate
directory structures and keeping them both in sync. I won't go into detail
into the implementation, though you can imagine the usual tree traversal
using path fragments of a given pathname. Using these endpoints in
a Solid component is as simple as calling the function in a createResource
call.
Styling
I didn't want to rely on any styling frameworks like Bootstrap or Tailwind. I can see the appeal for rapid prototyping, but I don't want to pollute the markup with a ton of cryptic class names, most of which are just a one-to-one mapping to a CSS rule. So for now, the most I can do is rely on SCSS, specifically SCSS modules. I also used Font Awesome for icons since I don't want to think too much about providing my own icon set.
Ultimately, most of the time is spent on figuring out how I want my site to look like. I actually had a mock-up design in Penpot (something like Figma but it's free and open-source), but then I realized that design iterations using the web browser are much faster. Plus, this means I can figure out how to implement responsive design, which requires a lot of trial and error.
Next steps
At the time of writing, my site is quite functional. I can easily add a page
as an .mdx
file, then add the corresponding metadata next to it, then link
it in the metadata tree. The page should then show up as an article entry.
But the site itself still needs a lot of work, including:
- page for showing articles with a specific "tag".
- "Gallery" and "Projects" sections.
- site logo and favicon.
- image processing for handling multiple image resolutions using
srcset
. - caching server functions.
- contact links and many more.
Until the next one!
EDIT: I had to update this log since there were some errors or missing content.