Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow HTML as entry points #2873

Closed
surma opened this issue May 23, 2019 · 5 comments
Closed

Allow HTML as entry points #2873

surma opened this issue May 23, 2019 · 5 comments

Comments

@surma
Copy link

surma commented May 23, 2019

Feature Use Case

For web apps, one or multiple HTML files are the de-facto entrypoint. I’d love for rollup to be able to handle this (with the help of a plugin).

Feature Proposal

To bring this to a more generic level, and with #2823 and #2872 in mind, I’d propose to allow assets (non-JS files) to be entry points. Plugins that handle these assets can then analyze these files and emit dependencies, which can be both further assets and JavaScript files.

I have written a small experimental plugin to teach Rollup to handle HTML. I’m mostly including this code fragment to show how weird this currently feels. Maybe we can come up with something better.

export default function htmlPlugin(opts) {
  // ... set up filter ...
  
  const contentMap = new Map();
  return {
    name: "html-plugin",
    
    async load(id) {
      if (!filter(id)) {
        return;
      }
      const contents = await fs.promises.readFile(id, { encoding: "utf-8" });
      const doc = parseHTML(contents);

      // Find references to JavaScript and CSS files.
      const references = [
        ... await findScriptTags(doc, id),
        ... await findStylesheets(doc, id)
      ];
      
      contentMap.set(id, {doc, references});
      // Because Rollup expects JavaScript, we return an empty file
      // and will inject the original contents in `generateBundle`.
      return {
        code: ""
      };
    },
    generateBundle(outputOptions, bundles) {
      for(const bundleId of Object.keys(bundles)) {
        const bundle = bundles[bundleId];
        if(bundle.isAsset) {
          continue;
        }
        if(!contentMap.has(bundle.facadeModuleId)) {
          continue;
        }
        const {doc, references} = contentMap.get(bundle.facadeModuleId);
        // Replace the references to JavaScript and CSS
        // with their new Rollup-generated file names.
        for(const reference of references) {
          reference.value = this.getChunkFileName(reference.value);
        } 
        bundle.code = serializeHTML(doc);
      }
    }
  };
}
@lukastaegert
Copy link
Member

This does not look "too bad" to me :)

I would be very wary of adding HTML handling to Rollup core. This is a very web specific feature that will possibly come with quite some overhead and a huge maintenance cost that I do not want to carry around. Also it is unclear to me what advantage it would have to have the HTML files as part of the dependency graph. Thus I will try to focus more on the problem you are attempting to solve.

As a suggestion how I would change your approach:
If you like to abuse Rollup's input option to specify an HTML file, you absolutely can! Just use the options hook and replace the input with an empty array. Yes, that should work! Of course if there are no inputs, then you MUST emit some chunks in the buildStart hook so that there is something to bundle.

Alternatively, you can ask the user to provide no inputs but I guess this feels wrong to the user.

Then you will not need to specify a load hook that filters ids but just a buildStart hook that emits chunks.

What is missing is a clean way to emit the updated HTML file(s) as you probably do not want to place them next to the other assets but next to the entry points or possibly in yet another location. As a "hack" you can currently just add new stuff to the bundle in generate bundle. I hope to add a proper context helper function for this in the future (so that you can also emit from other hooks).

@shellscape
Copy link
Contributor

I would be very wary of adding HTML handling to Rollup core. This is a very web specific feature that will possibly come with quite some overhead and a huge maintenance cost that I do not want to carry around.

Seconded.

@tivac
Copy link
Contributor

tivac commented May 24, 2019

That original snippet works basically exactly how I'd expect it to work, and doesn't seem that weird at all to me. Maybe I've been too deep into rollup plugins that support non-JS content for too long, dunno.

@LongTengDao
Copy link
Contributor

You want this?

(input)

<!DOCTYPE html>
<html>
    <head>
        <link rel="stylesheet" href="bootstrap" />
        <link rel="stylesheet" href="./style.css" />
        <script src="../lib.js"></script>
        <script src="./main.js"></script>
    </head>
    <body>
    </body>
</html>

(config)

const bundle = await rollup({
    input: '/index.html',
    external: [ 'bootstrap', '../lib.js' ],
});
const generated = await rollup({
    format: 'html',
    paths: {
        bootstrap: '../lib/bootstrap.css',
    },
});

(output)

<!DOCTYPE html>
<html>
    <head>
        <link rel="stylesheet" href="../lib/bootstrap.css" />
        <style> /* code in ./style.js */ </style>
        <script src="../lib.js"></script>
        <script> /* code in ./main.js */ </script>
    </head>
    <body>
    </body>
</html>

@surma
Copy link
Author

surma commented May 26, 2019

I should have been clearer, apologies.

I definitely do not want to add full HTML support to Rollup core. The core of my proposal was to allow assets (non-JS files) to be entry points. In combination with #2872, a plugin could then take care of emitting the chunks found in the asset file.

If you like to abuse Rollup's input option to specify an HTML file, you absolutely can! Just use the options hook and replace the input with an empty array. Yes, that should work! Of course if there are no inputs, then you MUST emit some chunks in the buildStart hook so that there is something to bundle.

This is probably a sane-ish solution. I’ll close this and rather focus in #2872 :D

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

5 participants