Chore: renames cache (#110877)

This commit is contained in:
Hugo Häggmark
2025-09-11 07:49:49 +02:00
committed by GitHub
parent bd207e5419
commit 22a41cdaa3
9 changed files with 63 additions and 62 deletions
@@ -7,7 +7,7 @@ import { Settings } from 'app/core/config';
import { importPanelPlugin } from 'app/features/plugins/importPanelPlugin';
import { StoreState, ThunkResult } from 'app/types/store';
import { invalidatePluginInCache } from '../../loader/cache';
import { clearPluginInfoInCache } from '../../loader/pluginInfoCache';
import {
getRemotePlugins,
getPluginErrors,
@@ -206,7 +206,7 @@ export const install = createAsyncThunk<
await updatePanels();
if (installType !== PluginStatus.INSTALL) {
invalidatePluginInCache(id);
clearPluginInfoInCache(id);
}
return { id, changes };
@@ -231,7 +231,7 @@ export const uninstall = createAsyncThunk<Update<CatalogPlugin, string>, string>
await uninstallPlugin(id);
await updatePanels();
invalidatePluginInCache(id);
clearPluginInfoInCache(id);
return {
id,
@@ -3,7 +3,7 @@ import { getResolvedLanguage } from '@grafana/i18n/internal';
import { config } from '@grafana/runtime';
import builtInPlugins from '../built_in_plugins';
import { registerPluginInCache } from '../loader/cache';
import { registerPluginInfoInCache } from '../loader/pluginInfoCache';
import { SystemJS } from '../loader/systemjs';
import { resolveModulePath } from '../loader/utils';
import { importPluginModuleInSandbox } from '../sandbox/sandboxPluginLoader';
@@ -22,7 +22,7 @@ export async function importPluginModule({
translations,
}: PluginImportInfo): Promise<System.Module> {
if (version) {
registerPluginInCache({ path, version, loadingStrategy });
registerPluginInfoInCache({ path, version, loadingStrategy });
}
// Add locales to i18n for a plugin if the feature toggle is enabled and the plugin has locales
@@ -2,3 +2,5 @@ export const SHARED_DEPENDENCY_PREFIX = 'package';
export const LOAD_PLUGIN_CSS_REGEX = /^plugins.+\.css$/i;
export const JS_CONTENT_TYPE_REGEX = /^(text|application)\/(x-)?javascript(;|$)/;
export const CACHE_INITIALISED_AT = Date.now();
export const PLUGIN_PATH_REGEX = /\/?public\/plugins\/([^\/]+)\//;
export const DECOUPLED_PLUGIN_REGEX = /\/?public\/app\/plugins\/(?:datasource|panel)\/([^\/]+)\//;
@@ -1,60 +1,61 @@
import { PluginLoadingStrategy } from '@grafana/data';
import {
registerPluginInCache,
invalidatePluginInCache,
resolveWithCache,
getPluginFromCache,
registerPluginInfoInCache,
clearPluginInfoInCache,
resolvePluginUrlWithCache,
getPluginInfoFromCache,
extractCacheKeyFromPath,
} from './cache';
} from './pluginInfoCache';
jest.mock('./constants', () => ({
...jest.requireActual('./constants'),
CACHE_INITIALISED_AT: 123456,
}));
describe('Cache Functions', () => {
describe('registerPluginInCache', () => {
it('should register a plugin in the cache', () => {
describe('registerPluginInfoInCache', () => {
it('should register pluginInfo in the cache', () => {
const plugin = { version: '1.0.0', loadingStrategy: PluginLoadingStrategy.script };
registerPluginInCache({ path: 'public/plugins/plugin1/module.js', ...plugin });
expect(getPluginFromCache('plugin1')).toEqual(plugin);
registerPluginInfoInCache({ path: 'public/plugins/plugin1/module.js', ...plugin });
expect(getPluginInfoFromCache('plugin1')).toEqual(plugin);
});
it('should not register a plugin if it already exists in the cache', () => {
it('should not register pluginInfo if it already exists in the cache', () => {
const path = 'public/plugins/plugin2/module.js';
const plugin = { path, version: '2.0.0', loadingStrategy: PluginLoadingStrategy.script };
registerPluginInCache(plugin);
registerPluginInfoInCache(plugin);
const plugin2 = { path, version: '2.5.0', loadingStrategy: PluginLoadingStrategy.script };
registerPluginInCache(plugin2);
expect(getPluginFromCache(path)?.version).toBe('2.0.0');
registerPluginInfoInCache(plugin2);
expect(getPluginInfoFromCache(path)?.version).toBe('2.0.0');
});
});
describe('invalidatePluginInCache', () => {
it('should invalidate a plugin in the cache', () => {
describe('clearPluginInfoInCache', () => {
it('should clear pluginInfo in the cache', () => {
const path = 'public/plugins/plugin2/module.js';
const plugin = { path, version: '3.0.0', loadingStrategy: PluginLoadingStrategy.script };
registerPluginInCache(plugin);
invalidatePluginInCache('plugin2');
expect(getPluginFromCache('plugin2')).toBeUndefined();
registerPluginInfoInCache(plugin);
clearPluginInfoInCache('plugin2');
expect(getPluginInfoFromCache('plugin2')).toBeUndefined();
});
it('should not throw an error if the plugin does not exist in the cache', () => {
expect(() => invalidatePluginInCache('nonExistentPlugin')).not.toThrow();
it('should not throw an error if the pluginInfo does not exist in the cache', () => {
expect(() => clearPluginInfoInCache('nonExistentPlugin')).not.toThrow();
});
});
describe('resolveWithCache', () => {
it('should resolve URL with timestamp cache bust parameter if plugin is not available in the cache', () => {
describe('resolvePluginUrlWithCache', () => {
it('should resolve URL with timestamp cache bust parameter if pluginInfo is not available in the cache', () => {
const url = 'http://localhost:3000/public/plugins/plugin4/module.js';
expect(resolveWithCache(url)).toContain('_cache=123456');
expect(resolvePluginUrlWithCache(url)).toContain('_cache=123456');
});
it('should resolve URL with plugin version as cache bust parameter if available', () => {
const url = 'http://localhost:3000/public/plugins/plugin5/module.js';
const plugin = { path: url, version: '5.0.0', loadingStrategy: PluginLoadingStrategy.script };
registerPluginInCache(plugin);
expect(resolveWithCache(url)).toContain('_cache=5.0.0');
registerPluginInfoInCache(plugin);
expect(resolvePluginUrlWithCache(url)).toContain('_cache=5.0.0');
});
});
@@ -84,15 +85,15 @@ describe('Cache Functions', () => {
});
});
describe('getPluginFromCache', () => {
it('should return plugin from cache if exists', () => {
describe('getPluginInfoFromCache', () => {
it('should return pluginInfo from cache if exists', () => {
const plugin = { version: '6.0.0', loadingStrategy: PluginLoadingStrategy.script };
registerPluginInCache({ path: 'public/plugins/plugin6/module.js', ...plugin });
expect(getPluginFromCache('plugin6')).toEqual(plugin);
registerPluginInfoInCache({ path: 'public/plugins/plugin6/module.js', ...plugin });
expect(getPluginInfoFromCache('plugin6')).toEqual(plugin);
});
it('should return undefined if plugin does not exist in cache', () => {
expect(getPluginFromCache('nonExistentPlugin')).toBeUndefined();
it('should return undefined if pluginInfo does not exist in cache', () => {
expect(getPluginInfoFromCache('nonExistentPlugin')).toBeUndefined();
});
});
});
@@ -2,19 +2,19 @@ import { PluginLoadingStrategy } from '@grafana/data';
import { clearPluginSettingsCache } from '../pluginSettings';
import { CACHE_INITIALISED_AT } from './constants';
import { CACHE_INITIALISED_AT, DECOUPLED_PLUGIN_REGEX, PLUGIN_PATH_REGEX } from './constants';
const cache: Record<string, CachedPlugin> = {};
const cache: Record<string, PluginInfo> = {};
type CacheablePlugin = {
type RegisterPluginInfo = {
path: string;
version: string;
loadingStrategy: PluginLoadingStrategy;
};
type CachedPlugin = Omit<CacheablePlugin, 'path'>;
type PluginInfo = Omit<RegisterPluginInfo, 'path'>;
export function registerPluginInCache({ path, version, loadingStrategy }: CacheablePlugin): void {
export function registerPluginInfoInCache({ path, version, loadingStrategy }: RegisterPluginInfo): void {
const key = extractCacheKeyFromPath(path);
if (key && !cache[key]) {
@@ -25,7 +25,7 @@ export function registerPluginInCache({ path, version, loadingStrategy }: Cachea
}
}
export function invalidatePluginInCache(pluginId: string): void {
export function clearPluginInfoInCache(pluginId: string): void {
const path = pluginId;
if (cache[path]) {
delete cache[path];
@@ -33,7 +33,7 @@ export function invalidatePluginInCache(pluginId: string): void {
clearPluginSettingsCache(pluginId);
}
export function resolveWithCache(url: string, defaultBust = CACHE_INITIALISED_AT): string {
export function resolvePluginUrlWithCache(url: string, defaultBust = CACHE_INITIALISED_AT): string {
const path = getCacheKey(url);
if (!path) {
return `${url}?_cache=${defaultBust}`;
@@ -43,7 +43,7 @@ export function resolveWithCache(url: string, defaultBust = CACHE_INITIALISED_AT
return `${url}?_cache=${bust}`;
}
export function getPluginFromCache(path: string): CachedPlugin | undefined {
export function getPluginInfoFromCache(path: string): PluginInfo | undefined {
const key = getCacheKey(path);
if (!key) {
return;
@@ -51,17 +51,15 @@ export function getPluginFromCache(path: string): CachedPlugin | undefined {
return cache[key];
}
export function extractCacheKeyFromPath(path: string) {
const regex = /\/?public\/plugins\/([^\/]+)\//;
const match = path.match(regex);
export function extractCacheKeyFromPath(path: string): string | null {
const match = path.match(PLUGIN_PATH_REGEX);
if (match) {
return match[1];
}
// Decoupled core plugins can be loaded by alternative paths
const decoupledPluginRegex = /\/?public\/app\/plugins\/(?:datasource|panel)\/([^\/]+)\//;
const decoupledPluginMatch = path.match(decoupledPluginRegex);
const decoupledPluginMatch = path.match(DECOUPLED_PLUGIN_REGEX);
if (decoupledPluginMatch) {
return decoupledPluginMatch[1];
@@ -70,8 +68,8 @@ export function extractCacheKeyFromPath(path: string) {
return null;
}
function getCacheKey(address: string): string | undefined {
const key = Object.keys(cache).find((key) => address.includes(key));
function getCacheKey(path: string): string | undefined {
const key = Object.keys(cache).find((key) => path.includes(key));
if (!key) {
return;
}
@@ -1,7 +1,7 @@
import { config } from '@grafana/runtime';
jest.mock('./cache', () => ({
resolveWithCache: (url: string) => `${url}?_cache=1234`,
jest.mock('./pluginInfoCache', () => ({
resolvePluginUrlWithCache: (url: string) => `${url}?_cache=1234`,
}));
import { server } from './pluginLoader.mock';
@@ -2,8 +2,8 @@ import { config } from '@grafana/runtime';
import { transformPluginSourceForCDN } from '../cdn/utils';
import { resolveWithCache } from './cache';
import { LOAD_PLUGIN_CSS_REGEX, JS_CONTENT_TYPE_REGEX, SHARED_DEPENDENCY_PREFIX } from './constants';
import { resolvePluginUrlWithCache } from './pluginInfoCache';
import { SystemJS } from './systemjs';
import { SystemJSWithLoaderHooks } from './types';
import { isHostedOnCDN } from './utils';
@@ -44,13 +44,13 @@ export function decorateSystemJSResolve(
(cleanedUrl.endsWith('.js') || cleanedUrl.endsWith('.css')) && !isHostedOnCDN(cleanedUrl);
// Add a cache query param for filesystem module.js requests
// CDN hosted plugins contain the version in the path so skip
return isFileSystemModule ? resolveWithCache(cleanedUrl) : cleanedUrl;
return isFileSystemModule ? resolvePluginUrlWithCache(cleanedUrl) : cleanedUrl;
} catch (err) {
// Provide fallback for plugins that use `loadPluginCss` to load theme styles.
if (LOAD_PLUGIN_CSS_REGEX.test(id)) {
const resolvedUrl = getLoadPluginCssUrl(id);
const url = originalResolve.apply(this, [resolvedUrl, parentUrl]);
return resolveWithCache(url);
return resolvePluginUrlWithCache(url);
}
console.warn(`SystemJS: failed to resolve '${id}'`);
return id;
+2 -2
View File
@@ -21,7 +21,7 @@ import {
} from './extensions/registry/setup';
import { importPluginModule } from './importer/importPluginModule';
import { pluginImporter } from './importer/pluginImporter';
import { getPluginFromCache } from './loader/cache';
import { getPluginInfoFromCache } from './loader/pluginInfoCache';
// SystemJS has to be imported before the sharedDependenciesMap
import { SystemJS } from './loader/systemjs';
// eslint-disable-next-line import/order
@@ -40,7 +40,7 @@ const systemJSPrototype: SystemJSWithLoaderHooks = SystemJS.constructor.prototyp
// it will load the plugin using a script tag. The logic that sets loadingStrategy comes from the backend.
// See: pkg/services/pluginsintegration/pluginassets/pluginassets.go
systemJSPrototype.shouldFetch = function (url) {
const pluginInfo = getPluginFromCache(url);
const pluginInfo = getPluginInfoFromCache(url);
const jsTypeRegEx = /^[^#?]+\.(js)([?#].*)?$/;
if (!jsTypeRegEx.test(url)) {
@@ -2,7 +2,7 @@ import { PluginType, patchArrayVectorProrotypeMethods } from '@grafana/data';
import { config } from '@grafana/runtime';
import { transformPluginSourceForCDN } from '../cdn/utils';
import { resolveWithCache } from '../loader/cache';
import { resolvePluginUrlWithCache } from '../loader/pluginInfoCache';
import { isHostedOnCDN, resolveModulePath } from '../loader/utils';
import { SandboxEnvironment, SandboxPluginMeta } from './types';
@@ -49,7 +49,7 @@ export async function loadScriptIntoSandbox(url: string, sandboxEnv: SandboxEnvi
export async function getPluginCode(meta: SandboxPluginMeta): Promise<string> {
if (isHostedOnCDN(meta.module)) {
// Load plugin from CDN, no need for "resolveWithCache" as CDN URLs already include the version
// Load plugin from CDN, no need for "resolvePluginUrlWithCache" as CDN URLs already include the version
const url = meta.module;
const response = await fetch(url);
@@ -67,9 +67,9 @@ export async function getPluginCode(meta: SandboxPluginMeta): Promise<string> {
return pluginCode;
} else {
let modulePath = resolveModulePath(meta.module);
// resolveWithCache will append a query parameter with its version
// resolvePluginUrlWithCache will append a query parameter with its version
// to ensure correct cached version is served for local plugins
const pluginCodeUrl = resolveWithCache(modulePath);
const pluginCodeUrl = resolvePluginUrlWithCache(modulePath);
const response = await fetch(pluginCodeUrl);
let pluginCode = await response.text();