fix (worker): iframe worker issue

Whenever using worker through an iframe it was throwing:

cannot open file SecurityError: Failed to construct 'Worker': Script at 'http://localhost:8000/assets/c06e8f0a220ae2c4e6fd03dd808e69ff1beee4c2/plugin/application_gis.zip/loader_dbf.worker.js' cannot be accessed from origin 'null'.
    at Module.default (loader_dbf.js:9:20)
    at application_table.js:58:50

So we made a helper function to run workers with an option to make it
compatible with iframes. The issue is it does require some flag to be
passed through the iframe: allow-same-origin and allow-scripts but this
was the only way we had to get it done until a better solution comes in
This commit is contained in:
MickaelK 2025-07-17 15:56:53 +10:00
parent a2f56f23c7
commit 083eac248f

View file

@ -1,3 +1,5 @@
import { onDestroy } from "../lib/skeleton/index.js";
export async function loadJS(baseURL, path, opts = {}) { export async function loadJS(baseURL, path, opts = {}) {
const $script = document.createElement("script"); const $script = document.createElement("script");
const link = new URL(path, baseURL); const link = new URL(path, baseURL);
@ -26,6 +28,31 @@ export async function loadCSS(baseURL, path) {
}); });
} }
export async function loadWorker(baseURL, path, opts = {}) {
const { iframe = true } = opts;
let url = new URL(path, baseURL);
if (iframe) {
// eg: fix issue coming from loading worker through an iframe like this nasty:
// SecurityError: Failed to construct 'Worker': Script at 'xxx.worker.js' cannot be accessed from origin 'null'.
// at Module.default (loader_dbf.js:9:20)
// at application_table.js:58:50
let code = await fetch(new URL(path, baseURL)).then((res) => res.text());
const importPathRE = new RegExp("import\\s+(?:[^'\";]*?\\s+from\\s+)?[\"']([^\"']+)[\"']", "gm");
code = code.replaceAll("import.meta.url", `"${baseURL}"`)
code.matchAll(importPathRE).forEach(([_, path]) => {
code = code.replaceAll(path, new URL(path, baseURL));
});
url = URL.createObjectURL(new Blob([code], { type: "application/javascript" }));
onDestroy(() => URL.revokeObjectURL(url));
}
const worker = new Worker(url, { type: "module" });
onDestroy(() => worker.terminate());
await new Promise((resolve) => worker.addEventListener(
"message", resolve, { once: true },
));
return worker;
}
export async function loadCSSInline(baseURL, filename) { export async function loadCSSInline(baseURL, filename) {
const res = await fetch(new URL(filename, baseURL).pathname, { const res = await fetch(new URL(filename, baseURL).pathname, {
cache: "force-cache", cache: "force-cache",