eleventy-plugin-bundle icon indicating copy to clipboard operation
eleventy-plugin-bundle copied to clipboard

Needs additional guidance around feeding `getBundle` through a minifier

Open zachleat opened this issue 2 years ago • 3 comments

If you run getBundle output through a minifier before the transform gets to it, it will get removed!

Specifically this quick tip: https://www.11ty.dev/docs/quicktips/inline-css/#capture-and-minify

<!-- capture the CSS content as a Nunjucks variable -->
{% set css %}
  {% include "sample.css" %}
  {% getBundle "css" %}
{% endset %}
<!-- feed it through our cssmin filter to minify -->
<style>
  {{ css | cssmin | safe }}
</style>

Workaround is to move the bundle outside of the css minification pipeline (and optionally use a bundle transform to minify instead):

<!-- capture the CSS content as a Nunjucks variable -->
{% set css %}
  {% include "sample.css" %}
{% endset %}
<!-- feed it through our cssmin filter to minify -->
<style>
  {{ css | cssmin | safe }}
</style>
<style>{% getBundle "css" %}</style>

zachleat avatar Mar 04 '23 01:03 zachleat

@zachleat I chose to add minification directly in my own template format (I support Sass, not CSS):

  • https://github.com/nhoizey/pack11ty/blob/63ea72d55d41236fb965d6371caa87e5aeabf384/eleventy.config.js#L73-L78

(I'm currently trying to move this code out of the project config file, into a plugin, so this should no longer be in the main branch soon.)

nhoizey avatar May 12 '23 18:05 nhoizey

The doco explains how to do it: Modify the bundle output. This is also more performant during the build.

Here's an example of what I'm doing in my site: .eleventy.js

const bundlerPlugin = require("@11ty/eleventy-plugin-bundle");
const postcss = require('postcss');
const postcssNesting = require('postcss-nesting');
const autoprefixer = require('autoprefixer');
const cssnano = require('cssnano');
const UglifyJS = require("uglify-js");

module.exports = function (eleventyConfig) {
  eleventyConfig.addPlugin(bundlerPlugin, {
    transforms: [
      async function (code) {
        // this.type returns the bundle name.
        if (this.type === 'css') {
          // Same as Eleventy transforms, this.page is available here.
          let result = await postcss([
            // postcssNesting,
            autoprefixer,
            cssnano
          ]).process(code, { from: this.page.inputPath, to: null });
          return result.css;
        }
        if (this.type === 'js') {
          let minified = UglifyJS.minify(code);
          if (minified.error) {
            console.log("UglifyJS error: ", minified.error);
            return code;
          }
          return minified.code;
        }
        return code;
      }
    ]
  });
 }

head.njk

<head>
  [...]
  {% css %}
    {% include "assets/css/inline.css" %}
  {% endcss %}
  <!-- Inlined critical styles -->
  <style>{% getBundle "css" %}</style>
  
  <!-- Deferred non-critical styles -->
  <link rel="stylesheet" href="{% getBundleFileUrl 'css', 'defer' %}" media="print" onload="this.media='all'">
  <noscript>
  <link rel="stylesheet" href="{% getBundleFileUrl 'css', 'defer' %}">
  </noscript>
  
  <!-- Inlined js bundle -->
  <script>{% getBundle "js" %}</script>
</head>

elgandoz avatar May 24 '23 12:05 elgandoz

I tried replicating the example in the bottom of the readme but it did not work, ultimately, I used the solution by elgandoz and it's working fine.

As an example, here's the code that did not work:

    cfg.addBundle("css", {
        transforms: [
            (/** @type {string} */ input) => (new CleanCSS()).minify(input).styles
        ]
    });

    cfg.addBundle("js", {
        transforms: [
            async function(/** @type {string} */ input) {
                try {
                    const result = await minifyJs(input);
                    return result.code;
                } catch (e) {
                    // eslint-disable-next-line no-console
                    console.error(e);
                    return input;
                }
            }
        ]
    });

Have I messed up somewhere? I tried with non-arrow functions but still no success.

The working code:

    cfg.addPlugin(pluginBundle, {
        transforms: [
            async function(content) {
                // this.type returns the bundle name.
                if (this.type === "css") {
                    return (new CleanCSS).minify(content).styles;
                }

                if (this.type === "js") {
                    try {
                        const minified = await minifyJs(content);
                        return minified.code;
                    }
                    catch (e) {
                        // eslint-disable-next-line no-console
                        console.error(e);
                        return content;
                    }
                }

                return content;
            }
        ]
    });

zyriab avatar May 11 '24 16:05 zyriab