msgpack.js icon indicating copy to clipboard operation
msgpack.js copied to clipboard

Detect Web Workers environment

Open grz0zrg opened this issue 5 years ago • 3 comments

When the library is used in a web worker there is an issue with undefined window so i suggest adding Web Workers detection such as :

// Environment detection
if (typeof module === "object" && module && typeof module.exports === "object") {
	// Node.js
	module.exports = msgpack;
}
else if (typeof WorkerGlobalScope !== 'undefined' && self instanceof WorkerGlobalScope) {
	// Global object
	self[self.msgpackJsName || "msgpack"] = msgpack;
} else {
	// Global object
	window[window.msgpackJsName || "msgpack"] = msgpack;
}

grz0zrg avatar Feb 02 '20 01:02 grz0zrg

Unfortunately I have no idea about web workers. This answer suggests that your suggested code change won't work very well. And I couldn't find out what that self is. I'll leave this open until somebody provides a reliable alternative.

ygoe avatar Jun 21 '20 09:06 ygoe

In the script of Web Workers, the self property returns WorkerGlobalScope object (the Worker global scope).

WorkerGlobalScope - Web APIs | MDN

I reference the solution from the other library:

  // Environment detection
  if (
    typeof module === "object" && module && typeof module.exports === "object"
  ) {
    // Node.js
    module.exports = msgpack;
  } else {
    // Global object
    var g;
    if (typeof window !== "undefined") {
      g = window;
    } else if (typeof global !== "undefined") {
      g = global;
    } else if (typeof self !== "undefined") {
      g = self;
    } else {
      g = this;
    }
    g[g.msgpackJsName || "msgpack"] = msgpack;
  }

ShenTengTu avatar Jun 26 '20 03:06 ShenTengTu

https://caniuse.com/?search=globalThis https://mathiasbynens.be/notes/globalthis has discussion on polyfills

Based on the above, pass the globalThis into your IIFE like this:

(function (_global) { //bind globalThis to _global
...
	// Environment detection
	if (typeof module === "object" && module && typeof module.exports === "object") {
		// Node.js
		module.exports = msgpack;
	}
	else if (_global) {
		// Global object
		_global[_global.msgpackJsName || "msgpack"] = msgpack;
	}
)(globalThis || this || self || window);

Notes:

  • Assumes no one bound something unexpected to globalThis from the context you call the IIFE.
  • In most modern JS environments globalThis will be defined and that's what will be used
  • If the JS environment is older, first fallback is this.
    • There are edge cases where this is not defined, so the next fallbacks are self || window
    • There are edge cases where self || window is undefined... or someone could have done var self=something so first fallback is this.
    • It is possible someone imported or called your IIFE from something other than the global context. But is this likely? I can't imagine any use case where someone would do this...
  • Finally, if this was undefined from the context msgpack.js was imported, the fallbacks self || window will work if some unexpected value wasn't bound to them. It's a risk that someone may have defined var self=something in the context of the import, but it would be unusual; especially if the previous globalThis and this were not defined.

There won't be any perfect solution to polyfill globalThis... but this is decent I think.

Another option is to not define global.mspack. and instead just support commonJS and expect browsers to use an applicable module loader that supports commonjs.

darcyparker avatar Jan 06 '21 20:01 darcyparker