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 ((comptime from_parser == false) and script._src.len == 0) {
// script was added via JavaScript, but without a src, don't try
// to execute it (we'll execute it if/when the src is set)
return;
// Script was added via JavaScript without a src attribute.
// Only skip if it has no inline content either — scripts with
// textContent/text should still execute per spec.
if (script.asConstElement().asConstNode().firstChild() == null) {
return;
}
}
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>