Skip to content

Keep HTML module roots independent and classify their type correctly - #1768

Merged
Lorenzobattistela merged 1 commit into
bendlang:mainfrom
oxura:fix/html-script-types-20261019e
Oct 20, 2026
Merged

Lorenzobattistela merged 1 commit into
bendlang:mainfrom
oxura:fix/html-script-types-20261019e

Conversation

@oxura

@oxura oxura commented Oct 19, 2026 •

Copy link
Copy Markdown
Contributor

Fixes HTML script classification and independent inline modules that deadlocked when Bun combined them into one sequential chunk.

Only inline modules become separate entries in the shared build graph. External src scripts stay on Bun's normal HTML path, including root-relative URLs and packages with sideEffects: false. Shared dependencies still execute once. The HTML batch stays outside inert templates and isn't duplicated when Bun already put it in the head.

Checked the real CLI and Chromium: the waiting page reaches 42; root-relative, side-effects, template/head placement and output-name cases pass. All three executable IO consumers print 0, including the new root-relative and console-only regressions. Child spawns use isolated HOME/origin/telemetry and 6-second timeouts. Repo gate: 54/54.

Missing external srcs use Bun's native diagnostic against the page and original relative specifier. No kernel, GUIDE, changelog, gate or cap changes.

Closes #1767

@oxura oxura changed the title Recognize HTML module types without activating inert scripts Keep HTML module roots independent and classify their type correctly Oct 19, 2026
@Lorenzobattistela Lorenzobattistela self-assigned this Oct 20, 2026

@Lorenzobattistela Lorenzobattistela left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Thanks for this. The type-classification fix and the deadlock repro are both solid, and the gates are green merged onto main d169272 (repo 54/54, test 1680/1680, perf 124/124, ping 63/63, safe 0 false rejects). But turning external module scripts into wrapper entries changes behavior beyond #1767/#1774, and three of those changes break pages that build on main:

  1. Root-relative srcs no longer build. <script type="module" src="/src/main.js"> (the usual Vite-style index.html) goes through path.resolve(dirname(file), source), which resolves to the filesystem root. Run from the page's directory, main builds this page; the PR fails with Could not resolve: "/src/main.js" at a.html:1:8.

  2. "sideEffects": false silently empties the script. The wrapper import "/abs/m.js"; is a bare side-effect import, and Bun drops it under "sideEffects": false. With a package.json holding {"sideEffects":false} and <script type="module" src="./m.js"> (m.js = console.log("side")), main's output contains the log; the PR's bend-entry-0-.js and chunk-.js are both empty, and the build reports no error.

  3. A module root inside <template> swallows the classic batch. early is inserted before the first rewritten module root even when that root is inside an inert <template>, and the real batch tag is then removed. With <template><script type="module">…</script></template><script src="./c.js"></script><script type="module">…</script>, c.js never runs. On main it does.

The simplest fix for all three may be to keep external src modules as Bun handles them today, and only split inline modules into separate entries. That's enough for #1774.

Smaller things:

  1. An unresolvable external src now reports the wrapper's location: m.html:1:8 with a code frame showing the generated import "/abs/..." line, instead of the user's ./missing.ts on its real line.
  2. tests/io/html_script_types.js runs main.ts without the HOME / BEND_ORIGIN / BEND_NO_TELEMETRY overrides and without a spawn timeout (the other two tests set them), so a gate run touches the real ~/.bend cache, calls bend-lang.com/check, and a stuck child can hang the shard.
  3. emitted takes any entry-point output whose basename matches bend-entry-N-, including the HTML page itself when the page is named bend-entry-0.html. It only works because the JS output happens to come last; filtering on .js would make it deterministic.
  4. When Bun's batch tag sits in <head> and the module roots are in <body>, the head tag is never removed, so the batch is emitted twice.
  5. Nit: the page's dest uses path.join(dir, …) while every other output uses path.resolve, so the size listing mixes relative and absolute paths. file is also bound three ways inside cli_bundle (page realpath, href's parameter, output path); renaming the inner two would make it easier to read.

@oxura

oxura commented Oct 20, 2026

Copy link
Copy Markdown
Contributor Author

Thanks, I'll keep external src scripts on Bun's normal path and split only inline modules. I'll fix the template/head batch placement and the test isolation too, then check the remaining diagnostics/output cases before pushing.

@oxura

oxura commented Oct 20, 2026

Copy link
Copy Markdown
Contributor Author

Pushed 903dffe. Cut out the external wrappers: only inline modules become separate entries now. Added real CLI regressions for root-relative srcs and a console-only module under sideEffects: false.

The batch stays outside templates, and an existing head batch is reused rather than copied. Entry mapping ignores HTML outputs; output paths are absolute and the shadowed bindings are gone. All three consumers now isolate HOME/origin/telemetry and give child processes a 6-second timeout.

The missing-src error now names ./missing.ts and the original HTML file, not the generated import. Bun 1.4.3 doesn't provide a line number for that native error.

All three IO consumers print 0, the Chromium cases pass (classic once, template inert, no duplicate batch, await reaches 42), and repo is 54/54.

HTMLRewriter keeps character references in attributes, so an encoded
"mod&bendlang#117;le" was skipped, and trim() strips NBSP, so a non-module type
ran. Decode the ASCII references that can spell "module" and trim only
HTML whitespace.

Closes bendlang#1767

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@Lorenzobattistela
Lorenzobattistela force-pushed the fix/html-script-types-20261019e branch from ac0c907 to c124b05 Compare October 20, 2026 14:29
@Lorenzobattistela

Copy link
Copy Markdown
Collaborator

Thanks for both fixes and the careful repros. We've cut this PR down to the #1767 fix and force-pushed it as one commit (authored by you): the HTML-rules decoding of type in is_inline_module plus tests/io/html_script_types. That's +152 ttok on main.ts, and all gates are green on main 60ca80a (repo 54/54, test 1692/1692, perf 124/124, ping 63/63, safe 0 false rejects).

We're not taking the #1774 part. After two review rounds we did have a version that kept every module root independent (per-script entries mapped through Bun's metafile, CSS links, template and batch handling; still reachable at ac0c907). But it cost about +1,600 ttok on main.ts and depends on Bun internals for a rare pattern. The underlying behavior is Bun's: its HTML bundler merges a page's module scripts into one sequential chunk, even separate src files. Details on #1774.

Removing our earlier changes-requested review once this lands.

@Lorenzobattistela
Lorenzobattistela merged commit b0d1ca6 into bendlang:main Oct 20, 2026
1 check passed
@oxura

oxura commented Oct 20, 2026

Copy link
Copy Markdown
Contributor Author

Thanks for landing the type-decoding fix. I'll keep the Bun workaround out and won't push the old branch over your rewrite.

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.

HTML bundling misses encoded module types and activates scripts with non-ASCII whitespace

2 participants