From 8fbd64955f609b5dae954381573b5b6115e663d4 Mon Sep 17 00:00:00 2001 From: Karl Seguin Date: Sun, 21 Dec 2025 16:51:39 +0800 Subject: [PATCH] Dynamically added scripts default to async --- src/browser/Page.zig | 6 +++--- src/browser/ScriptManager.zig | 15 ++++++++++++++- .../tests/element/html/script/dynamic.html | 9 ++++++--- src/browser/webapi/element/html/Script.zig | 2 +- 4 files changed, 24 insertions(+), 8 deletions(-) diff --git a/src/browser/Page.zig b/src/browser/Page.zig index d6708668..97c72f9a 100644 --- a/src/browser/Page.zig +++ b/src/browser/Page.zig @@ -895,8 +895,8 @@ pub fn tick(self: *Page) void { self.js.runMicrotasks(); } -pub fn scriptAddedCallback(self: *Page, script: *Element.Html.Script) !void { - self._script_manager.addFromElement(script, "parsing") catch |err| { +pub fn scriptAddedCallback(self: *Page, comptime from_parser: bool, script: *Element.Html.Script) !void { + self._script_manager.addFromElement(from_parser, script, "parsing") catch |err| { log.err(.page, "page.scriptAddedCallback", .{ .err = err, .src = script.asElement().getAttributeSafe("src"), @@ -2180,7 +2180,7 @@ fn nodeIsReady(self: *Page, comptime from_parser: bool, node: *Node) !void { return; } - self.scriptAddedCallback(script) catch |err| { + self.scriptAddedCallback(from_parser, script) catch |err| { log.err(.page, "page.nodeIsReady", .{ .err = err }); return err; }; diff --git a/src/browser/ScriptManager.zig b/src/browser/ScriptManager.zig index 4cdbdc8b..ccc00d04 100644 --- a/src/browser/ScriptManager.zig +++ b/src/browser/ScriptManager.zig @@ -143,7 +143,7 @@ fn clearList(list: *std.DoublyLinkedList) void { } } -pub fn addFromElement(self: *ScriptManager, script_element: *Element.Html.Script, comptime ctx: []const u8) !void { +pub fn addFromElement(self: *ScriptManager, comptime from_parser: bool, script_element: *Element.Html.Script, comptime ctx: []const u8) !void { if (script_element._executed) { // If a script tag gets dynamically created and added to the dom: // document.getElementsByTagName('head')[0].appendChild(script) @@ -220,12 +220,25 @@ pub fn addFromElement(self: *ScriptManager, script_element: *Element.Html.Script if (source == .@"inline") { break :blk if (kind == .module) .@"defer" else .normal; } + if (element.getAttributeSafe("async") != null) { break :blk .async; } + + // Check for defer or module (before checking dynamic script default) if (kind == .module or element.getAttributeSafe("defer") != null) { break :blk .@"defer"; } + + // For dynamically-inserted scripts (not from parser), default to async + // unless async was explicitly set to false (which removes the attribute) + // and defer was set to true (checked above) + if (comptime !from_parser) { + // Script has src and no explicit async/defer attributes + // Per HTML spec, dynamically created scripts default to async + break :blk .async; + } + break :blk .normal; }, }; diff --git a/src/browser/tests/element/html/script/dynamic.html b/src/browser/tests/element/html/script/dynamic.html index 766c3180..dcd0d403 100644 --- a/src/browser/tests/element/html/script/dynamic.html +++ b/src/browser/tests/element/html/script/dynamic.html @@ -2,12 +2,15 @@ - -