From 0a162bb206b5cd2711e2be4a20a66125e99a5433 Mon Sep 17 00:00:00 2001 From: Zach Leatherman Date: Thu, 2 Feb 2023 15:19:49 -0600 Subject: [PATCH] Add bundle transforms support --- codeManager.js | 49 +++++++++++++++----- eleventy.config.js | 7 ++- eleventy.shortcodes.js | 25 +++++----- outOfOrderRender.js | 15 ++++-- package.json | 4 +- test/stubs/use-transforms/eleventy.config.js | 16 +++++++ test/stubs/use-transforms/index.liquid | 6 +++ test/test.js | 10 ++++ 8 files changed, 98 insertions(+), 34 deletions(-) create mode 100644 test/stubs/use-transforms/eleventy.config.js create mode 100644 test/stubs/use-transforms/index.liquid diff --git a/codeManager.js b/codeManager.js index 3d16814..c83f300 100644 --- a/codeManager.js +++ b/codeManager.js @@ -61,6 +61,7 @@ class CodeManager { this.name = name; this.trimOnAdd = true; this.reset(); + this.transforms = []; } reset() { @@ -76,6 +77,14 @@ class CodeManager { return ["default"]; } + setTransforms(transforms) { + if(!Array.isArray(transforms)) { + throw new Error("Array expected to setTransforms"); + } + + this.transforms = transforms; + } + addToPage(pageUrl, code = [], bucket) { if(!Array.isArray(code) && code) { code = [code]; @@ -106,33 +115,51 @@ class CodeManager { } } - getForPage(pageUrl, buckets) { - if(!this.pages[pageUrl]) { - debug("No bundle code found for %o on %o, %O", this.name, pageUrl, this.pages); + async runTransforms(str, pageData) { + for (let callback of this.transforms) { + str = await callback.call( + { + page: pageData + }, + str + ); + } + + return str; + } + + async getForPage(pageData, buckets) { + let url = pageData.url; + if(!this.pages[url]) { + debug("No bundle code found for %o on %o, %O", this.name, url, this.pages); return ""; } buckets = CodeManager.normalizeBuckets(buckets); - debug("Retrieving %o for %o (buckets: %o)", this.name, pageUrl, buckets); + debug("Retrieving %o for %o (buckets: %o)", this.name, url, buckets); let set = new Set(); for(let b of buckets) { - if(!this.pages[pageUrl][b]) { + 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[pageUrl][b]) { + for(let entry of this.pages[url][b]) { set.add(entry); } } - return Array.from(set).join("\n"); + let bundleContent = Array.from(set).join("\n"); + + // returns promise + return this.runTransforms(bundleContent, pageData); } - writeBundle(pageUrl, buckets, options = {}) { - if(!this.pages[pageUrl]) { - debug("No bundle code found for %o on %o, %O", this.name, pageUrl, this.pages); + 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 ""; } @@ -140,7 +167,7 @@ class CodeManager { buckets = CodeManager.normalizeBuckets(buckets); - let content = this.getForPage(pageUrl, buckets); + let content = await this.getForPage(pageData, buckets); let writer = new BundleFileOutput(output, bundle); return writer.writeBundle(content, this.name, write); diff --git a/eleventy.config.js b/eleventy.config.js index 5744b04..098cb5a 100644 --- a/eleventy.config.js +++ b/eleventy.config.js @@ -6,9 +6,11 @@ function normalizeOptions(options = {}) { // Plugin defaults bundles: [], // extra bundles: css, js, and html are guaranteed toFileDirectory: "bundle", + // post-process + transforms: [] }, options); - options.bundles = Array.from(new Set(["css", "js", "html", ...options.bundles])); + options.bundles = Array.from(new Set(["css", "js", "html", ...(options.bundles || [])])); return options; } @@ -22,9 +24,6 @@ function eleventyBundlePlugin(eleventyConfig, options = {}) { options = normalizeOptions(options); - // TODO - // debug("Warning: Currently @11ty/eleventy-plugin-bundle only supports one addPlugin of this plugin per project. Subsequent adds are ignored."); - shortcodesPlugin(eleventyConfig, options); }; diff --git a/eleventy.shortcodes.js b/eleventy.shortcodes.js index 276360b..a52c7a1 100644 --- a/eleventy.shortcodes.js +++ b/eleventy.shortcodes.js @@ -5,19 +5,18 @@ const debug = require("debug")("Eleventy:Bundle"); module.exports = function(eleventyConfig, options = {}) { let managers = {}; - if(Array.isArray(options.bundles)) { - options.bundles.forEach(name => { - managers[name] = new CodeManager(name); + options.bundles.forEach(name => { + managers[name] = new CodeManager(name); + managers[name].setTransforms(options.transforms); - // e.g. `css` shortcode to add code to page bundle - // These shortcode names are not configurable on purpose (for wider plugin compatibility) - eleventyConfig.addPairedShortcode(name, function addContent(content, bucket, urlOverride) { - let url = urlOverride || this.page.url; - managers[name].addToPage(url, content, bucket); - return ""; - }); + // e.g. `css` shortcode to add code to page bundle + // These shortcode names are not configurable on purpose (for wider plugin compatibility) + eleventyConfig.addPairedShortcode(name, function addContent(content, bucket, urlOverride) { + let url = urlOverride || this.page.url; + managers[name].addToPage(url, content, bucket); + return ""; }); - } + }); let writeToFileSystem = true; eleventyConfig.on("eleventy.before", async ({ outputMode }) => { @@ -52,7 +51,7 @@ module.exports = function(eleventyConfig, options = {}) { return OutOfOrderRender.getAssetKey("file", type, bucket); }); - eleventyConfig.addTransform("@11ty/eleventy-bundle", function(content) { + eleventyConfig.addTransform("@11ty/eleventy-bundle", async function(content) { if((this.page.outputPath || "").endsWith(".html")) { let render = new OutOfOrderRender(content); for(let key in managers) { @@ -63,7 +62,7 @@ module.exports = function(eleventyConfig, options = {}) { render.setBundleDirectory(options.toFileDirectory); render.setWriteToFileSystem(writeToFileSystem); - return render.replaceAll(this.page.url); + return render.replaceAll(this.page); } return content; diff --git a/outOfOrderRender.js b/outOfOrderRender.js index 3234f02..193bc71 100644 --- a/outOfOrderRender.js +++ b/outOfOrderRender.js @@ -53,9 +53,10 @@ class OutOfOrderRender { this.writeToFileSystem = isWrite; } - replaceAll(url) { + async replaceAll(pageData) { let matches = this.findAll(); - return matches.map(match => { + + let content = await Promise.all(matches.map(match => { if(typeof match === "string") { return match; } @@ -65,16 +66,20 @@ class OutOfOrderRender { throw new Error(`No asset manager found for ${name}. Known keys: ${Object.keys(this.managers)}`); } if(type === "get") { - return this.managers[name].getForPage(url, bucket); + // returns promise + return this.managers[name].getForPage(pageData, bucket); } else if(type === "file") { - return this.managers[name].writeBundle(url, bucket, { + // returns promise + return this.managers[name].writeBundle(pageData, bucket, { output: this.outputDirectory, bundle: this.bundleDirectory, write: this.writeToFileSystem, }); } return ""; - }).join(""); + })); + + return content.join(""); } } diff --git a/package.json b/package.json index d4d5ccb..8c3fdea 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@11ty/eleventy-plugin-bundle", - "version": "0.0.1", + "version": "1.0.0", "description": "Little bundles of code, little bundles of joy.", "main": "eleventy.config.js", "scripts": { @@ -43,6 +43,8 @@ "devDependencies": { "@11ty/eleventy": "2.0.0-beta.2", "ava": "^5.1.0", + "postcss": "^8.4.21", + "postcss-nested": "^6.0.0", "sass": "^1.58.0" }, "dependencies": { diff --git a/test/stubs/use-transforms/eleventy.config.js b/test/stubs/use-transforms/eleventy.config.js new file mode 100644 index 0000000..842dd28 --- /dev/null +++ b/test/stubs/use-transforms/eleventy.config.js @@ -0,0 +1,16 @@ +const bundlePlugin = require("../../../"); +const postcss = require('postcss'); +const postcssNested = require('postcss-nested') + +module.exports = function(eleventyConfig) { + eleventyConfig.addPlugin(bundlePlugin, { + transforms: [async function(content) { + return new Promise(resolve => { + setTimeout(() => resolve(content), 50); + }); + }, async function(content) { + let result = await postcss([postcssNested]).process(content, { from: this.page.inputPath, to: this.page.outputPath }) + return result.css; + }] + }); +}; \ No newline at end of file diff --git a/test/stubs/use-transforms/index.liquid b/test/stubs/use-transforms/index.liquid new file mode 100644 index 0000000..c1b08d0 --- /dev/null +++ b/test/stubs/use-transforms/index.liquid @@ -0,0 +1,6 @@ + + +{%- css %}* { color: blue; }{% endcss %} +{%- css %}* { color: blue; }{% endcss %} +{%- css %}* { color: red; }{% endcss %} +{%- css %}#id { * { color: orange; } }{% endcss %} \ No newline at end of file diff --git a/test/test.js b/test/test.js index 8632215..9a1ba49 100644 --- a/test/test.js +++ b/test/test.js @@ -265,3 +265,13 @@ test("No bundling", async t => { `); }); + +test("Use Transforms", async t => { + let elev = new Eleventy("test/stubs/use-transforms/", undefined, { + configPath: "test/stubs/use-transforms/eleventy.config.js" + }); + let results = await elev.toJSON(); + t.deepEqual(normalize(results[0].content), ``); +});