From 7a52ddeba2a68388b544f529d2d92104420f77b0 Mon Sep 17 00:00:00 2001 From: Shipwreckt Date: Fri, 31 Oct 2025 20:02:14 +0000 Subject: Changed from static to 11ty! --- node_modules/@11ty/eleventy/src/Util/Require.js | 258 ++++++++++++++++++++++++ 1 file changed, 258 insertions(+) create mode 100644 node_modules/@11ty/eleventy/src/Util/Require.js (limited to 'node_modules/@11ty/eleventy/src/Util/Require.js') diff --git a/node_modules/@11ty/eleventy/src/Util/Require.js b/node_modules/@11ty/eleventy/src/Util/Require.js new file mode 100644 index 0000000..5f6412d --- /dev/null +++ b/node_modules/@11ty/eleventy/src/Util/Require.js @@ -0,0 +1,258 @@ +import fs from "node:fs"; +import path from "node:path"; +import { fileURLToPath } from "node:url"; +import module from "node:module"; +import { MessageChannel } from "node:worker_threads"; + +import { TemplatePath } from "@11ty/eleventy-utils"; + +import EleventyBaseError from "../Errors/EleventyBaseError.js"; +import eventBus from "../EventBus.js"; + +class EleventyImportError extends EleventyBaseError {} + +const { port1, port2 } = new MessageChannel(); + +// ESM Cache Buster is an enhancement that works in Node 18.19+ +// https://nodejs.org/docs/latest/api/module.html#moduleregisterspecifier-parenturl-options +// Fixes https://github.com/11ty/eleventy/issues/3270 +// ENV variable for https://github.com/11ty/eleventy/issues/3371 +if ("register" in module && !process?.env?.ELEVENTY_SKIP_ESM_RESOLVER) { + module.register("./EsmResolver.js", import.meta.url, { + parentURL: import.meta.url, + data: { + port: port2, + }, + transferList: [port2], + }); +} + +// important to clear the require.cache in CJS projects +const require = module.createRequire(import.meta.url); + +const requestPromiseCache = new Map(); + +function getImportErrorMessage(filePath, type) { + return `There was a problem importing '${path.relative(".", filePath)}' via ${type}`; +} + +// Used for JSON imports, suffering from Node warning that import assertions experimental but also +// throwing an error if you try to import() a JSON file without an import assertion. +/** + * + * @returns {string|undefined} + */ +function loadContents(path, options = {}) { + let rawInput; + /** @type {string} */ + let encoding = "utf8"; // JSON is utf8 + if (options?.encoding || options?.encoding === null) { + encoding = options.encoding; + } + + try { + // @ts-expect-error This is an error in the upstream types + rawInput = fs.readFileSync(path, encoding); + } catch (error) { + // @ts-expect-error Temporary + if (error?.code === "ENOENT") { + // if file does not exist, return nothing + return; + } + + throw error; + } + + // Can return a buffer, string, etc + if (typeof rawInput === "string") { + rawInput = rawInput.trim(); + } + + return rawInput; +} + +let lastModifiedPaths = new Map(); +eventBus.on("eleventy.importCacheReset", (fileQueue) => { + for (let filePath of fileQueue) { + let absolutePath = TemplatePath.absolutePath(filePath); + let newDate = Date.now(); + lastModifiedPaths.set(absolutePath, newDate); + + // post to EsmResolver worker thread + if (port1) { + port1.postMessage({ path: absolutePath, newDate }); + } + + // ESM Eleventy when using `import()` on a CJS project file still adds to require.cache + if (absolutePath in (require?.cache || {})) { + delete require.cache[absolutePath]; + } + } +}); + +// raw means we don’t normalize away the `default` export +async function dynamicImportAbsolutePath(absolutePath, options = {}) { + let { type, returnRaw, cacheBust } = Object.assign( + { + type: undefined, + returnRaw: false, + cacheBust: false, // force cache bust + }, + options, + ); + + // Short circuit for JSON files (that are optional and can be empty) + if (absolutePath.endsWith(".json") || type === "json") { + try { + // https://v8.dev/features/import-assertions#dynamic-import() is still experimental in Node 20 + let rawInput = loadContents(absolutePath); + if (!rawInput) { + // should not error when file exists but is _empty_ + return; + } + return JSON.parse(rawInput); + } catch (e) { + return Promise.reject( + new EleventyImportError(getImportErrorMessage(absolutePath, "fs.readFile(json)"), e), + ); + } + } + + // Removed a `require` short circuit from this piece originally added + // in https://github.com/11ty/eleventy/pull/3493 Was a bit faster but + // error messaging was worse for require(esm) + + let urlPath; + try { + let u = new URL(`file:${absolutePath}`); + + // Bust the import cache if this is the last modified file (or cache busting is forced) + if (cacheBust) { + lastModifiedPaths.set(absolutePath, Date.now()); + } + + if (cacheBust || lastModifiedPaths.has(absolutePath)) { + u.searchParams.set("_cache_bust", lastModifiedPaths.get(absolutePath)); + } + + urlPath = u.toString(); + } catch (e) { + urlPath = absolutePath; + } + + let promise; + if (requestPromiseCache.has(urlPath)) { + promise = requestPromiseCache.get(urlPath); + } else { + promise = import(urlPath); + requestPromiseCache.set(urlPath, promise); + } + + return promise.then( + (target) => { + if (returnRaw) { + return target; + } + + // If the only export is `default`, elevate to top (for ESM and CJS) + if (Object.keys(target).length === 1 && "default" in target) { + return target.default; + } + + // When using import() on a CommonJS file that exports an object sometimes it + // returns duplicated values in `default` key, e.g. `{ default: {key: value}, key: value }` + + // A few examples: + // module.exports = { key: false }; + // returns `{ default: {key: false}, key: false }` as not expected. + // module.exports = { key: true }; + // module.exports = { key: null }; + // module.exports = { key: undefined }; + // module.exports = { key: class {} }; + + // A few examples where it does not duplicate: + // module.exports = { key: 1 }; + // returns `{ default: {key: 1} }` as expected. + // module.exports = { key: "value" }; + // module.exports = { key: {} }; + // module.exports = { key: [] }; + + if (type === "cjs" && "default" in target) { + let match = true; + for (let key in target) { + if (key === "default") { + continue; + } + if (key === "module.exports") { + continue; + } + if (target[key] !== target.default[key]) { + match = false; + } + } + + if (match) { + return target.default; + } + } + + // Otherwise return { default: value, named: value } + // Object.assign here so we can add things to it in JavaScript.js + return Object.assign({}, target); + }, + (error) => { + return Promise.reject( + new EleventyImportError(getImportErrorMessage(absolutePath, `import(${type})`), error), + ); + }, + ); +} + +function normalizeFilePathInEleventyPackage(file) { + // Back up relative paths from ./src/Util/Require.js + return path.resolve(fileURLToPath(import.meta.url), "../../../", file); +} + +async function dynamicImportFromEleventyPackage(file) { + // points to files relative to the top level Eleventy directory + let filePath = normalizeFilePathInEleventyPackage(file); + + // Returns promise + return dynamicImportAbsolutePath(filePath, { type: "esm" }); +} + +async function dynamicImport(localPath, type, options = {}) { + let absolutePath = TemplatePath.absolutePath(localPath); + options.type = type; + + // Returns promise + return dynamicImportAbsolutePath(absolutePath, options); +} + +/* Used to import default Eleventy configuration file, raw means we don’t normalize away the `default` export */ +async function dynamicImportRawFromEleventyPackage(file) { + // points to files relative to the top level Eleventy directory + let filePath = normalizeFilePathInEleventyPackage(file); + + // Returns promise + return dynamicImportAbsolutePath(filePath, { type: "esm", returnRaw: true }); +} + +/* Used to import app configuration files, raw means we don’t normalize away the `default` export */ +async function dynamicImportRaw(localPath, type) { + let absolutePath = TemplatePath.absolutePath(localPath); + + // Returns promise + return dynamicImportAbsolutePath(absolutePath, { type, returnRaw: true }); +} + +export { + loadContents as EleventyLoadContent, + dynamicImport as EleventyImport, + dynamicImportRaw as EleventyImportRaw, + normalizeFilePathInEleventyPackage, + + // no longer used in core + dynamicImportFromEleventyPackage as EleventyImportFromEleventy, + dynamicImportRawFromEleventyPackage as EleventyImportRawFromEleventy, +}; -- cgit v1.2.3