diff --git a/public/app/features/plugins/loader/cache.ts b/public/app/features/plugins/loader/cache.ts index 3db74fd2a70..7bc30c405f9 100644 --- a/public/app/features/plugins/loader/cache.ts +++ b/public/app/features/plugins/loader/cache.ts @@ -1,17 +1,22 @@ import { clearPluginSettingsCache } from '../pluginSettings'; -const cache: Record = {}; +const cache: Record = {}; const initializedAt: number = Date.now(); type CacheablePlugin = { path: string; version: string; + isAngular?: boolean; }; -export function registerPluginInCache({ path, version }: CacheablePlugin): void { +export function registerPluginInCache({ path, version, isAngular }: CacheablePlugin): void { const key = extractPath(path); if (key && !cache[key]) { - cache[key] = encodeURI(version); + cache[key] = { + version: encodeURI(version), + isAngular, + path, + }; } } @@ -28,12 +33,19 @@ export function resolveWithCache(url: string, defaultBust = initializedAt): stri if (!path) { return `${url}?_cache=${defaultBust}`; } - - const version = cache[path]; + const version = cache[path]?.version; const bust = version || defaultBust; return `${url}?_cache=${bust}`; } +export function getPluginFromCache(path: string): CacheablePlugin | undefined { + const key = extractPath(path); + if (!key) { + return; + } + return cache[key]; +} + function extractPath(address: string): string | undefined { const match = /\/?.+\/(plugins\/.+\/module)\.js/i.exec(address); if (!match) { diff --git a/public/app/features/plugins/loader/types.ts b/public/app/features/plugins/loader/types.ts index 023f6a3986c..108f034d0b4 100644 --- a/public/app/features/plugins/loader/types.ts +++ b/public/app/features/plugins/loader/types.ts @@ -1,7 +1,7 @@ // Extend the System type with the loader hooks we use // to provide backwards compatibility with older version of Systemjs export type SystemJSWithLoaderHooks = typeof System & { - shouldFetch: () => Boolean; + shouldFetch: (url: string) => Boolean; fetch: (url: string, options?: Record) => Promise; onload: (err: unknown, id: string) => void; }; diff --git a/public/app/features/plugins/plugin_loader.ts b/public/app/features/plugins/plugin_loader.ts index 0593d1e3eea..86fa82d8897 100644 --- a/public/app/features/plugins/plugin_loader.ts +++ b/public/app/features/plugins/plugin_loader.ts @@ -11,14 +11,14 @@ import { DataQuery } from '@grafana/schema'; import { GenericDataSourcePlugin } from '../datasources/types'; import builtInPlugins from './built_in_plugins'; -import { registerPluginInCache } from './loader/cache'; +import { getPluginFromCache, registerPluginInCache } from './loader/cache'; // SystemJS has to be imported before the sharedDependenciesMap import { SystemJS } from './loader/systemjs'; // eslint-disable-next-line import/order import { sharedDependenciesMap } from './loader/sharedDependencies'; import { decorateSystemJSFetch, decorateSystemJSResolve, decorateSystemJsOnload } from './loader/systemjsHooks'; import { SystemJSWithLoaderHooks } from './loader/types'; -import { buildImportMap, resolveModulePath } from './loader/utils'; +import { buildImportMap, isHostedOnCDN, resolveModulePath } from './loader/utils'; import { importPluginModuleInSandbox } from './sandbox/sandbox_plugin_loader'; import { isFrontendSandboxSupported } from './sandbox/utils'; @@ -28,9 +28,13 @@ SystemJS.addImportMap({ imports }); const systemJSPrototype: SystemJSWithLoaderHooks = SystemJS.constructor.prototype; -// Monaco Editors reliance on RequireJS means we need to transform -// the content of the plugin code at runtime which can only be done with fetch/eval. -systemJSPrototype.shouldFetch = () => true; +// This instructs SystemJS to load a plugin using fetch and eval if it returns a truthy value, otherwise it will load the plugin using a script tag. +// We only want to fetch and eval plugins that are hosted on a CDN or are Angular plugins. +systemJSPrototype.shouldFetch = function (url) { + const pluginInfo = getPluginFromCache(url); + + return isHostedOnCDN(url) || Boolean(pluginInfo?.isAngular); +}; const originalImport = systemJSPrototype.import; // Hook Systemjs import to support plugins that only have a default export. @@ -68,7 +72,7 @@ export async function importPluginModule({ isAngular?: boolean; }): Promise { if (version) { - registerPluginInCache({ path, version }); + registerPluginInCache({ path, version, isAngular }); } const builtIn = builtInPlugins[path];