summaryrefslogtreecommitdiff
path: root/node_modules/@11ty/eleventy-plugin-bundle/src
diff options
context:
space:
mode:
Diffstat (limited to 'node_modules/@11ty/eleventy-plugin-bundle/src')
-rw-r--r--node_modules/@11ty/eleventy-plugin-bundle/src/BundleFileOutput.js75
-rw-r--r--node_modules/@11ty/eleventy-plugin-bundle/src/CodeManager.js231
-rw-r--r--node_modules/@11ty/eleventy-plugin-bundle/src/OutOfOrderRender.js158
-rw-r--r--node_modules/@11ty/eleventy-plugin-bundle/src/bundlePlucker.js69
-rw-r--r--node_modules/@11ty/eleventy-plugin-bundle/src/eleventy.bundleManagers.js85
-rw-r--r--node_modules/@11ty/eleventy-plugin-bundle/src/eleventy.pruneEmptyBundles.js105
-rw-r--r--node_modules/@11ty/eleventy-plugin-bundle/src/eleventy.shortcodes.js83
7 files changed, 806 insertions, 0 deletions
diff --git a/node_modules/@11ty/eleventy-plugin-bundle/src/BundleFileOutput.js b/node_modules/@11ty/eleventy-plugin-bundle/src/BundleFileOutput.js
new file mode 100644
index 0000000..332c5b7
--- /dev/null
+++ b/node_modules/@11ty/eleventy-plugin-bundle/src/BundleFileOutput.js
@@ -0,0 +1,75 @@
+import fs from "node:fs";
+import path from "node:path";
+import debugUtil from "debug";
+
+import { createHash } from "@11ty/eleventy-utils";
+
+const debug = debugUtil("Eleventy:Bundle");
+
+const hashCache = {};
+const directoryExistsCache = {};
+const writingCache = new Set();
+
+class BundleFileOutput {
+ constructor(outputDirectory, bundleDirectory) {
+ this.outputDirectory = outputDirectory;
+ this.bundleDirectory = bundleDirectory || "";
+ this.hashLength = 10;
+ this.fileExtension = undefined;
+ }
+
+ setFileExtension(ext) {
+ this.fileExtension = ext;
+ }
+
+ async getFilenameHash(content) {
+ if(hashCache[content]) {
+ return hashCache[content];
+ }
+
+ let base64hash = await createHash(content);
+ let filenameHash = base64hash.substring(0, this.hashLength);
+ hashCache[content] = filenameHash;
+ return filenameHash;
+ }
+
+ getFilename(filename, extension) {
+ return filename + (extension && !extension.startsWith(".") ? `.${extension}` : "");
+ }
+
+ modifyPathToUrl(dir, filename) {
+ return "/" + path.join(dir, filename).split(path.sep).join("/");
+ }
+
+ async writeBundle(content, type, writeToFileSystem) {
+ // do not write a bundle, do not return a file name is content is empty
+ if(!content) {
+ return;
+ }
+
+ let dir = path.join(this.outputDirectory, this.bundleDirectory);
+ let filenameHash = await this.getFilenameHash(content);
+ let filename = this.getFilename(filenameHash, this.fileExtension || type);
+
+ if(writeToFileSystem) {
+ let fullPath = path.join(dir, filename);
+
+ // no duplicate writes, this may be improved with a fs exists check, but it would only save the first write
+ if(!writingCache.has(fullPath)) {
+ writingCache.add(fullPath);
+
+ if(!directoryExistsCache[dir]) {
+ fs.mkdirSync(dir, { recursive: true });
+ directoryExistsCache[dir] = true;
+ }
+
+ debug("Writing bundle %o", fullPath);
+ fs.writeFileSync(fullPath, content);
+ }
+ }
+
+ return this.modifyPathToUrl(this.bundleDirectory, filename);
+ }
+}
+
+export { BundleFileOutput };
diff --git a/node_modules/@11ty/eleventy-plugin-bundle/src/CodeManager.js b/node_modules/@11ty/eleventy-plugin-bundle/src/CodeManager.js
new file mode 100644
index 0000000..809c242
--- /dev/null
+++ b/node_modules/@11ty/eleventy-plugin-bundle/src/CodeManager.js
@@ -0,0 +1,231 @@
+import { BundleFileOutput } from "./BundleFileOutput.js";
+import debugUtil from "debug";
+
+const debug = debugUtil("Eleventy:Bundle");
+const DEBUG_LOG_TRUNCATION_SIZE = 200;
+
+class CodeManager {
+ // code is placed in this bucket by default
+ static DEFAULT_BUCKET_NAME = "default";
+
+ // code is hoisted to this bucket when necessary
+ static HOISTED_BUCKET_NAME = "default";
+
+ constructor(name) {
+ this.name = name;
+ this.trimOnAdd = true;
+ // TODO unindent on add
+ this.reset();
+ this.transforms = [];
+ this.isHoisting = true;
+ this.fileExtension = undefined;
+ this.toFileDirectory = undefined;
+ this.bundleExportKey = "bundle";
+ this.runsAfterHtmlTransformer = false;
+ this.pluckedSelector = undefined;
+ }
+
+ setDelayed(isDelayed) {
+ this.runsAfterHtmlTransformer = Boolean(isDelayed);
+ }
+
+ isDelayed() {
+ return this.runsAfterHtmlTransformer;
+ }
+
+ // posthtml-match-selector friendly
+ setPluckedSelector(selector) {
+ this.pluckedSelector = selector;
+ }
+
+ getPluckedSelector() {
+ return this.pluckedSelector;
+ }
+
+ setFileExtension(ext) {
+ this.fileExtension = ext;
+ }
+
+ setHoisting(enabled) {
+ this.isHoisting = !!enabled;
+ }
+
+ setBundleDirectory(dir) {
+ this.toFileDirectory = dir;
+ }
+
+ setBundleExportKey(key) {
+ this.bundleExportKey = key;
+ }
+
+ getBundleExportKey() {
+ return this.bundleExportKey;
+ }
+
+ reset() {
+ this.pages = {};
+ }
+
+ static normalizeBuckets(bucket) {
+ if(Array.isArray(bucket)) {
+ return bucket;
+ } else if(typeof bucket === "string") {
+ return bucket.split(",");
+ }
+ return [CodeManager.DEFAULT_BUCKET_NAME];
+ }
+
+ setTransforms(transforms) {
+ if(!Array.isArray(transforms)) {
+ throw new Error("Array expected to setTransforms");
+ }
+
+ this.transforms = transforms;
+ }
+
+ _initBucket(pageUrl, bucket) {
+ if(!this.pages[pageUrl][bucket]) {
+ this.pages[pageUrl][bucket] = new Set();
+ }
+ }
+
+ addToPage(pageUrl, code = [], bucket) {
+ if(!Array.isArray(code) && code) {
+ code = [code];
+ }
+ if(code.length === 0) {
+ return;
+ }
+
+ if(!this.pages[pageUrl]) {
+ this.pages[pageUrl] = {};
+ }
+
+ let buckets = CodeManager.normalizeBuckets(bucket);
+
+ let codeContent = code.map(entry => {
+ if(this.trimOnAdd) {
+ return entry.trim();
+ }
+ return entry;
+ });
+
+
+ for(let b of buckets) {
+ this._initBucket(pageUrl, b);
+
+ for(let content of codeContent) {
+ if(content) {
+ if(!this.pages[pageUrl][b].has(content)) {
+ debug("Adding code to bundle %o for %o (bucket: %o, size: %o): %o", this.name, pageUrl, b, content.length, content.length > DEBUG_LOG_TRUNCATION_SIZE ? content.slice(0, DEBUG_LOG_TRUNCATION_SIZE) + "…" : content);
+ this.pages[pageUrl][b].add(content);
+ }
+ }
+ }
+ }
+ }
+
+ async runTransforms(str, pageData, buckets) {
+ for (let callback of this.transforms) {
+ str = await callback.call(
+ {
+ page: pageData,
+ type: this.name,
+ buckets: buckets
+ },
+ str
+ );
+ }
+
+ return str;
+ }
+
+ getBucketsForPage(pageData) {
+ let pageUrl = pageData.url;
+ if(!this.pages[pageUrl]) {
+ return [];
+ }
+ return Object.keys(this.pages[pageUrl]);
+ }
+
+ getRawForPage(pageData, buckets = undefined) {
+ let url = pageData.url;
+ if(!this.pages[url]) {
+ debug("No bundle code found for %o on %o, %O", this.name, url, this.pages);
+ return new Set();
+ }
+
+ buckets = CodeManager.normalizeBuckets(buckets);
+
+ let set = new Set();
+ let size = 0;
+ for(let b of buckets) {
+ if(!this.pages[url][b]) {
+ // Just continue, if you retrieve code from a bucket that doesn’t exist or has no code, it will return an empty set
+ continue;
+ }
+
+ for(let entry of this.pages[url][b]) {
+ size += entry.length;
+ set.add(entry);
+ }
+ }
+
+ debug("Retrieving %o for %o (buckets: %o, entries: %o, size: %o)", this.name, url, buckets, set.size, size);
+ return set;
+ }
+
+ async getForPage(pageData, buckets = undefined) {
+ let set = this.getRawForPage(pageData, buckets);
+ let bundleContent = Array.from(set).join("\n");
+
+ // returns promise
+ return this.runTransforms(bundleContent, pageData, buckets);
+ }
+
+ async writeBundle(pageData, buckets, options = {}) {
+ let url = pageData.url;
+ if(!this.pages[url]) {
+ debug("No bundle code found for %o on %o, %O", this.name, url, this.pages);
+ return "";
+ }
+
+ let { output, write } = options;
+
+ buckets = CodeManager.normalizeBuckets(buckets);
+
+ // TODO the bundle output URL might be useful in the transforms for sourcemaps
+ let content = await this.getForPage(pageData, buckets);
+ let writer = new BundleFileOutput(output, this.toFileDirectory);
+ writer.setFileExtension(this.fileExtension);
+ return writer.writeBundle(content, this.name, write);
+ }
+
+ // Used when a bucket is output multiple times on a page and needs to be hoisted
+ hoistBucket(pageData, bucketName) {
+ let newTargetBucketName = CodeManager.HOISTED_BUCKET_NAME;
+ if(!this.isHoisting || bucketName === newTargetBucketName) {
+ return;
+ }
+
+ let url = pageData.url;
+ if(!this.pages[url] || !this.pages[url][bucketName]) {
+ debug("No bundle code found for %o on %o, %O", this.name, url, this.pages);
+ return;
+ }
+
+ debug("Code in bucket (%o) is being hoisted to a new bucket (%o)", bucketName, newTargetBucketName);
+
+ this._initBucket(url, newTargetBucketName);
+
+ for(let codeEntry of this.pages[url][bucketName]) {
+ this.pages[url][bucketName].delete(codeEntry);
+ this.pages[url][newTargetBucketName].add(codeEntry);
+ }
+
+ // delete the bucket
+ delete this.pages[url][bucketName];
+ }
+}
+
+export { CodeManager };
diff --git a/node_modules/@11ty/eleventy-plugin-bundle/src/OutOfOrderRender.js b/node_modules/@11ty/eleventy-plugin-bundle/src/OutOfOrderRender.js
new file mode 100644
index 0000000..6cafa49
--- /dev/null
+++ b/node_modules/@11ty/eleventy-plugin-bundle/src/OutOfOrderRender.js
@@ -0,0 +1,158 @@
+import debugUtil from "debug";
+
+const debug = debugUtil("Eleventy:Bundle");
+
+/* This class defers any `bundleGet` calls to a post-build transform step,
+ * to allow `getBundle` to be called before all of the `css` additions have been processed
+ */
+class OutOfOrderRender {
+ static SPLIT_REGEX = /(\/\*__EleventyBundle:[^:]*:[^:]*:[^:]*:EleventyBundle__\*\/)/;
+ static SEPARATOR = ":";
+
+ constructor(content) {
+ this.content = content;
+ this.managers = {};
+ }
+
+ // type if `get` (return string) or `file` (bundle writes to file, returns file url)
+ static getAssetKey(type, name, bucket) {
+ if(Array.isArray(bucket)) {
+ bucket = bucket.join(",");
+ } else if(typeof bucket === "string") {
+ } else {
+ bucket = "";
+ }
+ return `/*__EleventyBundle:${type}:${name}:${bucket || "default"}:EleventyBundle__*/`
+ }
+
+ static parseAssetKey(str) {
+ if(str.startsWith("/*__EleventyBundle:")) {
+ let [prefix, type, name, bucket, suffix] = str.split(OutOfOrderRender.SEPARATOR);
+ return { type, name, bucket };
+ }
+ return false;
+ }
+
+ setAssetManager(name, assetManager) {
+ this.managers[name] = assetManager;
+ }
+
+ setOutputDirectory(dir) {
+ this.outputDirectory = dir;
+ }
+
+ normalizeMatch(match) {
+ let ret = OutOfOrderRender.parseAssetKey(match)
+ return ret || match;
+ }
+
+ findAll() {
+ let matches = this.content.split(OutOfOrderRender.SPLIT_REGEX);
+ let ret = [];
+ for(let match of matches) {
+ ret.push(this.normalizeMatch(match));
+ }
+ return ret;
+ }
+
+ setWriteToFileSystem(isWrite) {
+ this.writeToFileSystem = isWrite;
+ }
+
+ getAllBucketsForPage(pageData) {
+ let availableBucketsForPage = new Set();
+ for(let name in this.managers) {
+ for(let bucket of this.managers[name].getBucketsForPage(pageData)) {
+ availableBucketsForPage.add(`${name}::${bucket}`);
+ }
+ }
+ return availableBucketsForPage;
+ }
+
+ getManager(name) {
+ if(!this.managers[name]) {
+ throw new Error(`No asset manager found for ${name}. Known names: ${Object.keys(this.managers)}`);
+ }
+ return this.managers[name];
+ }
+
+ async replaceAll(pageData, stage = 0) {
+ let matches = this.findAll();
+ let availableBucketsForPage = this.getAllBucketsForPage(pageData);
+ let usedBucketsOnPage = new Set();
+ let bucketsOutputStringCount = {};
+ let bucketsFileCount = {};
+
+ for(let match of matches) {
+ if(typeof match === "string") {
+ continue;
+ }
+
+ // type is `file` or `get`
+ let {type, name, bucket} = match;
+ let key = `${name}::${bucket}`;
+ if(!usedBucketsOnPage.has(key)) {
+ usedBucketsOnPage.add(key);
+ }
+
+ if(type === "get") {
+ if(!bucketsOutputStringCount[key]) {
+ bucketsOutputStringCount[key] = 0;
+ }
+ bucketsOutputStringCount[key]++;
+ } else if(type === "file") {
+ if(!bucketsFileCount[key]) {
+ bucketsFileCount[key] = 0;
+ }
+ bucketsFileCount[key]++;
+ }
+ }
+
+ // Hoist code in non-default buckets that are output multiple times
+ // Only hoist if 2+ `get` OR 1+ `get` and 1+ `file`
+ for(let bucketInfo in bucketsOutputStringCount) {
+ let stringOutputCount = bucketsOutputStringCount[bucketInfo];
+ if(stringOutputCount > 1 || stringOutputCount === 1 && bucketsFileCount[bucketInfo] > 0) {
+ let [name, bucketName] = bucketInfo.split("::");
+ this.getManager(name).hoistBucket(pageData, bucketName);
+ }
+ }
+
+ let content = await Promise.all(matches.map(match => {
+ if(typeof match === "string") {
+ return match;
+ }
+
+ let {type, name, bucket} = match;
+ let manager = this.getManager(name);
+
+ // Quit early if in stage 0, run delayed replacements if in stage 1+
+ if(typeof manager.isDelayed === "function" && manager.isDelayed() && stage === 0) {
+ return OutOfOrderRender.getAssetKey(type, name, bucket);
+ }
+
+ if(type === "get") {
+ // returns promise
+ return manager.getForPage(pageData, bucket);
+ } else if(type === "file") {
+ // returns promise
+ return manager.writeBundle(pageData, bucket, {
+ output: this.outputDirectory,
+ write: this.writeToFileSystem,
+ });
+ }
+ return "";
+ }));
+
+ for(let bucketInfo of availableBucketsForPage) {
+ if(!usedBucketsOnPage.has(bucketInfo)) {
+ let [name, bucketName] = bucketInfo.split("::");
+ debug(`WARNING! \`${pageData.inputPath}\` has unbundled \`${name}\` assets (in the '${bucketName}' bucket) that were not written to or used on the page. You might want to add a call to \`getBundle('${name}', '${bucketName}')\` to your content! Learn more: https://github.com/11ty/eleventy-plugin-bundle#asset-bucketing`);
+ }
+ }
+
+ return content.join("");
+ }
+}
+
+export { OutOfOrderRender };
diff --git a/node_modules/@11ty/eleventy-plugin-bundle/src/bundlePlucker.js b/node_modules/@11ty/eleventy-plugin-bundle/src/bundlePlucker.js
new file mode 100644
index 0000000..5dcad46
--- /dev/null
+++ b/node_modules/@11ty/eleventy-plugin-bundle/src/bundlePlucker.js
@@ -0,0 +1,69 @@
+import debugUtil from "debug";
+import matchHelper from "posthtml-match-helper";
+
+const debug = debugUtil("Eleventy:Bundle");
+
+const ATTRS = {
+ ignore: "eleventy:ignore",
+ bucket: "eleventy:bucket",
+};
+
+const POSTHTML_PLUGIN_NAME = "11ty/eleventy/html-bundle-plucker";
+
+function hasAttribute(node, name) {
+ return node?.attrs?.[name] !== undefined;
+}
+
+function addHtmlPlucker(eleventyConfig, bundleManager) {
+ let matchSelector = bundleManager.getPluckedSelector();
+
+ if(!matchSelector) {
+ throw new Error("Internal error: missing plucked selector on bundle manager.");
+ }
+
+ eleventyConfig.htmlTransformer.addPosthtmlPlugin(
+ "html",
+ function (context = {}) {
+ let pageUrl = context?.url;
+ if(!pageUrl) {
+ throw new Error("Internal error: missing `url` property from context.");
+ }
+
+ return function (tree, ...args) {
+ tree.match(matchHelper(matchSelector), function (node) {
+ try {
+ // ignore
+ if(hasAttribute(node, ATTRS.ignore)) {
+ delete node.attrs[ATTRS.ignore];
+ return node;
+ }
+
+ if(Array.isArray(node?.content) && node.content.length > 0) {
+ // TODO make this better decoupled
+ if(node?.content.find(entry => entry.includes(`/*__EleventyBundle:`))) {
+ // preserve {% getBundle %} calls as-is
+ return node;
+ }
+
+ let bucketName = node?.attrs?.[ATTRS.bucket];
+ bundleManager.addToPage(pageUrl, [ ...node.content ], bucketName);
+
+ return { attrs: [], content: [], tag: false };
+ }
+ } catch(e) {
+ debug(`Bundle plucker: error adding content to bundle in HTML Assets: %o`, e);
+ return node;
+ }
+
+ return node;
+ });
+ };
+ },
+ {
+ // pluginOptions
+ name: POSTHTML_PLUGIN_NAME,
+ },
+ );
+}
+
+export { addHtmlPlucker };
diff --git a/node_modules/@11ty/eleventy-plugin-bundle/src/eleventy.bundleManagers.js b/node_modules/@11ty/eleventy-plugin-bundle/src/eleventy.bundleManagers.js
new file mode 100644
index 0000000..8510abc
--- /dev/null
+++ b/node_modules/@11ty/eleventy-plugin-bundle/src/eleventy.bundleManagers.js
@@ -0,0 +1,85 @@
+import debugUtil from "debug";
+import { CodeManager } from "./CodeManager.js";
+import { addHtmlPlucker } from "./bundlePlucker.js"
+
+const debug = debugUtil("Eleventy:Bundle");
+
+function eleventyBundleManagers(eleventyConfig, pluginOptions = {}) {
+ if(pluginOptions.force) {
+ // no errors
+ } else if(("getBundleManagers" in eleventyConfig || "addBundle" in eleventyConfig)) {
+ throw new Error("Duplicate addPlugin calls for @11ty/eleventy-plugin-bundle");
+ }
+
+ let managers = {};
+
+ function addBundle(name, bundleOptions = {}) {
+ if(name in managers) {
+ // note: shortcode must still be added
+ debug("Bundle exists %o, skipping.", name);
+ } else {
+ debug("Creating new bundle %o", name);
+ managers[name] = new CodeManager(name);
+
+ if(bundleOptions.delayed !== undefined) {
+ managers[name].setDelayed(bundleOptions.delayed);
+ }
+
+ if(bundleOptions.hoist !== undefined) {
+ managers[name].setHoisting(bundleOptions.hoist);
+ }
+
+ if(bundleOptions.bundleHtmlContentFromSelector !== undefined) {
+ managers[name].setPluckedSelector(bundleOptions.bundleHtmlContentFromSelector);
+ managers[name].setDelayed(true); // must override `delayed` above
+
+ addHtmlPlucker(eleventyConfig, managers[name]);
+ }
+
+ if(bundleOptions.bundleExportKey !== undefined) {
+ managers[name].setBundleExportKey(bundleOptions.bundleExportKey);
+ }
+
+ if(bundleOptions.outputFileExtension) {
+ managers[name].setFileExtension(bundleOptions.outputFileExtension);
+ }
+
+ if(bundleOptions.toFileDirectory) {
+ managers[name].setBundleDirectory(bundleOptions.toFileDirectory);
+ }
+
+ if(bundleOptions.transforms) {
+ managers[name].setTransforms(bundleOptions.transforms);
+ }
+ }
+
+ // if undefined, defaults to `name`
+ if(bundleOptions.shortcodeName !== false) {
+ let shortcodeName = bundleOptions.shortcodeName || name;
+
+ // e.g. `css` shortcode to add code to page bundle
+ // These shortcode names are not configurable on purpose (for wider plugin compatibility)
+ eleventyConfig.addPairedShortcode(shortcodeName, function addContent(content, bucket, explicitUrl) {
+ let url = explicitUrl || this.page?.url;
+ if(url) { // don’t add if a file doesn’t have an output URL
+ managers[name].addToPage(url, content, bucket);
+ }
+ return "";
+ });
+ }
+ };
+
+ eleventyConfig.addBundle = addBundle;
+
+ eleventyConfig.getBundleManagers = function() {
+ return managers;
+ };
+
+ eleventyConfig.on("eleventy.before", async () => {
+ for(let key in managers) {
+ managers[key].reset();
+ }
+ });
+};
+
+export default eleventyBundleManagers;
diff --git a/node_modules/@11ty/eleventy-plugin-bundle/src/eleventy.pruneEmptyBundles.js b/node_modules/@11ty/eleventy-plugin-bundle/src/eleventy.pruneEmptyBundles.js
new file mode 100644
index 0000000..3bcaa72
--- /dev/null
+++ b/node_modules/@11ty/eleventy-plugin-bundle/src/eleventy.pruneEmptyBundles.js
@@ -0,0 +1,105 @@
+import matchHelper from "posthtml-match-helper";
+import debugUtil from "debug";
+
+const debug = debugUtil("Eleventy:Bundle");
+
+const ATTRS = {
+ keep: "eleventy:keep"
+};
+
+const POSTHTML_PLUGIN_NAME = "11ty/eleventy-bundle/prune-empty";
+
+function getTextNodeContent(node) {
+ if (!node.content) {
+ return "";
+ }
+
+ return node.content
+ .map((entry) => {
+ if (typeof entry === "string") {
+ return entry;
+ }
+ if (Array.isArray(entry.content)) {
+ return getTextNodeContent(entry);
+ }
+ return "";
+ })
+ .join("");
+}
+
+function eleventyPruneEmptyBundles(eleventyConfig, options = {}) {
+ // Right now script[src],link[rel="stylesheet"] nodes are removed if the final bundles are empty.
+ // `false` to disable
+ options.pruneEmptySelector = options.pruneEmptySelector ?? `style,script,link[rel="stylesheet"]`;
+
+ // Subsequent call can remove a previously added `addPosthtmlPlugin` entry
+ // htmlTransformer.remove is v3.0.1-alpha.4+
+ if(typeof eleventyConfig.htmlTransformer.remove === "function") {
+ eleventyConfig.htmlTransformer.remove("html", entry => {
+ if(entry.name === POSTHTML_PLUGIN_NAME) {
+ return true;
+ }
+
+ // Temporary workaround for missing `name` property.
+ let fnStr = entry.fn.toString();
+ return !entry.name && fnStr.startsWith("function (pluginOptions = {}) {") && fnStr.includes(`tree.match(matchHelper(options.pruneEmptySelector), function (node)`);
+ });
+ }
+
+ // `false` disables this plugin
+ if(options.pruneEmptySelector === false) {
+ return;
+ }
+
+ if(!eleventyConfig.htmlTransformer || !eleventyConfig.htmlTransformer?.constructor?.SUPPORTS_PLUGINS_ENABLED_CALLBACK) {
+ debug("You will need to upgrade your version of Eleventy core to remove empty bundle tags automatically (v3 or newer).");
+ return;
+ }
+
+ eleventyConfig.htmlTransformer.addPosthtmlPlugin(
+ "html",
+ function bundlePruneEmptyPosthtmlPlugin(pluginOptions = {}) {
+ return function (tree) {
+ tree.match(matchHelper(options.pruneEmptySelector), function (node) {
+ if(node.attrs && node.attrs[ATTRS.keep] !== undefined) {
+ delete node.attrs[ATTRS.keep];
+ return node;
+ }
+
+ // <link rel="stylesheet" href="">
+ if(node.tag === "link") {
+ if(node.attrs?.rel === "stylesheet" && (node.attrs?.href || "").trim().length === 0) {
+ return false;
+ }
+ } else {
+ let content = getTextNodeContent(node);
+
+ if(!content) {
+ // <script></script> or <script src=""></script>
+ if(node.tag === "script" && (node.attrs?.src || "").trim().length === 0) {
+ return false;
+ }
+
+ // <style></style>
+ if(node.tag === "style") {
+ return false;
+ }
+ }
+ }
+
+
+ return node;
+ });
+ };
+ },
+ {
+ name: POSTHTML_PLUGIN_NAME,
+ // the `enabled` callback for plugins is available on v3.0.0-alpha.20+ and v3.0.0-beta.2+
+ enabled: () => {
+ return Object.keys(eleventyConfig.getBundleManagers()).length > 0;
+ }
+ }
+ );
+}
+
+export default eleventyPruneEmptyBundles;
diff --git a/node_modules/@11ty/eleventy-plugin-bundle/src/eleventy.shortcodes.js b/node_modules/@11ty/eleventy-plugin-bundle/src/eleventy.shortcodes.js
new file mode 100644
index 0000000..924731a
--- /dev/null
+++ b/node_modules/@11ty/eleventy-plugin-bundle/src/eleventy.shortcodes.js
@@ -0,0 +1,83 @@
+import { OutOfOrderRender } from "./OutOfOrderRender.js";
+import debugUtil from "debug";
+
+const debug = debugUtil("Eleventy:Bundle");
+
+export default function(eleventyConfig, pluginOptions = {}) {
+ let managers = eleventyConfig.getBundleManagers();
+ let writeToFileSystem = true;
+
+ function bundleTransform(content, stage = 0) {
+ // Only run if content is string
+ // Only run if managers are in play
+ if(typeof content !== "string" || Object.keys(managers).length === 0) {
+ return content;
+ }
+
+ debug("Processing %o", this.page.url);
+ let render = new OutOfOrderRender(content);
+ for(let key in managers) {
+ render.setAssetManager(key, managers[key]);
+ }
+
+ render.setOutputDirectory(eleventyConfig.directories.output);
+ render.setWriteToFileSystem(writeToFileSystem);
+
+ return render.replaceAll(this.page, stage);
+ }
+
+ eleventyConfig.on("eleventy.before", async ({ outputMode }) => {
+ if(Object.keys(managers).length === 0) {
+ return;
+ }
+
+ if(outputMode !== "fs") {
+ writeToFileSystem = false;
+ debug("Skipping writing to the file system due to output mode: %o", outputMode);
+ }
+ });
+
+ // e.g. `getBundle` shortcode to get code in current page bundle
+ // bucket can be an array
+ // This shortcode name is not configurable on purpose (for wider plugin compatibility)
+ eleventyConfig.addShortcode("getBundle", function getContent(type, bucket, explicitUrl) {
+ if(!type || !(type in managers) || Object.keys(managers).length === 0) {
+ throw new Error(`Invalid bundle type: ${type}. Available options: ${Object.keys(managers)}`);
+ }
+
+ return OutOfOrderRender.getAssetKey("get", type, bucket);
+ });
+
+ // write a bundle to the file system
+ // This shortcode name is not configurable on purpose (for wider plugin compatibility)
+ eleventyConfig.addShortcode("getBundleFileUrl", function(type, bucket, explicitUrl) {
+ if(!type || !(type in managers) || Object.keys(managers).length === 0) {
+ throw new Error(`Invalid bundle type: ${type}. Available options: ${Object.keys(managers)}`);
+ }
+
+ return OutOfOrderRender.getAssetKey("file", type, bucket);
+ });
+
+ eleventyConfig.addTransform("@11ty/eleventy-bundle", function (content) {
+ let hasNonDelayedManagers = Boolean(Object.values(eleventyConfig.getBundleManagers()).find(manager => {
+ return typeof manager.isDelayed !== "function" || !manager.isDelayed();
+ }));
+ if(hasNonDelayedManagers) {
+ return bundleTransform.call(this, content, 0);
+ }
+ return content;
+ });
+
+ eleventyConfig.addPlugin((eleventyConfig) => {
+ // Delayed bundles *MUST* not alter URLs
+ eleventyConfig.addTransform("@11ty/eleventy-bundle/delayed", function (content) {
+ let hasDelayedManagers = Boolean(Object.values(eleventyConfig.getBundleManagers()).find(manager => {
+ return typeof manager.isDelayed === "function" && manager.isDelayed();
+ }));
+ if(hasDelayedManagers) {
+ return bundleTransform.call(this, content, 1);
+ }
+ return content;
+ });
+ });
+};