Displaying Eleventy Version On A Page
Posted: Sunday, December 29, 2024 at 11:25 AM | Categories: Eleventy, Static Site Generators
Update: Soon after I posted a link to this article on Mastodon, the Eleventy team responded with
@johnwargo you needn’t parse your package.json for a meta generator element: you can use
Eleventy v2.0.1
directly, it’s supplied for free by Eleventy! Docs: https://www.11ty.dev/docs/data-eleventy-supplied/#use-with-meta-namegenerator
So it turns out you don't need any of the stuff that follows. :-)
A while back, I added the Eleventy build details to the footer of this site; here's what it looks like today:
Doing this was pretty easy. First, I added a data file to the site, creating a file called eleventyinfo.js
in the site's _data
folder (_data/eleventyinfo.js
) with the following code:
'use strict'
const eleventyPackage = require('@11ty/eleventy/package.json')
module.exports = function () {
return { generatorStr: `${eleventyPackage.name} v${eleventyPackage.version}` }
}
The code loads the Eleventy package.json
file as an object using require()
, then returns an object with a string representing the package name and package version.
With that in place, any page in the site can display the generatorStr
value using eleventyinfo.generatorStr
. So, in the site's footer is the code that displays the value shown in the image above.
<footer id="footer">
<div class="copyright">
© John M. Wargo; All rights reserved | Powered by <a href="https://www.11ty.dev/" target="_blank">{{ eleventyinfo.generatorStr }}</a> | Template by <a href="https://pixelarity.com/" target="_blank">Pixelarity (Faction)</a>
</div>
</footer>
This worked very well for a long time, but when I started playing around with Eleventy 3, the code broke. On an Eleventy 3.x site, building the site with that code in place generates the following error:
[11ty] Problem writing Eleventy templates:
[11ty] Package subpath './package.json' is not defined by "exports" in D:\dev\11ty\site-name\node_modules\@11ty\eleventy\package.json
[11ty]
[11ty] Original error stack trace: Error [ERR_PACKAGE_PATH_NOT_EXPORTED]: Package subpath './package.json' is not defined by "exports" in D:\dev\11ty\site-name\node_modules\@11ty\eleventy\package.json
[11ty] at exportsNotFound (node:internal/modules/esm/resolve:314:10)
[11ty] at packageExportsResolve (node:internal/modules/esm/resolve:662:9)
[11ty] at resolveExports (node:internal/modules/cjs/loader:640:36)
[11ty] at Function._findPath (node:internal/modules/cjs/loader:748:31)
[11ty] at Function._resolveFilename (node:internal/modules/cjs/loader:1235:27)
[11ty] at Function._load (node:internal/modules/cjs/loader:1075:27)
[11ty] at TracingChannel.traceSync (node:diagnostics_channel:322:14)
[11ty] at wrapModuleLoad (node:internal/modules/cjs/loader:219:24)
[11ty] at Module.require (node:internal/modules/cjs/loader:1340:12)
[11ty] at require (node:internal/modules/helpers:138:16)
[11ty] Wrote 0 files in 0.21 seconds (v3.0.0)
ERROR: "build:eleventy" exited with 1.
A quick online search took me to the following Google AI generated message:
The error message "Package subpath './package.json' is not defined by 'exports'" in Eleventy means that you're trying to import a file directly from your project's package.json file, but your package.json file is configured to only export specific modules through the "exports" field, and the root directory (where package.json resides) is not explicitly included in those exports
I'm not an expert, but I generally understand what the error is telling me and since I won't be able to modify the source package file, I had to look for other solutions.
Fix for Eleventy 3
I didn't spend a lot of time researching the best solution, I just leveraged my existing JavaScript capabilities and came up with this, changing the name of the file from eleventyinfo.js
to eleventyinfo.mjs
:
import fs from 'fs';
export default function () {
const packageJson = JSON.parse(fs.readFileSync('./node_modules/@11ty/eleventy/package.json', 'utf8'));
return { generatorStr: `${packageJson.name} v${packageJson.version}` }
}
Instead of loading the package through require
, the code just reads the package.json
file directly from the Eleventy package folder ./node_modules/@11ty/eleventy/package.json
then uses JSON.parse
method to convert it to a JavaScript object.
That's it, it works great. Its a hack and I'm not that proud of it, but it works.
Alternative Option
My existing approach return a string, and that supports my use case very well. If I needed the package properties as separate values, I could use:
import fs from 'fs';
export default function () {
const packageJson = JSON.parse(fs.readFileSync('./node_modules/@11ty/eleventy/package.json', 'utf8'));
return {
packageName: packageJson.name,
packageVersion: packageJson.version
}
}
Then, in the site content, reference the individual properties like this:
<p class="copyright">Powered by <a href="https://www.11ty.dev/" target="_blank" >{{ eleventyinfo.packageName}} {{eleventyinfo.packageVersion}}</a>.</p>
Next Post: Eleventy 3 Upgrade
Previous Post: Upgrading Old Flutter Apps
If this content helps you in some way, please consider buying me a coffee.
Header image: Eleventy Project Home Page.