From ceafcc8790b7d3254c9f23ea1114a4a886c50ed6 Mon Sep 17 00:00:00 2001 From: Sagar Vora <16315650+sagarvora@users.noreply.github.com> Date: Sun, 23 Nov 2025 20:53:16 +0530 Subject: [PATCH] fix: use script/link tag injection in frappe.require to preserve global scope - Changed frappe.require to use script/link tag injection instead of fetch + IIFE - This fixes loading of UMD libraries like html5-qrcode that need global scope - Maintains original behavior: waits for assets to load before callback - Resolves scanner breakage caused by PR #33973 --- frappe/public/js/frappe/assets.js | 54 ++++++++++++++++++++----------- 1 file changed, 35 insertions(+), 19 deletions(-) diff --git a/frappe/public/js/frappe/assets.js b/frappe/public/js/frappe/assets.js index cde8715c23..fade5972c9 100644 --- a/frappe/public/js/frappe/assets.js +++ b/frappe/public/js/frappe/assets.js @@ -23,11 +23,28 @@ class AssetManager { constructor() { this._executed = []; this._handlers = { - js: function (txt) { - frappe.dom.eval(txt); + js: (url) => { + return new Promise((resolve) => { + const script = document.createElement("script"); + script.type = "text/javascript"; + script.src = url; + script.onload = resolve; + // for backward compatibility, resolve even on error + script.onerror = resolve; + document.head.appendChild(script); + }); }, - css: function (txt) { - frappe.dom.set_style(txt); + css: (url) => { + return new Promise((resolve) => { + const link = document.createElement("link"); + link.type = "text/css"; + link.rel = "stylesheet"; + link.href = url; + link.onload = resolve; + // for backward compatibility, resolve even on error + link.onerror = resolve; + document.head.appendChild(link); + }); }, }; } @@ -77,11 +94,16 @@ class AssetManager { console.log("localStorage cleared"); } - eval_assets(path, content) { - if (!this._executed.includes(path)) { - this._handlers[this.extn(path)](content); - this._executed.push(path); + load_asset(path, url) { + if (this._executed.includes(path)) { + return Promise.resolve(); } + + const ext = this.extn(path); + const handler = this._handlers[ext]; + return handler(url).then(() => { + this._executed.push(path); + }); } execute(items, callback) { @@ -91,8 +113,7 @@ class AssetManager { const version_string = frappe.boot.developer_mode || window.dev_server ? Date.now() : window._version_number; - let fetched_assets = {}; - async function fetch_item(path) { + let load_promises = items.map((path) => { let url = new URL(path, window.location.origin); // Add the version to the URL to bust the cache for non-bundled assets @@ -103,17 +124,12 @@ class AssetManager { ) { url.searchParams.append("v", version_string); } - const response = await fetch(url.toString()); - fetched_assets[path] = await response.text(); - } + + return me.load_asset(path, url.toString()); + }); frappe.dom.freeze(); - const fetch_promises = items.map(fetch_item); - Promise.all(fetch_promises).then(() => { - items.forEach((path) => { - let body = fetched_assets[path]; - me.eval_assets(path, body); - }); + Promise.all(load_promises).then(() => { frappe.dom.unfreeze(); callback?.(); });