Get good Git info from Eleventy, too

While per-page Git data is built into Hugo, a little code can bring it to Eleventy, as well.

2022-09-05

Note: This post also appears on dev.to.

Update from the future: Although the data and formatting in each page’s header differ from what’s described in this post, the code blocks contained herein are still accurate and usable.

In “Get good Git info from Hugo,” I explained how to use the Hugo static site generator (SSG)’s built-in Git info variables to display page-by-page Git commit data for one’s static website. Well, lo and behold, you can get that kind of information in the Eleventy SSG, too. You just need to add a little code, in the form of a shortcode that takes advantage of Eleventy-supplied data.

It requires CI/CD

The one potential kink to this for you is that, in order for this to work best, you’ll have to use a CI/CD method of deploying your site. For anybody likely to find this article, you’ll typically be using either GitHub Actions or GitLab CI/CD. The reason this is necessary is because this method uses git log, and — at least as far as I know — there’s no way to use any of the Jamstack-savvy web hosts’ UIs to specify fetch-depth: 0, which is necessary for this to work.

Note from the future: In testing for a later article, I found that, in fact, Netlify and DigitalOcean App Platform exhibit deep-clone behavior where Git is concerned, so you likely can use the information herein with their native UIs rather than having to deploy to them via CI/CD.
Moreover, as I mentioned in another, later article, it turns out that Cloudflare Pages will perform a sufficiently deep clone if you preface your build command with git fetch --unshallow followed by the && concatenation operator; e.g.:
git fetch --unshallow && npm run build

It’s outside the scope of this article to explain the CI/CD part, but I’ve written other posts about it (see my search page, especially regarding GitHub Actions) which you may find useful in pressing ahead with it.

The shortcode: go easy

In putting together this shortcode, we’ll follow the advice I gave in “Take a load off” about how not to overtax your development environment. While that article was about limiting accesses of remote APIs, it also applies to getting Git data. This is because git log is notorious for its potentially high impact on local device performance; it was built to be comprehensive, not to save CPU cycles. Thus, we’ll set the shortcode, which I call gitinfo.js, so that it does the heavy lifting only in production.

Of course, be sure to enable gitinfo.js (or whatever you choose to call it) in your Eleventy config file through the usual procedure.

Note that gitinfo.js assumes you have installed the luxon package, to be used here for formatting dates from Git commit data. (On the other hand, child_process is included in Node.js.) Notice also that you’ll have to supply, in the repoLink variable, the URL for your online repo’s commits.

gitinfo.js

const { DateTime } = require("luxon")
const childProcess = require('child_process')
const environment = process.env.NODE_ENV

module.exports = (pubdate, filename) => {
	let stringToRet = ``
	if (environment === "production") {
		let repoLink = ``
		/* ================
			For `repoLink`, fill in the starting URL
			for commits to your project's online repo!
			If you use GitHub, it'll usually be
			in the format of:
			https://github.com/your-github-name/your-repo-name/commit/
		================ */
		pubdate = DateTime.fromJSDate(pubdate).toFormat("yyyy-MM-dd")

		const lastUpdatedFromGit =
			childProcess
			.execSync(`git log -1 --format=%cd --date=short ${filename}`)
			.toString()
			.trim()

		const abbrevHash =
			childProcess
			.execSync(`git log -1 --pretty=format:"%h" ${filename}`)
			.toString()
			.trim()

		const longHash =
			childProcess
			.execSync(`git log -1 --pretty=format:"%H" ${filename}`)
			.toString()
			.trim()

		repoLink += longHash

		if (longHash !== '') {
			stringToRet = `Latest commit: <a class="mono" href="${repoLink}" rel="noopener">${abbrevHash}</a>`
			if (pubdate !== lastUpdatedFromGit) {
				stringToRet += `, ${lastUpdatedFromGit}`
			}
		} else {
			stringToRet = `&nbsp;`
		}

	} else {
		stringToRet = `[Git info will appear here in production.]`
	}

	return stringToRet
}

You may have noticed that the shortcode took two parameters: pubdate and filename. Here’s where the Eleventy-supplied data comes in. Wherever you want the Git data to occur, use the gitinfo shortcode as follows:

{% gitinfo page.date, page.inputPath %}

This will automatically feed to gitinfo a Markdown file’s date (derived by default from the file’s front matter but, if it’s not there, Eleventy has fallbacks) and inputPath. In a typical Eleventy repo, inputPath takes this form:

./src/path/to/my-markdown-file.md

As for the final message conveyed in your site by stringToRet, you’re obviously free to make stringToRet say what works best for your site. The main thing is that the code here shows you how to get the data that it needs in the first place. And, to be specific about that data, in production the gitinfo shortcode invocation brings back a string containing:

  • lastUpdatedFromGit — The date of the file’s last Git commit in yyyy-mm-dd format. (If this is on the same day as the initial date of publication, lastUpdatedFromGit doesn’t appear.)
  • abbrevHash and longHash — The short and long versions, respectively, of the commit’s hash. The returned string combines repoLink with longHash to produce the URL to which it then links abbrevHash.

If you typically show each page’s initial publication date and last-modified date, you can choose to avoid worrying about that latter part from here on by just using gitinfo’s output, instead. (Some prefer to provide the last-modified info manually, to indicate only true content changes; by contrast, gitinfo can report only the last time the file was changed/committed at all, even if just to eliminate a totally invisible empty line someplace.)

So, while it’s indeed cool that Hugo wields Git info-handling prowess out of the box, this shortcode gives Eleventy the same powers. (I’ll avoid the “great responsibility” trope.) Perhaps you can make good use of them.

NEXT   

PREVIOUS