sc
Scott avatar
ttwillsey

Auto-Generated Last Modified Date in Astro

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.

remark-modified-time.mjs
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.

astro.config.mjs
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/config
export 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.

now.astro
---
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.

Last updated indicator