11ty / eleventy-plugin-webc

Adds support for WebC *.webc files to Eleventy
https://www.11ty.dev/docs/languages/webc/
120 stars 10 forks source link

Handling empty <script>, <style> and <link> tags when bundles are empty #82

Open noelforte opened 1 year ago

noelforte commented 1 year ago

This might be something that could be a lack of education on my part, so hoping either @zachleat or any others knowledgeable about how the WebC plugin works can help me find the right way to handle this.

On pages where there isn't any bundled content returned from getBundle(), the output files end up with empty <script></script> and <style></style> tags when using the example markup from the WebC Plugin Documentation like so:

<style @raw="getBundle('css')" webc:keep></style>
<script @raw="getBundle('js')" webc:keep></script>

I've tried using webc:if to conditionally render the style and script tags if getBundle() returns falsey, however, this doesn't appear to have any effect, even if I check to see if the bundle returns falsey:

<style webc:if="getBundle('css')" @raw="getBundle('css')" webc:keep></style>
<script webc:if="getBundle('js')" @raw="getBundle('js')" webc:keep></script>
<!-- or -->
<style webc:if="getBundle('css')" @raw="getBundle('css')" webc:keep></style>
<script webc:if="getBundle('js')" @raw="getBundle('js')" webc:keep></script>

As a last ditch effort, I've tried adding some logic to the bundler plugin to return early if there's empty content and combine that with webc:if, but that doesn't have any impact either:

eleventy.config.js ```js eleventyConfig.addPlugin(bundlerPlugin, { transforms: [ async function (content) { if (!content) { return false; } return content; }, ], }); ```
index.webc ``` ```

Also of note, when writing to an external file, if no bundle can be produced, WebC will produce invalid markup:

<link rel="stylesheet" href="">
<script src=""></script>

What's the preferred way to drop a <script> or <style> tag from rendering if a bundle returns empty? Is this something that's better to handle by post-processing the HTML output?

I've uploaded my reduced test case to https://github.com/noelforte/eleventy-webc-bundle-rtc in case anyone wants to tinker with how to handle this.

noelforte commented 1 year ago

Stumbled across this issue (https://github.com/11ty/eleventy-plugin-bundle/issues/8) while trying to dig deeper into this. Looks like handling empty bundles isn't quite supported yet. I'll leave this issue open in case anyone knows different but for now will probably add some global data to hide the script / style / link tags until there's official support.

noelforte commented 9 months ago

Have a workaround for this now: You can use a transform to post-process Eleventy's output to match and strip empty tags generated by @11ty/eleventy-plugin-bundle. If there's an official solution to this issue I'd love to hear it, but until then the following transform works great:

eleventyConfig.addTransform('formatHTML', async function (content) {
  if (this.page.outputPath && this.page.outputPath.endsWith('.html')) {
    const filtered = content
      // Remove all invalid script link and style tags
      .replaceAll(/<link.+href=["']{2}.*\/?>/g, '')
      .replaceAll(/<script((?!src=".+").)*><\/script>/g, '')
      .replaceAll(/<style.*>\s*<\/style>/g, '')

      // Clean up multi line breaks
      .replaceAll(/\s{2,}/g, '\n');

    return filtered;
  }
});

EDIT (02-01-2024): Note that this transform needs to be added AFTER the call to .addPlugin(webcPlugin) otherwise the transform happens too early and the content is still populated with the placeholder bundle comments.