From be71277d33e1e7e1bfe3a4ca2922a33aa02b6c90 Mon Sep 17 00:00:00 2001 From: Ben Sully Date: Wed, 21 Feb 2024 13:25:00 +0000 Subject: [PATCH] Plugins: fix loading of modules which resolve to Promises (#82299) * Plugins: fix loading of modules which resolve to Promises Prior to this commit we expected the default export of a plugin module to be an object with a `plugin` field. This is the case for the vast majority of plugins, but if a plugin uses webpack's `asyncWebAssembly` feature then the default export will actually be a promise which resolves to such an object. This commit checks the result of the SystemJS import to make sure it has a `plugin` field. If not, and if the `default` field looks like a Promise, it recursively attempts to resolve the Promise until the object looks like a plugin. I think this may have broken with the SystemJS upgrade (#70068) because it used to work without this change in Grafana 10.1, but it's difficult to say for sure. * Use Promise.resolve instead of await to clean up some logic * Override systemJSPrototype.import instead of handling defaults inside importPluginModule * Add comment to explain why we're overriding systemJS' import Co-authored-by: Jack Westbrook --------- Co-authored-by: Jack Westbrook --- public/app/features/plugins/plugin_loader.ts | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/public/app/features/plugins/plugin_loader.ts b/public/app/features/plugins/plugin_loader.ts index c594b4f0a13..0a2172f0b9d 100644 --- a/public/app/features/plugins/plugin_loader.ts +++ b/public/app/features/plugins/plugin_loader.ts @@ -29,6 +29,17 @@ const systemJSPrototype: SystemJSWithLoaderHooks = SystemJS.constructor.prototyp // the content of the plugin code at runtime which can only be done with fetch/eval. systemJSPrototype.shouldFetch = () => true; +const originalImport = systemJSPrototype.import; +// Hook Systemjs import to support plugins that only have a default export. +systemJSPrototype.import = function (...args: Parameters) { + return originalImport.apply(this, args).then((module) => { + if (module && module.__useDefault) { + return module.default; + } + return module; + }); +}; + const systemJSFetch = systemJSPrototype.fetch; systemJSPrototype.fetch = function (url: string, options?: Record) { return decorateSystemJSFetch(systemJSFetch, url, options);