Thwarted for the last time!
I can always tell when I haven't written a blog in a while, because inevitably on running gatsby develop
, I will get a pile of inscrutable errors (despite not touching anything for months).
⠋ compile gatsby files
node(52176,0x1709bf000) malloc: Incorrect checksum for freed object 0x12110aa00: probably modified after being freed.
Corrupt value: 0x0
node(52176,0x170dcb000) malloc: Incorrect checksum for freed object 0x1221f8400: probably modified after being freed.
Corrupt value: 0x0
node(52176,0x1709bf000) malloc: *** set a breakpoint in malloc_error_break to debug
⠦ compile gatsby files
When you're getting memory allocation errors on npm start, it's time to step away from the computer
Well that ends today (I hope).
Part of my issue was that I was using a custom mdx
fork of gatsby-starter-lumen, which is a theme that doesn't seem to be maintained anymore. What's worse, mdx
support in Gatsby also seems to be.... less than great. The current solution to the inevitable npm i
dependency hell is to pass --legacy-peer-deps
when using gatsby-plugin-mdx
, which seems broken for an officially supported mode (that you toggle on when you start a new Gatsby project!)
I'd chosen Gatsby/MDX initially because I work with React on a daily basis, and I wanted to include Observable Notebook components in blog posts (and there was a nice little export function you could run to achieve this). I did this in a few places for some interactive visualizations, which suited my blogging style. However, the Gatsby headache kept mounting, introducing additional friction to something that I should enjoy doing, and should be much more seamless. (I spend enough time debugging React for $$; it's not something I want to do in my free time).
The Approach
I started with the recommended create script:
npx @observablehq/framework@latest create
Markdown Files
Since many of my blog posts were already in boring markdown, I just dumped the directories from gatsby into my src
directory to see what would happen.
/Users/mclare/
── workspaces/
└── mclare-blog/
├── dist/
└── posts/
└── 2020-09-18---Building-Blender-As-A-Python-module
Posts with .md
extensions were immediately navigable and viewable at /posts/2020-09-18---Building-Blender-As-A-Python-module
. I needed to adjust the paths on the image files, but that was the only main change needed to the files.
However, Gatsby had previously processed these directories to automatically appear at a nicer slug like /posts/building-blender-as-a-python-module
, so I ended up just bulk renaming the directories to match their slugs in the frontmatter rather than finding a similar workaround.
MDX Files
The posts that were in .mdx
had the aforementioned Observable/React components. Importing and calling them in a mdx file looked something like this:
import {
SoftwareEngineerInterviews,
WeekByWeekInterviews,
GroupedInterviewType,
} from "./observable/softwareInterview.js";
<SoftwareEngineerInterviews />
Observable has a helpful guide for converting notebooks, so that's what I used as a reference here. I can definitely go back and clean up the code at this point (possibly make these into components), but it worked as is with a few tweaks. I removed the small amount of React I was using to just have pure D3 in the JS cells.
Sorting Pages
It's a bit confusing to figure out where to troubleshoot things with Observable Framework, as it appears most folks have moved to GitHub discussions rather than the previous iteration on Observable Talk. However, it turns out that there's an enthusiastic group in the Observable community already tackling the problem of blogging with Observable Framework. I was able to adapt a load-posts.js
script from James King to automatically update my sidebar pages within my home page and at /posts
in descending date order thanks to the existing date
field on the front matter:
import fs from "fs";
import path from "path";
import matter from "gray-matter";
import { fileURLToPath } from "url";
import { dirname } from "path";
// Get the current directory (since __dirname is not available in ES modules)
const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);
// Define the posts directory path
const postsDirectory = path.join(__dirname, "..", "src", "posts");
// Function to load markdown files from the posts directory
function loadMarkdownFiles() {
const postFolders = fs
.readdirSync(postsDirectory, { withFileTypes: true })
.filter((dirent) => dirent.isDirectory())
.map((dirent) => dirent.name);
const postsData = postFolders
.map((folder) => {
const fullPath = path.join(postsDirectory, folder, "index.md");
try {
const fileContent = fs.readFileSync(fullPath, "utf8");
// Parse front matter using gray-matter
const { data: frontMatter, content } = matter(fileContent);
return {
slug: folder,
frontMatter,
fileName: folder,
content,
};
} catch (error) {
console.warn(
`Warning: Could not read file for post "${folder}". Skipping this post.`
);
return null;
}
})
.filter((post) => post !== null)
.filter((post) => post?.frontMatter?.draft !== true)
.filter((post) => post?.frontMatter?.title !== undefined);
const outputData = postsData.sort((a, b) => {
const dateA = new Date(a.frontMatter.date);
const dateB = new Date(b.frontMatter.date);
return dateB - dateA; // Sort in descending order (newest first)
});
return outputData;
}
// Load posts and export as default
const posts = loadMarkdownFiles();
export default posts;
CSS
The lumen theme used CSS modules and Sass. I think it's likely that Observable will at some point support CSS modules (it might already, tbh), but I'll doubt they'll go in on all the different CSS management frameworks. I ended up using a lot of sass ${lumen-dir} ${framework-dir}
to extract all the CSS I needed to get the same feel in my post feed and posts themselves, and just dumped the results into a style.css
at the root of the project as per the Observable instructions. I also did some not so great things with the page loader to get the right DOM structure for a custom sidebar on the home page that I'd like to clean up later (there are definitely some layout issues).
Before (Gatsby)
After (Observable Framework)
RSS Feed
Turns out in addition to solving the page listing problem, James King has already also tackled the RSS feed issue. I had a few minor modifications due to differences in how we structured our directories, but this was pretty straightforward to add and then run post build.
Future Work
Things that are currently missing:
- Avatar (sad things happened with images when I tried to directly copy the node into html)
- Tags pages
- Categories pages
- pagination on these pages and others (currently the home page and
/posts
just have a full link list) - fixing the favicon (minor)
Things I need a better way of handling:
- All the css (I have a single style file :grimace:) - hoping I can figure out how to use CSS modules (if not SASS, which is what my Gatsby theme used)
- Footers. I'm currently abusing CSS to hide the next entry button on the home page. I'd like to not be doing that.
- html "components". Again, this is a time/search thing based on direct mapping from the Gatsby theme. I was able to shove the DOM hierarchy and styles I needed into my page loader (and I need to better understand what exactly I can do with these loaders)
Things I'll probably omit:
- Comments. I'm a woman in tech; ain't nobody got time for that.
New features I'm liking:
- Built in post navigation
What I'm most excited about with this approach is that I'll be able to update some of my visualizations automatically via data loaders to maintain current data. It would be particularly interesting to have a live view on my Los Angeles' Soft Story Retrofits and the previous work I did on tracking structural engineering licensure.
Onwards and upwards!