Skip to content

feat(html): add output.html to generate HTML for non-HTML entrypoints#21125

Closed
aryanraj45 wants to merge 2 commits into
webpack:mainfrom
aryanraj45:feat/output-html
Closed

feat(html): add output.html to generate HTML for non-HTML entrypoints#21125
aryanraj45 wants to merge 2 commits into
webpack:mainfrom
aryanraj45:feat/output-html

Conversation

@aryanraj45

@aryanraj45 aryanraj45 commented Jun 8, 2026

Copy link
Copy Markdown
Contributor

Summary

When output.html is true webpack emits an HTML file for every non-HTML entrypoint and injects the entrypoint's initial JS and CSS chunks. JS chunks are injected as deferred scripts (or type="module" for ESM output) at the end of <body>; CSS chunks as <link rel="stylesheet"> in <head>. HTML entries are left to HtmlModulesPlugin and are not duplicated. This is part of the experiments.html roadmap — bringing html-webpack-plugin abilities into webpack core.

What kind of change does this PR introduce?

feat

Did you add tests for your changes?

Yes — test/OutputHtmlPlugin.unittest.js (6 unit tests: default-off, JS inject, publicPath, ESM output, XSS escaping, HTML-entry skip) and test/configCases/output-html/ (2 integration cases).

Does this PR introduce a breaking change?

No. output.html defaults to false.

If relevant, what needs to be documented once your changes are merged or what have you already documented?

output.html option should be added to the webpack configuration docs.

Use of AI

Claude Code was used to assist with implementation, test scaffolding, and lint fixes. All logic was reviewed, tested, and validated manually per the webpack AI policy.

Copilot AI review requested due to automatic review settings June 8, 2026 12:10
@changeset-bot

changeset-bot Bot commented Jun 8, 2026

Copy link
Copy Markdown

⚠️ No Changeset found

Latest commit: 43732d0

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@aryanraj45 aryanraj45 requested a review from Copilot June 8, 2026 20:11

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@aryanraj45

Copy link
Copy Markdown
Contributor Author

@alexander-akait could u please have a look here implemented output.html to generate HTML for non-HTML entrypoints with JS/CSS chunk injection ask co-pilot to review ? Thanks!

Comment thread lib/html/OutputHtmlPlugin.js Outdated
}
}

module.exports = OutputHtmlPlugin;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is wrong solution, we should not add a new plugin, when output.html is true we should wrap all entrypoints (js or css) in html file, like we have entry: "./index.html", so template option will work and other things will work too, we already have logic about how to handle css, js and etc

Also we should support html in entry description option, so developer can set by entries where generate html where no

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ohh yeah, thanks for the direction! I went through the existing HTML pipeline publicPath is already handled by the generator, and the template gets reused automatically. So no other option needed for them in future as discussed. Got it, thanks!

@alexander-akait alexander-akait left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should revisit architecture

@aryanraj45

aryanraj45 commented Jun 9, 2026

Copy link
Copy Markdown
Contributor Author

@alexander-akait Done as discussed no new plugin. Each non-HTML entry is wrapped into a synthetic HTML entry through the existing pipeline (JS/CSS injection, publicPath, template all work). Also added html to the entry descriptor.

One thing: the synthetic entry also emits a [name].js (HTML module's JS export), same as a normal .html entry. Seemed fine to me please take a look when u have a moment thanks ;))

@aryanraj45 aryanraj45 force-pushed the feat/output-html branch 2 times, most recently from ca99e42 to 9aba257 Compare June 16, 2026 10:58
@aryanraj45

Copy link
Copy Markdown
Contributor Author

@alexander-akait could you please have a re-look :))

When output.html (or an entry's `html` option) is enabled, the entrypoint
is wrapped in a synthetic HTML module (<script src> for JS, <link> for
CSS) that flows through the existing HtmlModulesPlugin/HtmlGenerator
pipeline, so chunk injection, publicPath and the template option work like
a real `entry: "./index.html"`. Adds `html` to the entry descriptor for
per-entry control.

@alexander-akait alexander-akait left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let’s make it smarter, let’s add a hook for entry option plugin and use this hook in html webpack plugin, it will be more plugable, also other developers can use it to
Implement custom logic for non html files, for example for markdown

Move the output.html entry-wrapping logic out of EntryOptionPlugin into a
tap on a new EntryOptionPlugin.getHooks(compiler).entry SyncBailHook, and
register it from HtmlModulesPlugin. Other plugins can now redirect a
non-HTML entry to a custom request (e.g. markdown).
@aryanraj45

aryanraj45 commented Jun 17, 2026

Copy link
Copy Markdown
Contributor Author

@alexander-akait done Added an EntryOptionPlugin.getHooks().entry SyncBailHook and moved the
wrapping logic into a tap in HtmlModulesPlugin — EntryOptionPlugin is now decoupled from HTML and
any plugin can redirect a non-HTML entry markdown and etc. Also dded output-html-hook-custom test cases
proving a third-party plugin can wrap an entry via the hook without output.html. Thanks Please take a view :))

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants