FredKSchott / snowpack

ESM-powered frontend build tool. Instant, lightweight, unbundled development. ✌️
https://www.snowpack.dev
MIT License
19.48k stars 922 forks source link

[BUG] Snowpack since v3.1.0 emits only one file by .load() method #3099

Closed orlov-vo closed 3 years ago

orlov-vo commented 3 years ago

Bug Report Quick Checklist

Describe the bug

Snowpacks since v3.1.0 emits XXX.h1.html files instead of XXX.html and XXX.css when I using own plugin and empty XXX.h1 file:

module.exports = function htmlPlugin(_snowpackConfig, _pluginOptions) {
  return {
    name: 'html-plugin',
    resolve: {
      input: ['.h1'],
      output: ['.html', '.css'],
    },
    async load() {
      return {
        '.html': { code: '<h1>Hello world</h1>' },
        '.css': { code: '.h1 { color: red }' },
      }
    },
  }
}

For convenience, I've created a repository with minimal reproducable env of the bug: https://github.com/orlov-vo/snowpack-html-bug

Expected behavior

It should emit multiple files as it was before in v3.0.13

orlov-vo commented 3 years ago

Another great question is why it starts name files as XXX.h1.html since v3.0.0 instead ofXXX.html as it was before in v2.18.5?

drwpow commented 3 years ago

The change to XXX.h1.html was intentional. It helps Snowpack look up files faster in both dev and build, by being able to trace it back to its original source file.

But the missing files is unexpected, though. I believe this may happen accidentally because one file is not being imported by your project, so it’s accidentally discarded. So it is outputting both files, but they might not both make it to the final build.

This is probably something I’ll be working on soon, but may happen as part of a larger improvement to Snowpack. In the meantime, try importing one or both files either in an .html or .js file. That should trigger both files to be output correctly.

drwpow commented 3 years ago

Sorry for the delay in investigating this. This is definitely an issue introduced in 3.1 as stated. Working on a fix + test for this now!

drwpow commented 3 years ago

This should be resolved in v3.3.7! 🎉

Another great question is why it starts name files as XXX.h1.html since v3.0.0 instead of XXX.html as it was before in v2.18.5?

Wanted to add an additional comment to my other statement: we’ll be releasing an update in the semi-near future that allows customizing this in a non-breaking way. But will take a little bit of work first to get right. So while this is the current 3.x behavior as stated, you’ll be able to use 2.x-style extensions in an upcoming update if you’re a plugin author.

Xeevis commented 3 years ago

Wanted to add an additional comment to my other statement: we’ll be releasing an update in the semi-near future that allows customizing this in a non-breaking way. But will take a little bit of work first to get right. So while this is the current 3.x behavior as stated, you’ll be able to use 2.x-style extensions in an upcoming update if you’re a plugin author.

@drwpow I just arrived at probably related issue when creating filter plugin for excluding files from output based on globs.

[
  "filter-plugin",
  {
    paths: ["**/*.razor", "**/*.pcss", "**/*.styles.css", "**/*.razor.css"],
  },
],
module.exports = (snowpackConfig, pluginOptions) => {
  return {
    name: "filter-plugin",
    resolve: {
      input: [...parseExtensions(pluginOptions.paths)],
      output: [...parseExtensions(pluginOptions.paths)],
    },
    async load({ filePath, isDev }) {
      let relativePath = path.relative(process.cwd(), filePath);
      if (!micromatch.isMatch(relativePath, pluginOptions.paths)) {
        return;
      }
      return "";
    },
  };
};

function parseExtensions(paths) {
  let extensions = [];
  paths.forEach((filePath) => {
    extensions.push(path.extname(filePath));
  });

  return new Set(extensions);
}

It works great, except CSS files that should be just passed through with return; have duplicated extension app.css builds as app.css.css which is not behavior I'd expect, I can work around this by setting just output: [".css"], but it fairly limits the reusability of the plugin for other extensions. Will 2.x-style help with this? Should I open new issue? Thanks for all the hard work and your time 🙏🏻.