execute dynamically inserted inline script elements

Scripts created via createElement('script') with inline content (textContent,
text, or innerHTML) and inserted into the DOM now execute per the HTML spec.
Previously all dynamically inserted scripts without a src attribute were
skipped, breaking most JS framework hydration patterns.
This commit is contained in:
egrs
2026-03-08 15:44:07 +01:00
parent 0227afffc8
commit ec9a2d8155
2 changed files with 60 additions and 3 deletions

View File

@@ -2908,9 +2908,12 @@ fn nodeIsReady(self: *Page, comptime from_parser: bool, node: *Node) !void {
} }
if (node.is(Element.Html.Script)) |script| { if (node.is(Element.Html.Script)) |script| {
if ((comptime from_parser == false) and script._src.len == 0) { if ((comptime from_parser == false) and script._src.len == 0) {
// script was added via JavaScript, but without a src, don't try // Script was added via JavaScript without a src attribute.
// to execute it (we'll execute it if/when the src is set) // Only skip if it has no inline content either — scripts with
return; // textContent/text should still execute per spec.
if (script.asConstElement().asConstNode().firstChild() == null) {
return;
}
} }
self.scriptAddedCallback(from_parser, script) catch |err| { self.scriptAddedCallback(from_parser, script) catch |err| {

View File

@@ -0,0 +1,54 @@
<!DOCTYPE html>
<head></head>
<script src="../../../testing.js"></script>
<script id=textContent_inline>
window.inline_executed = false;
const s1 = document.createElement('script');
s1.textContent = 'window.inline_executed = true;';
document.head.appendChild(s1);
testing.expectTrue(window.inline_executed);
</script>
<script id=text_property_inline>
window.text_executed = false;
const s2 = document.createElement('script');
s2.text = 'window.text_executed = true;';
document.head.appendChild(s2);
testing.expectTrue(window.text_executed);
</script>
<script id=innerHTML_inline>
window.innerHTML_executed = false;
const s3 = document.createElement('script');
s3.innerHTML = 'window.innerHTML_executed = true;';
document.head.appendChild(s3);
testing.expectTrue(window.innerHTML_executed);
</script>
<script id=no_double_execute_inline>
window.inline_counter = 0;
const s4 = document.createElement('script');
s4.textContent = 'window.inline_counter++;';
document.head.appendChild(s4);
document.head.appendChild(s4);
testing.expectEqual(1, window.inline_counter);
</script>
<script id=empty_script_no_execute>
window.empty_ran = false;
const s5 = document.createElement('script');
document.head.appendChild(s5);
testing.expectFalse(window.empty_ran);
</script>
<script id=module_inline>
window.module_executed = false;
const s6 = document.createElement('script');
s6.type = 'module';
s6.textContent = 'window.module_executed = true;';
document.head.appendChild(s6);
testing.eventually(() => {
testing.expectTrue(window.module_executed);
});
</script>