Skip to content

Allow HTML as entry points #2873

Closed
Closed

Description

@surma

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);
      }
    }
  };
}

Activity

  1. lukastaegert commented on May 24, 2019

    @lukastaegert
    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).

  2. shellscape commented on May 24, 2019

    @shellscape
    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.

  3. tivac commented on May 24, 2019

    @tivac
    Contributor

    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.

  4. LongTengDao commented on May 26, 2019

    @LongTengDao
    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>
  5. surma commented on May 26, 2019

    @surma
    Author

    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

  6. vadimkantorov commented on Nov 16, 2025

    @vadimkantorov

    Curious, what is the situation in 2025?

    E.g. I have HTML file entry point which has a <script> which imports some things from npm-installed modules. I'd like to have a single self-contained HTML file as output, with all JavaScript dependencies' source code embedded in <script> tags. Can one achieve this with rollup?

    Thanks!

  7. lukastaegert commented on Nov 16, 2025

    @lukastaegert
    Member

    You can do exactly as was stated above. To clean up the output, the official way is to specify a generateBundle hook. To remove the unwanted files, just delete from the bundle object. The HTML output can be added at this point via this.emitFile using the fileName option, as it also states in the docs:

    You can prevent files from being emitted by deleting them from the bundle object in this hook. To emit additional files, use the this.emitFile plugin context function.

  8. vadimkantorov commented on Nov 16, 2025

    @vadimkantorov

    Also, I found that official HTML plugin exists now, but does not support HTML entry points for some reason...

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

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions