Auto-Generated Last Modified Date in Astro
Part of the Astro series
I’m trying to figure out how to use remark plugins in Astro to modify a couple things in posts for me automatically, and along the way I’ve used remark to add a couple quality of life improvements. The first is an auto-generated table of contents for longer posts that I feel need one, and the second is an auto-generated last modified date for pages based on git commit timestamps.
The benefit of an automatically generated last modified date is that I don’t have to remember to update it when I make changes to a page that displays it, like my now page or my links page. I can just commit my changes and the last modified date will update automatically. It’s simple, but it’s kind of beautiful.
I basically did exactly what Astro’s documentation says to do in a helpful recipe called Add last modified time. I created a file called remark-modified-time.mjs and put it in my src/components/utilities folder.1
import { execSync } from "child_process";
export function remarkModifiedTime() { return function (tree, file) { const filepath = file.history[0]; const result = execSync(`git log -1 --pretty="format:%cI" "${filepath}"`); file.data.astro.frontmatter.lastModified = result.toString(); };}
Then I updated my astro.config.mjs file to reference this as a remark plugin, and to use it in my markdown processing.
import { defineConfig } from "astro/config";import expressiveCode from "astro-expressive-code";import icon from "astro-icon";import pagefind from "astro-pagefind";import { remarkModifiedTime } from './src/components/utilities/remark-modified-time.mjs';import remarkToc from 'remark-toc';
/** @type {import('astro-expressive-code').AstroExpressiveCodeOptions} */const astroExpressiveCodeOptions = { // Example: Change the themes themes: ["material-theme-ocean", "light-plus", "github-dark-dimmed"], themeCssSelector: (theme) => `[data-theme='${theme.name}']`,}
// https://astro.build/configexport default defineConfig({ site: "https://scottwillsey.com/", integrations: [expressiveCode(astroExpressiveCodeOptions), icon(), pagefind()], markdown: { remarkPlugins: [ remarkModifiedTime, [remarkToc, { heading: "contents" } ] ], },});
Once those are set up, it’s just a matter of referencing remarkPluginFrontMatter.lastModified in the Astro template.
---import { getEntry } from "astro:content";import { Icon } from "astro-icon/components";import Base from "../layouts/Base.astro";import { modifieddate } from "../components/utilities/DateFormat.js";
const now = await getEntry("now", "now");const { Content, remarkPluginFrontmatter } = await now.render();
let title = now.data.title;let description = now.data.description;---
<Base title={title} description={description}> <article> <h1>{title}</h1> <p class="now"> The <a href="https://nownownow.com/about">"now page"</a> concept comes from an idea by <a href="https://sive.rs">Derek Sivers</a> to have people communicate what they're focused on <b>now</b> at this point in their lives. </p> <div class="time"> <Icon name="bi:calendar2-week-fill" /> <time datetime={now.data.date}> <a href={`/${now.slug}`} >Last updated {modifieddate(remarkPluginFrontmatter.lastModified)}</a > </time> </div> <div class="now"> <Content /> </div> </article></Base>
That’s it. Now I have auto-generated last modified dates for any page I feel needs one, thanks to Astro using remark to render markdown and therefore making adding remark plugins super simple.
Footnotes
-
You can put your remark plugin anywhere you want, as long as you reference the path correctly in astro.config.mjs. ↩