Created
July 14, 2025 07:47
-
-
Save cboulanger/72a4f7bc43659608ed430ebfe203c07b to your computer and use it in GitHub Desktop.
js-plugin as an ESM module
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| /** | |
| * patched version of https://www.npmjs.com/package/js-plugin | |
| */ | |
| var _plugins = []; | |
| var _byName = {}; | |
| var _cache = {}; | |
| // Only support debug mode on browser and node, not web workers. | |
| var isBrowser = typeof window !== 'undefined' && typeof window.document !== 'undefined'; | |
| var isNode = | |
| typeof process !== 'undefined' && process.versions != null && process.versions.node != null; | |
| var isDebug = | |
| (isBrowser && document.location.search.includes('JS_PLUGIN_DEBUG')) || | |
| (isNode && process.env && process.env.JS_PLUGIN_DEBUG); | |
| function _isFunc(o) { | |
| return !!(o.constructor && o.call && o.apply); | |
| } | |
| function _get(obj, prop) { | |
| var arr = prop.split('.'); | |
| for (var i = 0; i < arr.length; i++) { | |
| if (!(arr[i] in obj)) return undefined; | |
| obj = obj[arr[i]]; | |
| } | |
| return obj; | |
| } | |
| function _has(obj, prop) { | |
| var arr = prop.split('.'); | |
| for (var i = 0; i < arr.length; i++) { | |
| if (!(arr[i] in obj)) return undefined; | |
| obj = obj[arr[i]]; | |
| } | |
| return true; | |
| } | |
| // patch: convert to esm export | |
| export default { | |
| config: {}, | |
| register: function (p) { | |
| if (!p.name) { | |
| console.log('Every plugin should have a name.'); | |
| console.log(p); | |
| throw new Error('Every plugin should have a name.'); | |
| } | |
| if (_byName[p.name]) { | |
| throw new Error('Plugin "' + p.name + '" already exits.'); | |
| } | |
| _cache = {}; | |
| _plugins = _plugins.slice(); | |
| var pos = _plugins.length; | |
| _plugins.forEach((p2, i) => { | |
| if (p2.deps && p2.deps.indexOf(p.name) >= 0) { | |
| pos = Math.min(pos, i); | |
| } | |
| }); | |
| _plugins.splice(pos, 0, p); | |
| _byName[p.name] = p; | |
| if (p.initialize) { | |
| p.initialize(); | |
| } | |
| }, | |
| unregister: function (name) { | |
| var p = _byName[name]; | |
| if (!p) throw new Error('Plugin "' + name + '" does\'t exist.'); | |
| var i = _plugins.indexOf(p); | |
| if (i === -1) | |
| throw new Error( | |
| 'Plugin "' + | |
| name + | |
| '" does\'t exist in _plugins but in _byName. This seems to be a bug of js-plugin.' | |
| ); | |
| _cache = {}; | |
| delete _byName[name]; | |
| _plugins = _plugins.slice(); | |
| _plugins.splice(i, 1); | |
| }, | |
| getPlugin: function (name) { | |
| return _byName[name]; | |
| }, | |
| getPlugins: function (prop) { | |
| if (!prop) { | |
| prop = '.'; | |
| } | |
| if (!_cache[prop]) { | |
| _cache[prop] = _plugins.filter((p) => { | |
| if (p.deps && p.deps.some((dep) => !_byName[dep])) { | |
| // If deps not exist, then not load it. | |
| const notExistDeps = p.deps.filter((dep) => !_byName[dep]); | |
| console.log( | |
| `Plugin ${p.name} is not loaded because its deps do not exist: ${notExistDeps}.` | |
| ); | |
| return false; | |
| } | |
| return prop === '.' ? true : _has(p, prop); | |
| }); | |
| } | |
| return _cache[prop]; | |
| }, | |
| processRawPlugins: function (callback) { | |
| // This method allows to process _plugins so that it could | |
| // do some unified pre-process before application starts. | |
| callback(_plugins); | |
| _cache = {}; | |
| }, | |
| invoke: function (prop) { | |
| var args = Array.prototype.slice.call(arguments, 1); | |
| if (!prop) throw new Error('Invoke on plugin should have prop argument'); | |
| var noCall = /^!/.test(prop); | |
| var throws = this.config.throws || /!$/.test(prop); | |
| prop = prop.replace(/^!|!$/g, ''); | |
| var arr = prop.split('.'); | |
| arr.pop(); | |
| var obj = arr.join('.'); | |
| return this.getPlugins(prop).map(function (p) { | |
| var method = _get(p, prop); | |
| if (!_isFunc(method) || noCall) return method; | |
| try { | |
| isDebug && console.log('Before', p.name, prop, args); | |
| return method.apply(_get(p, obj), args); | |
| } catch (err) { | |
| // When a plugin failed, doesn't break the app | |
| console.log('Failed to invoke plugin: ' + p.name + '!' + prop); | |
| if (throws) throw err; | |
| else console.log(err); | |
| } finally { | |
| isDebug && console.log('After ', p.name, prop, args); | |
| } | |
| return null; | |
| }); | |
| }, | |
| sort: function (arr, sortProp) { | |
| // A helper method to sort an array according to 'order' (or by sortProp) property of the array element. | |
| sortProp = sortProp || 'order'; | |
| arr.sort((a, b) => { | |
| var order1 = a.hasOwnProperty(sortProp) ? a[sortProp] : 1000000; | |
| var order2 = b.hasOwnProperty(sortProp) ? b[sortProp] : 1000000; | |
| return order1 - order2; | |
| }); | |
| } | |
| }; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment