├── .eleventy.js
├── .github
└── workflows
│ └── release.yml
├── .gitignore
├── README.md
├── package.json
└── src
├── alias-template-formats.js
├── compile-options-permalink.js
├── edge-plugin.js
├── empty-formats.js
├── explicit-config-file.js
├── html-output-suffix.js
├── js-yaml.js
├── meta-generator.js
├── node-version.js
├── plugin-land.js
└── serverless-plugin.js
/.eleventy.js:
--------------------------------------------------------------------------------
1 | const pkg = require("./package.json");
2 | const chalk = require("kleur");
3 |
4 | module.exports = function(eleventyConfig) {
5 | try {
6 | eleventyConfig.versionCheck(pkg["11ty"].compatibility);
7 | } catch(e) {
8 | console.error( `${chalk.blue(`[11ty/eleventy-upgrade-help]`)} ${chalk.red(`Plugin Compatibility Error`)} ${e.message}` );
9 | return;
10 | }
11 |
12 | console.log(chalk.blue(`[11ty/eleventy-upgrade-help] ---`));
13 | console.log(chalk.blue(`[11ty/eleventy-upgrade-help]`), `This plugin will help you migrate from 2.0 to 3.0.`);
14 | console.log(chalk.blue(`[11ty/eleventy-upgrade-help]`), `If you are migrating from 0.x or 1.x, please use a previous version of this plugin.`);
15 | console.log(chalk.blue(`[11ty/eleventy-upgrade-help] ---`));
16 |
17 | eleventyConfig.addPlugin(require("./src/meta-generator.js"));
18 |
19 | // Full list of issues: https://github.com/11ty/eleventy/issues?q=milestone%3A%22Eleventy+3.0.0%22+is%3Aclosed+label%3Abreaking-change
20 | eleventyConfig.addPlugin(require("./src/node-version.js"));
21 | eleventyConfig.addPlugin(require("./src/explicit-config-file.js"));
22 | eleventyConfig.addPlugin(require("./src/html-output-suffix.js"));
23 | eleventyConfig.addPlugin(require("./src/alias-template-formats.js"));
24 | eleventyConfig.addPlugin(require("./src/empty-formats.js"));
25 | eleventyConfig.addPlugin(require("./src/plugin-land.js"));
26 | eleventyConfig.addPlugin(require("./src/compile-options-permalink.js"));
27 | eleventyConfig.addPlugin(require("./src/js-yaml.js"));
28 | eleventyConfig.addPlugin(require("./src/serverless-plugin.js"));
29 | eleventyConfig.addPlugin(require("./src/edge-plugin.js"));
30 |
31 | eleventyConfig.on("eleventy.after", () => {
32 | console.log(chalk.blue(`[11ty/eleventy-upgrade-help] This plugin is intended for temporary use: once you’re satisfied please remove this plugin from your project.`));
33 | })
34 | };
--------------------------------------------------------------------------------
/.github/workflows/release.yml:
--------------------------------------------------------------------------------
1 | name: Publish Release to npm
2 | on:
3 | release:
4 | types: [published]
5 | jobs:
6 | build:
7 | runs-on: ubuntu-latest
8 | permissions:
9 | contents: read
10 | id-token: write
11 | steps:
12 | - uses: actions/checkout@v4
13 | - uses: actions/setup-node@v4
14 | with:
15 | node-version: "20"
16 | registry-url: 'https://registry.npmjs.org'
17 | - run: npm install
18 | - run: npm test
19 | - if: ${{ github.event.release.tag_name != '' && env.NPM_PUBLISH_TAG != '' }}
20 | run: npm publish --provenance --access=public --tag=${{ env.NPM_PUBLISH_TAG }}
21 | env:
22 | NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
23 | NPM_PUBLISH_TAG: ${{ contains(github.event.release.tag_name, '-beta.') && 'beta' || 'latest' }}
24 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | package-lock.json
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # eleventy-upgrade-help v3.0
2 |
3 | A plugin to help you upgrade your Eleventy project from Eleventy v2.0 to v3.0.
4 |
5 | Previous versions:
6 |
7 | * [Upgrade from 0.x to 1.0](https://github.com/11ty/eleventy-upgrade-help/tree/v1.x)
8 | * [Upgrade from 1.x to 2.0](https://github.com/11ty/eleventy-upgrade-help/tree/v2.x)
9 |
10 | The major version of this plugin will always match the major version of Eleventy that you’re upgrading to.
11 |
12 | ## Usage
13 |
14 | Upgrade Eleventy with `npm` _before_ using this plugin by running the following command:
15 |
16 | ```bash
17 | npm install @11ty/eleventy@3
18 | ```
19 |
20 | Then, install this plugin:
21 |
22 | ```bash
23 | npm install @11ty/eleventy-upgrade-help@3
24 | ```
25 |
26 | Add to your configuration file (probably `.eleventy.js` or `eleventy.config.js`):
27 |
28 | ```js
29 | const UpgradeHelper = require("@11ty/eleventy-upgrade-help");
30 |
31 | module.exports = function(eleventyConfig) {
32 | // If you have other `addPlugin` calls, UpgradeHelper should be listed last.
33 | eleventyConfig.addPlugin(UpgradeHelper);
34 | };
35 | ```
36 |
37 | Run your usual build command (e.g. `npm run build`) and pay attention to the output.
38 | Address any violations and warnings. Once you’ve removed all of the violations/warnings from your output, run `npm uninstall @11ty/eleventy-upgrade-help` to remove the plugin and delete its code from your Eleventy configuration file.
39 |
40 | ## Example demo
41 |
42 | You can review a [sample project using this upgrade plugin](https://github.com/11ty/demo-eleventy-upgrade-help).
43 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@11ty/eleventy-upgrade-help",
3 | "version": "3.0.1",
4 | "description": "Helper plugin when upgrading your Eleventy project to a new major version.",
5 | "publishConfig": {
6 | "access": "public"
7 | },
8 | "main": ".eleventy.js",
9 | "scripts": {
10 | "test": ""
11 | },
12 | "license": "MIT",
13 | "engines": {
14 | "node": ">=18"
15 | },
16 | "funding": {
17 | "type": "opencollective",
18 | "url": "https://opencollective.com/11ty"
19 | },
20 | "keywords": [
21 | "eleventy",
22 | "11ty"
23 | ],
24 | "author": {
25 | "name": "Zach Leatherman",
26 | "email": "zachleatherman@gmail.com",
27 | "url": "https://zachleat.com/"
28 | },
29 | "repository": {
30 | "type": "git",
31 | "url": "git://github.com/11ty/eleventy-upgrade-help.git"
32 | },
33 | "bugs": "https://github.com/11ty/eleventy-upgrade-help/issues",
34 | "homepage": "https://www.11ty.dev/",
35 | "dependencies": {
36 | "fast-glob": "^3.3.2",
37 | "kleur": "^4.1.5",
38 | "minimist": "^1.2.8",
39 | "posthtml-match-helper": "^2.0.2",
40 | "semver": "^7.6.3"
41 | },
42 | "11ty": {
43 | "compatibility": ">=3 <4"
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/src/alias-template-formats.js:
--------------------------------------------------------------------------------
1 | const chalk = require("kleur");
2 |
3 | module.exports = function(eleventyConfig) {
4 | eleventyConfig.on("eleventy.config", templateConfig => {
5 | let templateFormatsActive = templateConfig.templateFormats.getTemplateFormats();
6 |
7 | if(eleventyConfig.extensionMap.size === 0) {
8 | console.log(chalk.green(`[11ty/eleventy-upgrade-help] PASSED`), `No aliases were added via \`eleventyConfig.addExtension()\`. If you had added an alias, it would need to be also added to your active template formats. Learn more about template formats: https://www.11ty.dev/docs/config/#template-formats or about this change: https://github.com/11ty/eleventy/issues/3302`);
9 | } else {
10 | for(let { key, extension, aliasKey } of eleventyConfig.extensionMap) {
11 | if(!aliasKey) {
12 | continue;
13 | }
14 | if(!templateFormatsActive.includes(extension)) {
15 | console.log(chalk.red(`[11ty/eleventy-upgrade-help] ERROR`), `Aliases added via \`eleventyConfig.addExtension()\` must be added to your active template formats, via \`--formats=${extension}\` on the command line, the \`templateFormats: "${extension}"\` configuration object property, \`eleventyConfig.setTemplateFormats("${extension}")\`, or \`eleventyConfig.addTemplateFormats("${extension}")\` (additive). This *might* be what you want if you added a plugin but don’t want to currently process ${extension} files in Eleventy. Learn more about template formats: https://www.11ty.dev/docs/config/#template-formats or about this change: https://github.com/11ty/eleventy/issues/3302`);
16 | } else {
17 | console.log(chalk.green(`[11ty/eleventy-upgrade-help] PASSED`), `\`${extension}\` is an active template format, referenced as an alias via \`eleventyConfig.addExtension()\`. Learn more about template formats: https://www.11ty.dev/docs/config/#template-formats or about this change: https://github.com/11ty/eleventy/issues/3302`);
18 | }
19 | }
20 |
21 | }
22 | });
23 |
24 | };
--------------------------------------------------------------------------------
/src/compile-options-permalink.js:
--------------------------------------------------------------------------------
1 | const chalk = require("kleur");
2 |
3 | module.exports = function(eleventyConfig) {
4 | for(let { key, compileOptions } of eleventyConfig.extensionMap) {
5 | if(compileOptions && compileOptions.permalink) {
6 | console.log(chalk.green(`[11ty/eleventy-upgrade-help] PASSED`), `The ${key} Custom Template Language has an explicit option that decides how permalinks are rendered in ${key} files. If you didn’t specify this, it would be important to know that the \`compileOptions.permalink\` default was changed from \`true\` to "raw". Docs: https://www.11ty.dev/docs/languages/custom/#compileoptions.permalink-to-override-permalink-compilation GitHub issue: https://github.com/11ty/eleventy/issues/2780`);
7 | } else {
8 | console.log(chalk.yellow(`[11ty/eleventy-upgrade-help] WARNING`), `You will likely want to add a \`compileOptions.permalink\` option for the ${key} Custom Template Language. If you do not explicitly specify this behavior, we will no longer render permalink strings in ${key} syntax. The default for this option changed from \`true\` to "raw". Docs: https://www.11ty.dev/docs/languages/custom/#compileoptions.permalink-to-override-permalink-compilation GitHub issue: https://github.com/11ty/eleventy/issues/2780`);
9 | }
10 | }
11 | };
--------------------------------------------------------------------------------
/src/edge-plugin.js:
--------------------------------------------------------------------------------
1 | const chalk = require("kleur");
2 |
3 | module.exports = function(eleventyConfig) {
4 | console.log(chalk.green(`[11ty/eleventy-upgrade-help] PASSED`), `The Edge plugin was removed from Eleventy core in 3.0. Any use will throw an error, so if you don’t see an error you’re not using it. Learn more: https://www.11ty.dev/docs/plugins/edge/`);
5 | };
--------------------------------------------------------------------------------
/src/empty-formats.js:
--------------------------------------------------------------------------------
1 | const chalk = require("kleur");
2 | const minimist = require("minimist");
3 |
4 | const argv = minimist(process.argv.slice(2), {
5 | string: ["formats"]
6 | });
7 |
8 | module.exports = function(eleventyConfig) {
9 | if(argv.formats || argv.formats === undefined) {
10 | console.log(chalk.green(`[11ty/eleventy-upgrade-help] PASSED`), `You aren’t using \`--formats=\` or \`--formats=''\` but if you were you should know that these are now empty template format sets. In previous versions, they were aliased to "*". Read more: https://github.com/11ty/eleventy/issues/3255`);
11 | } else if(argv.formats === "" || argv.formats === null) {
12 | console.log(chalk.red(`[11ty/eleventy-upgrade-help] ERROR`), `In Eleventy 3.0 \`--formats=""\` and \`formats=\` are empty template format sets. Previous versions aliased these to "*". Use \`--formats=*\` if you want to keep using that behavior in 3.0. Read more: https://github.com/11ty/eleventy/issues/3255`);
13 | }
14 | };
--------------------------------------------------------------------------------
/src/explicit-config-file.js:
--------------------------------------------------------------------------------
1 | const fs = require("node:fs");
2 | const chalk = require("kleur");
3 |
4 | const minimist = require("minimist");
5 |
6 | const argv = minimist(process.argv.slice(2), {
7 | string: ["config"]
8 | });
9 |
10 | module.exports = function(eleventyConfig) {
11 | if(argv.config) {
12 | if(!fs.existsSync(argv.config)) {
13 | // We’ll never get here because the configuration file has to work to run the upgrade plugin.
14 | console.log(chalk.red(`[11ty/eleventy-upgrade-help] ERROR`), `Eleventy will fail with an error when you point \`--config\` to a configuration file that does not exist. Previous versions ran as-is (without application configuration). Read more: https://github.com/11ty/eleventy/issues/3373`);
15 | } else {
16 | console.log(chalk.green(`[11ty/eleventy-upgrade-help] PASSED`), `Eleventy will fail with an error when you point \`--config\` to a configuration file that does not exist. You are using \`--config\` but your configuration file _does_ exist—great! Read more: https://github.com/11ty/eleventy/issues/3373`);
17 | }
18 | } else {
19 | console.log(chalk.green(`[11ty/eleventy-upgrade-help] PASSED`), `Eleventy will fail with an error when you point \`--config\` to a configuration file that does not exist. You are not using \`--config\`—so don’t worry about it! Read more: https://github.com/11ty/eleventy/issues/3373`);
20 | }
21 |
22 | };
--------------------------------------------------------------------------------
/src/html-output-suffix.js:
--------------------------------------------------------------------------------
1 | const chalk = require("kleur");
2 |
3 | // https://v2-0-1.11ty.dev/docs/languages/html/#using-the-same-input-and-output-directories
4 | module.exports = function(eleventyConfig) {
5 | eleventyConfig.on("eleventy.config", (templateConfig) => {
6 | if(!("htmlOutputSuffix" in templateConfig.config)) {
7 | console.log(chalk.green(`[11ty/eleventy-upgrade-help] PASSED`), `The \`htmlOutputSuffix\` feature was removed. It doesn’t look like you were using it! Learn more: https://github.com/11ty/eleventy/issues/3327`);
8 | } else {
9 | console.log(chalk.red(`[11ty/eleventy-upgrade-help]`), chalk.red(`ERROR`), `The \`htmlOutputSuffix\` feature was removed. Learn more: https://github.com/11ty/eleventy/issues/3327`);
10 | }
11 | })
12 |
13 | // Input and output are the same
14 | if(eleventyConfig.directories.input === eleventyConfig.directories.output) {
15 | console.log(chalk.blue(`[11ty/eleventy-upgrade-help] NOTICE`), `Your input and output folders are identical so please take note that Eleventy will now throw an error if any of your output files attempt to overwrite your input files. Learn more: https://github.com/11ty/eleventy/issues/3327`);
16 | }
17 | };
--------------------------------------------------------------------------------
/src/js-yaml.js:
--------------------------------------------------------------------------------
1 | const chalk = require("kleur");
2 |
3 | module.exports = function(eleventyConfig) {
4 | console.log(chalk.blue(`[11ty/eleventy-upgrade-help] NOTICE`), `The \`js-yaml\` dependency was upgraded from v3 to v4 to improve error messaging when folks use tabs in their front matter. GitHub issue: https://github.com/11ty/eleventy/issues/2126 Most folks will be unaffected by this change but you can read the \`js-yaml\` migration guide: https://github.com/nodeca/js-yaml/blob/master/migrate_v3_to_v4.md`);
5 | };
--------------------------------------------------------------------------------
/src/meta-generator.js:
--------------------------------------------------------------------------------
1 | const chalk = require("kleur");
2 |
3 | module.exports = async function(eleventyConfig) {
4 | const { default: matchHelper } = await import("posthtml-match-helper");
5 |
6 | let htmlTemplatesMissingMetaGenerator = new Set();
7 | let found = 0;
8 |
9 | eleventyConfig.on("eleventy.before", () => {
10 | htmlTemplatesMissingMetaGenerator = new Set();
11 | found = 0;
12 | });
13 |
14 | eleventyConfig.on("eleventy.after", () => {
15 | if(htmlTemplatesMissingMetaGenerator.size > 0) {
16 | console.log(chalk.blue(`[11ty/eleventy-upgrade-help] NOTICE`), `Your project has .html output files (×${htmlTemplatesMissingMetaGenerator.size}) that don’t have a populated tag. It would be helpful to Eleventy if you added it (but isn’t required). Applicable input files: ${Array.from(htmlTemplatesMissingMetaGenerator).join(", ")} Read more: https://www.11ty.dev/docs/data-eleventy-supplied/#use-with-meta-namegenerator`);
17 | } else {
18 | console.log(chalk.green(`[11ty/eleventy-upgrade-help] PASSED`), `All of your project’s .html output files (×${found}) are using `);
19 | }
20 | });
21 |
22 | eleventyConfig.htmlTransformer.addPosthtmlPlugin(
23 | "html",
24 | function (options) {
25 | return function (tree) {
26 | let missing = 1;
27 |
28 | tree.match(matchHelper(`meta[name="generator"]`), function (node) {
29 | if (node.attrs?.content && (node.attrs?.content || "").toLowerCase().startsWith("eleventy")) {
30 | missing--;
31 | }
32 |
33 | return node;
34 | });
35 |
36 | if(missing > 0) {
37 | htmlTemplatesMissingMetaGenerator.add(options.page.inputPath);
38 | } else {
39 | found++;
40 | }
41 | };
42 | }
43 | );
44 | };
--------------------------------------------------------------------------------
/src/node-version.js:
--------------------------------------------------------------------------------
1 | const chalk = require("kleur");
2 |
3 | module.exports = function(eleventyConfig) {
4 | // This throws an error in Eleventy core, so if we’ve made it here—we’ve passed the test.
5 | console.log(chalk.green(`[11ty/eleventy-upgrade-help]`), chalk.green("PASSED"), `You are using Node ${process.version}. Node 18 or newer is required.`);
6 | };
--------------------------------------------------------------------------------
/src/plugin-land.js:
--------------------------------------------------------------------------------
1 | const chalk = require("kleur");
2 | const fastglob = require("fast-glob");
3 |
4 | module.exports = function(eleventyConfig) {
5 | let installedPlugins = {};
6 | for(let { key, extension, aliasKey } of eleventyConfig.extensionMap) {
7 | installedPlugins[key] = true;
8 | }
9 |
10 | let allRemovedKeys = "pug,ejs,haml,mustache,handlebars".split(",");
11 | let notFound = [];
12 |
13 | for(let removedKey of allRemovedKeys) {
14 | let foundFiles = fastglob.sync(`${eleventyConfig.directories.input}**/*.${removedKey}`);
15 | if(foundFiles.length > 0) {
16 | if( !installedPlugins[removedKey]) {
17 | console.log(chalk.red(`[11ty/eleventy-upgrade-help] ERROR`), `Found ${foundFiles.length} ${removedKey} file${foundFiles.length !== 1 ? "s" : ""} in your project but the ${removedKey} plugin was moved from core to an officially supported plugin. You will need to add the plugin for ${removedKey}, available here: https://github.com/11ty/eleventy-plugin-template-languages and you can learn more about this here: https://github.com/11ty/eleventy/issues/3124`);
18 | } else {
19 | console.log(chalk.green(`[11ty/eleventy-upgrade-help] PASSED`), `You have installed the ${removedKey} plugin to handle the ${foundFiles.length} ${removedKey} file${foundFiles.length !== 1 ? "s" : ""} in your project. Learn more: https://github.com/11ty/eleventy/issues/3124`);
20 | }
21 | } else {
22 | notFound.push(removedKey);
23 | }
24 | }
25 |
26 | if(notFound.length > 0) {
27 | console.log(chalk.green(`[11ty/eleventy-upgrade-help] PASSED`), `No {${notFound.join(",")}} templates were found in this project. If you were, you would have needed to install plugins for these: https://github.com/11ty/eleventy-plugin-template-languages. Learn more: https://github.com/11ty/eleventy/issues/3124`);
28 | }
29 | };
--------------------------------------------------------------------------------
/src/serverless-plugin.js:
--------------------------------------------------------------------------------
1 | const chalk = require("kleur");
2 |
3 | module.exports = function(eleventyConfig) {
4 | console.log(chalk.green(`[11ty/eleventy-upgrade-help] PASSED`), `The Serverless plugin was removed from Eleventy core in 3.0. Any use will throw an error, so if you don’t see an error you’re not using it. Learn more: https://www.11ty.dev/docs/plugins/serverless/`);
5 | };
--------------------------------------------------------------------------------