@11ty/eleventy
Advanced tools
| const POSTHTML_PLUGIN_NAME = "11ty/eleventy/preserve-closing-tags"; | ||
| export function PreserveClosingTagsPlugin(eleventyConfig, options = {}) { | ||
| // TODO error on non-void eligible tag names | ||
| if (!options.tags) { | ||
| // "meta" | ||
| options.tags = []; | ||
| } | ||
| if (!Array.isArray(options.tags)) { | ||
| throw new Error("`tags` passed to the Preserve Closing Tags plugin must be an Array"); | ||
| } | ||
| const tagMatches = options.tags.map((tag) => ({ tag })); | ||
| if (tagMatches.length === 0) { | ||
| return; | ||
| } | ||
| eleventyConfig.htmlTransformer.addPosthtmlPlugin( | ||
| "html", | ||
| function preserveClosingTagsPlugin(pluginOptions = {}) { | ||
| return function (tree) { | ||
| tree.match(tagMatches, function (node) { | ||
| node.closeAs = "slash"; // close eligible tags as `<meta />` and not `<meta>` | ||
| return node; | ||
| }); | ||
| }; | ||
| }, | ||
| { | ||
| // pluginOptions | ||
| name: POSTHTML_PLUGIN_NAME, | ||
| }, | ||
| ); | ||
| } |
| function canRequireTypeScript() { | ||
| try { | ||
| let res = require("./TypeScript/TypeScriptSample.cts"); | ||
| return typeof res === "function"; | ||
| } catch(e) { | ||
| // Not supported in node_modules, but we know it is supported! | ||
| if(e.code === "ERR_UNSUPPORTED_NODE_MODULES_TYPE_STRIPPING") { | ||
| return true; | ||
| } | ||
| return false; | ||
| } | ||
| } | ||
| const TYPESCRIPT_ENABLED = canRequireTypeScript(); | ||
| module.exports.isTypeScriptSupported = function() { | ||
| return TYPESCRIPT_ENABLED; | ||
| } |
| module.exports.isTypeScriptSupported = function() { | ||
| return false; | ||
| } |
| module.exports = function(b: boolean, s: string) {} |
+11
-0
@@ -33,2 +33,12 @@ #!/usr/bin/env node | ||
| // Defensive use of Node 22.8+ Module Compile Cache | ||
| if(!process.env?.ELEVENTY_SKIP_NODE_COMPILE_CACHE) { | ||
| try { | ||
| const nodeMod = await import('node:module').then(mod => mod.default); | ||
| nodeMod.enableCompileCache?.(); | ||
| } catch(e) { | ||
| debug("Node compile cache error (optional API) %o", e); | ||
| } | ||
| } | ||
| try { | ||
@@ -154,2 +164,3 @@ const argv = minimist(process.argv.slice(2), { | ||
| // await | ||
| exec(); |
+29
-29
| { | ||
| "name": "@11ty/eleventy", | ||
| "version": "4.0.0-alpha.6", | ||
| "version": "4.0.0-alpha.7", | ||
| "description": "A simpler static site generator.", | ||
@@ -100,40 +100,40 @@ "publishConfig": { | ||
| "@11ty/eleventy-img": "^6.0.4", | ||
| "@11ty/eleventy-plugin-rss": "^2.0.4", | ||
| "@11ty/eleventy-plugin-rss": "^3.0.0", | ||
| "@11ty/eleventy-plugin-syntaxhighlight": "^5.0.2", | ||
| "@11ty/eleventy-plugin-webc": "^0.12.0-beta.7", | ||
| "@eslint/js": "^9.39.1", | ||
| "@eslint/js": "^10.0.1", | ||
| "@iarna/toml": "^2.2.5", | ||
| "@mdx-js/node-loader": "^3.1.1", | ||
| "@stylistic/eslint-plugin-js": "^4.4.1", | ||
| "@types/node": "^22.19.1", | ||
| "@vue/server-renderer": "^3.5.25", | ||
| "@zachleat/noop": "^1.0.6", | ||
| "@types/node": "^25.5.0", | ||
| "@vue/server-renderer": "^3.5.30", | ||
| "@zachleat/noop": "^1.0.7", | ||
| "ava": "^6.4.1", | ||
| "c8": "^10.1.3", | ||
| "c8": "^11.0.0", | ||
| "cross-env": "^10.1.0", | ||
| "eslint": "^9.39.1", | ||
| "eslint": "^10.1.0", | ||
| "eslint-config-prettier": "^10.1.8", | ||
| "globals": "^16.5.0", | ||
| "jsx-async-runtime": "^1.0.4", | ||
| "globals": "^17.4.0", | ||
| "jsx-async-runtime": "^2.0.3", | ||
| "luxon": "^3.7.2", | ||
| "markdown-it-abbr": "^2.0.0", | ||
| "markdown-it-emoji": "^3.0.0", | ||
| "marked": "^15.0.12", | ||
| "nano-staged": "^0.8.0", | ||
| "prettier": "^3.7.1", | ||
| "marked": "^17.0.5", | ||
| "nano-staged": "^0.9.0", | ||
| "prettier": "^3.8.1", | ||
| "pretty": "^2.0.0", | ||
| "react": "^19.2.1", | ||
| "react-dom": "^19.2.1", | ||
| "rimraf": "^6.1.2", | ||
| "sass": "^1.94.2", | ||
| "react": "^19.2.4", | ||
| "react-dom": "^19.2.4", | ||
| "sass": "^1.98.0", | ||
| "simple-git-hooks": "^2.13.1", | ||
| "tsx": "^4.20.6", | ||
| "tsx": "^4.21.0", | ||
| "typescript": "^5.9.3", | ||
| "vue": "^3.5.25", | ||
| "zod": "^3.25.76", | ||
| "zod-validation-error": "^3.5.4" | ||
| "vue": "^3.5.30", | ||
| "zod": "^4.3.6", | ||
| "zod-validation-error": "^5.0.0" | ||
| }, | ||
| "dependencies": { | ||
| "@11ty/dependency-tree": "^4.0.1", | ||
| "@11ty/dependency-tree-esm": "^2.0.3", | ||
| "@11ty/dependency-tree": "^4.0.2", | ||
| "@11ty/dependency-tree-esm": "^2.0.4", | ||
| "@11ty/dependency-tree-typescript": "^1.0.0", | ||
| "@11ty/eleventy-dev-server": "^3.0.0-alpha.6", | ||
@@ -148,3 +148,3 @@ "@11ty/eleventy-plugin-bundle": "^3.0.7", | ||
| "@11ty/posthtml-urls": "^1.0.2", | ||
| "@11ty/recursive-copy": "^5.0.0", | ||
| "@11ty/recursive-copy": "^5.0.2", | ||
| "@sindresorhus/slugify": "^3.0.0", | ||
@@ -155,10 +155,10 @@ "bcp-47-normalize": "^2.3.0", | ||
| "dependency-graph": "^1.0.0", | ||
| "entities": "^7.0.0", | ||
| "entities": "^8.0.0", | ||
| "import-module-string": "^2.0.3", | ||
| "iso-639-1": "^3.1.5", | ||
| "kleur": "^4.1.5", | ||
| "liquidjs": "^10.24.0", | ||
| "markdown-it": "^14.1.0", | ||
| "liquidjs": "^10.25.0", | ||
| "markdown-it": "^14.1.1", | ||
| "minimist": "^1.2.8", | ||
| "moo": "^0.5.2", | ||
| "moo": "0.5.2", | ||
| "node-retrieve-globals": "^6.0.1", | ||
@@ -168,3 +168,3 @@ "picomatch": "^4.0.3", | ||
| "posthtml-match-helper": "^2.0.3", | ||
| "semver": "^7.7.3", | ||
| "semver": "^7.7.4", | ||
| "tinyglobby": "^0.2.15" | ||
@@ -171,0 +171,0 @@ }, |
+15
-7
@@ -722,2 +722,3 @@ import debugUtil from "debug"; | ||
| } | ||
| if (this.loader == "esm") { | ||
@@ -728,3 +729,9 @@ this.#isEsm = true; | ||
| } else if (this.loader == "auto") { | ||
| this.#isEsm = this.projectPackageJson?.type === "module"; | ||
| // Note: Node defaults to CommonJS if missing, Deno defaults to ESM | ||
| // https://docs.deno.com/runtime/fundamentals/node/#commonjs-support | ||
| if (typeof Deno !== "undefined") { | ||
| this.#isEsm = this.projectPackageJson?.type !== "commonjs"; | ||
| } else { | ||
| this.#isEsm = this.projectPackageJson?.type === "module"; | ||
| } | ||
| } else { | ||
@@ -939,15 +946,16 @@ throw new Error("The 'loader' option must be one of 'esm', 'cjs', or 'auto'"); | ||
| let cfgStr = this.#activeConfigurationPath | ||
| ? `, ${TemplatePath.stripLeadingDotSlash(this.#activeConfigurationPath)}` | ||
| : " no config file"; | ||
| // More than 1 second total, show estimate of per-template time | ||
| if (time >= 1 && writeCount > 1) { | ||
| ret.push(`(${((time * 1000) / writeCount).toFixed(1)}ms each, v${pkg.version})`); | ||
| ret.push( | ||
| chalk.gray(`(${((time * 1000) / writeCount).toFixed(1)}ms each, v${pkg.version}${cfgStr})`), | ||
| ); | ||
| } else { | ||
| ret.push(`(v${MinimalCore.getVersion()})`); | ||
| ret.push(chalk.gray(`(v${MinimalCore.getVersion()}${cfgStr})`)); | ||
| } | ||
| if (!this.#activeConfigurationPath) { | ||
| ret.push("(no config file)"); | ||
| } | ||
| return ret.join(" "); | ||
| } | ||
| } |
@@ -16,2 +16,3 @@ import path from "node:path"; | ||
| import ReservedData from "../Util/ReservedData.js"; | ||
| import { isTypeScriptSupported } from "../Util/FeatureTests.cjs"; | ||
@@ -177,2 +178,8 @@ const { set: lodashSet, get: lodashGet } = lodash; | ||
| globSuffixesWithLeadingDot.add(`${suffix.slice(1)}.js`); | ||
| if (isTypeScriptSupported()) { | ||
| globSuffixesWithLeadingDot.add(`${suffix.slice(1)}.mts`); | ||
| globSuffixesWithLeadingDot.add(`${suffix.slice(1)}.cts`); | ||
| globSuffixesWithLeadingDot.add(`${suffix.slice(1)}.ts`); | ||
| } | ||
| } else { | ||
@@ -183,2 +190,8 @@ // "suffix.js" without leading dot | ||
| globSuffixesWithoutLeadingDot.add(`${suffix || ""}.js`); | ||
| if (isTypeScriptSupported()) { | ||
| globSuffixesWithoutLeadingDot.add(`${suffix || ""}.mts`); | ||
| globSuffixesWithoutLeadingDot.add(`${suffix || ""}.cts`); | ||
| globSuffixesWithoutLeadingDot.add(`${suffix || ""}.ts`); | ||
| } | ||
| } | ||
@@ -215,3 +228,3 @@ } | ||
| // paths.push(`${this.inputDir}/**/*${suffix || ""}.cjs`); // Same as above | ||
| paths.push(`${this.inputDir}**/*${suffix || ""}.js`); | ||
| paths.push(`${this.inputDir}**/*${suffix || ""}.js`); // TODO typescript? | ||
| } | ||
@@ -218,0 +231,0 @@ } |
+2
-0
@@ -613,2 +613,4 @@ import { relative } from "node:path"; | ||
| export { PreserveClosingTagsPlugin } from "./Plugins/PreserveClosingTagsPlugin.js"; | ||
| // Error messages for Removed plugins | ||
@@ -615,0 +617,0 @@ export function EleventyServerlessBundlerPlugin() { |
@@ -31,4 +31,4 @@ function canRequireModules() { | ||
| 4. Upgrade your Node version (at time of writing, v22.12 or newer) to enable this behavior. If you use a version | ||
| of Node older than v22.12, try the --experimental-require-module command line flag in Node. Read more: | ||
| 4. Upgrade your Node version (at time of writing, v20.19 or newer) to enable this behavior. If you use a version | ||
| of Node older than v20.19, try the --experimental-require-module command line flag in Node. Read more: | ||
| https://nodejs.org/api/modules.html#loading-ecmascript-modules-using-require`); | ||
@@ -35,0 +35,0 @@ |
| import { TemplatePath } from "@11ty/eleventy-utils"; | ||
| import { isTypeScriptSupported } from "./Util/FeatureTests.cjs"; | ||
| class EleventyExtensionMap { | ||
@@ -268,2 +270,8 @@ #engineManager; | ||
| if (isTypeScriptSupported()) { | ||
| this._extensionToKeyMap["11ty.ts"] = { key: "11ty.js", extension: "11ty.ts" }; | ||
| this._extensionToKeyMap["11ty.cts"] = { key: "11ty.js", extension: "11ty.cts" }; | ||
| this._extensionToKeyMap["11ty.mts"] = { key: "11ty.js", extension: "11ty.mts" }; | ||
| } | ||
| if ("extensionMap" in this.config) { | ||
@@ -270,0 +278,0 @@ for (let entry of this.config.extensionMap) { |
@@ -29,3 +29,3 @@ import matchHelper from "posthtml-match-helper"; | ||
| function IdAttributePlugin(eleventyConfig, options = {}) { | ||
| export function IdAttributePlugin(eleventyConfig, options = {}) { | ||
| if (!options.slugify) { | ||
@@ -108,3 +108,1 @@ options.slugify = eleventyConfig.getFilter("slugify"); | ||
| } | ||
| export { IdAttributePlugin }; |
@@ -101,3 +101,3 @@ import path from "node:path"; | ||
| let inputDir = eleventyConfig.directories.input; | ||
| let suffix = ""; | ||
| let suffix; | ||
| [suffix, targetFilePath] = parseFilePath(targetFilePath); | ||
@@ -148,3 +148,3 @@ if (targetFilePath) { | ||
| let suffix = ""; | ||
| let suffix; | ||
| [suffix, targetFilepathOrUrl] = parseFilePath(targetFilepathOrUrl); | ||
@@ -151,0 +151,0 @@ if (targetFilepathOrUrl) { |
@@ -54,3 +54,7 @@ import { readFileSync } from "node:fs"; | ||
| tr.engine.name === "11ty.cjs" || | ||
| tr.engine.name === "11ty.mjs" | ||
| tr.engine.name === "11ty.mjs" || | ||
| // TODO Node 22+ | ||
| tr.engine.name === "11ty.ts" || | ||
| tr.engine.name === "11ty.cts" || | ||
| tr.engine.name === "11ty.mts" | ||
| ) { | ||
@@ -275,3 +279,3 @@ throw new Error( | ||
| let str = ""; | ||
| let matches = null; | ||
| let matches; | ||
@@ -278,0 +282,0 @@ // Exit when there's nothing to match |
@@ -1,2 +0,1 @@ | ||
| import { existsSync } from "node:fs"; | ||
| import { Merge, TemplatePath, isPlainObject } from "@11ty/eleventy-utils"; | ||
@@ -14,2 +13,3 @@ import debugUtil from "debug"; | ||
| import ProjectTemplateFormats from "./Util/ProjectTemplateFormats.js"; | ||
| import { isTypeScriptSupported } from "./Util/FeatureTests.cjs"; | ||
@@ -83,2 +83,8 @@ const debug = debugUtil("Eleventy:TemplateConfig"); | ||
| ]; | ||
| if (isTypeScriptSupported()) { | ||
| this.projectConfigPaths.push("eleventy.config.ts"); | ||
| this.projectConfigPaths.push("eleventy.config.mts"); | ||
| this.projectConfigPaths.push("eleventy.config.cts"); | ||
| } | ||
| } | ||
@@ -85,0 +91,0 @@ |
@@ -922,8 +922,8 @@ import debugUtil from "debug"; | ||
| // Array support added in 2.0.0-canary.19 | ||
| // Array support 2.0.0-canary.19+ | ||
| if (Array.isArray(fileExtension)) { | ||
| extensions = fileExtension; | ||
| } else { | ||
| // single string | ||
| extensions = [fileExtension]; | ||
| // Comma separated support 4.0.0-alpha.7+ | ||
| extensions = (fileExtension || "").split(","); | ||
| } | ||
@@ -930,0 +930,0 @@ |
@@ -18,2 +18,3 @@ import posthtml from "posthtml"; | ||
| recognizeNoValueAttribute: true, | ||
| closingSingleTag: "closeAs", | ||
| }; | ||
@@ -20,0 +21,0 @@ this.plugins = {}; |
| import dependencyTree from "@11ty/dependency-tree"; | ||
| import { find, findGraph, mergeGraphs } from "@11ty/dependency-tree-esm"; | ||
| import { | ||
| find as findTypeScript, | ||
| findGraph as findTypeScriptGraph, | ||
| } from "@11ty/dependency-tree-typescript"; | ||
| import { TemplatePath } from "@11ty/eleventy-utils"; | ||
@@ -14,2 +18,23 @@ import { DepGraph } from "dependency-graph"; | ||
| static getFlavor(filePath, isProjectUsingEsm) { | ||
| if ( | ||
| (isProjectUsingEsm && (filePath.endsWith(".js") || filePath.endsWith(".ts"))) || | ||
| filePath.endsWith(".mjs") || | ||
| filePath.endsWith(".mts") | ||
| ) { | ||
| return "esm"; | ||
| } | ||
| if ( | ||
| (!isProjectUsingEsm && (filePath.endsWith(".js") || filePath.endsWith(".ts"))) || | ||
| filePath.endsWith(".cjs") || | ||
| filePath.endsWith(".cts") | ||
| ) { | ||
| return "cjs"; | ||
| } | ||
| } | ||
| static isTypeScript(filePath) { | ||
| return filePath.endsWith(".ts") || filePath.endsWith(".cts") || filePath.endsWith(".mts"); | ||
| } | ||
| static async getCommonJsDependencies(inputFiles, isProjectUsingEsm) { | ||
@@ -20,5 +45,6 @@ let depSet = new Set(); | ||
| let commonJsFiles = inputFiles.filter( | ||
| (file) => (!isProjectUsingEsm && file.endsWith(".js")) || file.endsWith(".cjs"), | ||
| (file) => this.getFlavor(file, isProjectUsingEsm) === "cjs", | ||
| ); | ||
| // TODO require(esm) means some files *could* be wrong here | ||
| for (let file of commonJsFiles) { | ||
@@ -47,8 +73,7 @@ try { | ||
| let esmFiles = inputFiles.filter( | ||
| (file) => (isProjectUsingEsm && file.endsWith(".js")) || file.endsWith(".mjs"), | ||
| ); | ||
| let esmFiles = inputFiles.filter((file) => this.getFlavor(file, isProjectUsingEsm) === "esm"); | ||
| for (let file of esmFiles) { | ||
| try { | ||
| let modules = await find(file); | ||
| // TODO feature test for node:module->stripTypeScriptTypes and use with find(file, { preprocess }) | ||
| let modules = await (this.isTypeScript(file) ? findTypeScript : find)(file); | ||
| for (let dep of modules) { | ||
@@ -73,8 +98,7 @@ depSet.add(dep); | ||
| let rootGraph = new DepGraph(); | ||
| let esmFiles = inputFiles.filter( | ||
| (file) => (isProjectUsingEsm && file.endsWith(".js")) || file.endsWith(".mjs"), | ||
| ); | ||
| let esmFiles = inputFiles.filter((file) => this.getFlavor(file, isProjectUsingEsm) === "esm"); | ||
| for (let file of esmFiles) { | ||
| try { | ||
| let graph = await findGraph(file); | ||
| // TODO feature test for node:module->stripTypeScriptTypes and use with find(file, { preprocess }) | ||
| let graph = await (this.isTypeScript(file) ? findTypeScriptGraph : findGraph)(file); | ||
@@ -81,0 +105,0 @@ mergeGraphs(rootGraph, graph); |
+11
-1
@@ -6,3 +6,3 @@ import { readFileSync } from "node:fs"; | ||
| import importer from "./importer.js"; | ||
| import { clearRequireCache } from "../Util/RequireUtils.js"; | ||
| import { clearRequireCache, requireCommonJsTypeScript } from "../Util/RequireUtils.js"; | ||
| import { port1 } from "./EsmResolverPortAdapter.js"; | ||
@@ -16,2 +16,6 @@ import EleventyBaseError from "../Errors/EleventyBaseError.js"; | ||
| function isCommonJSTypeScript(filePath, type) { | ||
| return (type === "cjs" && filePath.endsWith(".ts")) || filePath.endsWith(".cts"); // no .mts here | ||
| } | ||
| function getImportErrorMessage(filePath, type) { | ||
@@ -104,2 +108,8 @@ return `There was a problem importing '${path.relative(".", filePath)}' via ${type}`; | ||
| // Workaround for Node issue https://github.com/nodejs/node/issues/61385 | ||
| // Remove this when fixed upstream! | ||
| if (isCommonJSTypeScript(absolutePath, type)) { | ||
| return requireCommonJsTypeScript(absolutePath); | ||
| } | ||
| let urlPath; | ||
@@ -106,0 +116,0 @@ try { |
@@ -9,4 +9,9 @@ import { EleventyLoadContent } from "./Require.js"; | ||
| // noop | ||
| export function clearRequireCache(absolutePath) {} | ||
| export function clearRequireCache() {} | ||
| // Stub for workaround for https://github.com/nodejs/node/issues/61385 | ||
| export function requireCommonJsTypeScript() { | ||
| throw new Error("TypeScript is not supported in this bundle of Eleventy."); | ||
| } | ||
| export function importJsonSync(path) { | ||
@@ -13,0 +18,0 @@ // should not be a no-op |
@@ -22,1 +22,5 @@ import { createRequire } from "node:module"; | ||
| } | ||
| export function requireCommonJsTypeScript(filePath) { | ||
| return require(filePath); | ||
| } |
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Long strings
Supply chain riskContains long string literals, which may be a sign of obfuscated or packed code.
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
Filesystem access
Supply chain riskAccesses the file system, and could potentially read sensitive data.
Long strings
Supply chain riskContains long string literals, which may be a sign of obfuscated or packed code.
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
572552
0.91%34
-2.86%161
2.55%16968
0.78%32
3.23%28
3.7%+ Added
+ Added
+ Added
+ Added
- Removed
- Removed
Updated
Updated
Updated
Updated
Updated
Updated
Updated