amark / gun

An open source cybersecurity protocol for syncing decentralized graph data.
https://gun.eco/docs
Other
17.93k stars 1.16k forks source link

Loading sea.js with importScripts fails in worker #1334

Open eternal-turtles opened 11 months ago

eternal-turtles commented 11 months ago

Hi, I'm seeing the following error when attempting to load sea.js using importScripts in a SharedWorker:

shared.worker.js:9 Uncaught DOMException: Failed to execute 'importScripts' on 'WorkerGlobalScope': The script at 'https://cdn.jsdelivr.net/npm/gun@0.2020.1239/sea.js' failed to load.
    at http://localhost:8000/shared.worker.js:9:6

In addition, it seems that loading gun.js using importScripts assigns GUN to window, which is unavailable in a worker environment. Is there a non-hacky way to load gun.js using importScripts?

Code:

const window = {}; // gun.js import sets window.GUN.

self.importScripts(
  "https://cdn.jsdelivr.net/npm/gun@0.2020.1239/gun.js"
);

console.log("GUN", window.GUN);

self.importScripts(
  "https://cdn.jsdelivr.net/npm/gun@0.2020.1239/sea.js" // Throws error.
);

Demo: https://github.com/eternal-turtles/gun-shared-worker-bug-demo

amark commented 11 months ago

@eternal-turtles @bmatusiak

https://github.com/amark/gun/blob/master/gun.js#L544

should only do if window exists, idk why its doing it without.

but maybe module also doesn't exist, so it is never exported & never globalized?

the issue is we CANNOT do ES6+ module export because you can't try/catch and without it breaks old browsers.

so maybe we can do something like window||self in a safe way?

bmatusiak commented 11 months ago

I think the global is called WorkerGlobalScope or something stupid

eternal-turtles commented 11 months ago

@amark Yes, if the first line is removed ( const window = {};), then the gun.js import won't fail, there's just no way I've found to actually access GUN. The window || self fallback would work I think, but it looks like globalThis may be more appropriate depending on browser support (hadn't heard about this before, thanks @bmatusiak) - https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/globalThis

atjn commented 11 months ago

the issue is we CANNOT do ES6+ module export because you can't try/catch and without it breaks old browsers.

@amark what old browsers are you trying to support? To not have ES6 support, you would need to be using a 5+ year old browser. That is so old, it would be trivial to hack. According to caniuse, ~98.5%* of all network traffic supports ES6, and when you factor in that GUN already uses some methods that are not supported in old browsers, it is likely only a very small set of browsers that would see new breakage.

If any developer has a need to support these old browsers, it is relatively simple to install Babel and transpile it to ancient JS. You could even do the transpiling in this repo and provide a simple code example showing how to conditionally load the transpiled vs new version of GUN.

*: adjusting for known issues with caniuse's data

0awful commented 11 months ago

@atjn There's also a question of if it would be better to use polyfills to regain the support of older browsers.

On the topic of the thread. @eternal-turtles If you're attempting to use GUN within a web worker you may run into additional problems. AFAIK you cannot open a webRTC connection within a web worker and I believe GUNDB does require webrtc. Do watch my words though because in the link I call out it is mentioned that you can transfer an existing webrtc connection to a web worker. Will that work with GUN? Who knows! @amark might have an answer but experimentation may give us all more information.

eternal-turtles commented 11 months ago

We found that adding the following at the top of the worker script is sufficient for importing gun/gun and gun/sea: self.window = self;. I haven't had time yet to actually test doing anything with gun within a worker, but I'll be on the lookout for the WebRTC issue - thanks @imizaac