From be0857fa8fcb8f278f84048e12b5ef35879cd93a Mon Sep 17 00:00:00 2001 From: Erik Sundell Date: Wed, 19 Nov 2025 15:42:27 +0100 Subject: [PATCH] Plugins: Pass build mode to frontend (#114092) * pass build mode to frontend * set buildMode build time using shared plugin webpack conf --- packages/grafana-data/src/types/config.ts | 1 + .../grafana-plugin-configs/webpack.config.ts | 34 ++++++++++++++++++- pkg/api/frontendsettings.go | 1 + pkg/plugins/models.go | 1 + pkg/plugins/plugins.go | 3 ++ 5 files changed, 39 insertions(+), 1 deletion(-) diff --git a/packages/grafana-data/src/types/config.ts b/packages/grafana-data/src/types/config.ts index bac0e9d322d..bb7fe29a655 100644 --- a/packages/grafana-data/src/types/config.ts +++ b/packages/grafana-data/src/types/config.ts @@ -37,6 +37,7 @@ export type AppPluginConfig = { dependencies: PluginDependencies; extensions: PluginExtensions; moduleHash?: string; + buildMode?: string; }; export type PreinstalledPlugin = { diff --git a/packages/grafana-plugin-configs/webpack.config.ts b/packages/grafana-plugin-configs/webpack.config.ts index 7cc76782449..6f2846b5a97 100644 --- a/packages/grafana-plugin-configs/webpack.config.ts +++ b/packages/grafana-plugin-configs/webpack.config.ts @@ -4,7 +4,7 @@ import ForkTsCheckerWebpackPlugin from 'fork-ts-checker-webpack-plugin'; import path from 'path'; import ReplaceInFileWebpackPlugin from 'replace-in-file-webpack-plugin'; import TerserPlugin from 'terser-webpack-plugin'; -import webpack, { type Configuration } from 'webpack'; +import webpack, { type Configuration, type Compiler } from 'webpack'; import { BundleAnalyzerPlugin } from 'webpack-bundle-analyzer'; import VirtualModulesPlugin from 'webpack-virtual-modules'; @@ -31,6 +31,36 @@ function skipFiles(f: string): boolean { return true; } +class BuildModeWebpackPlugin { + apply(compiler: Compiler) { + compiler.hooks.compilation.tap('BuildModeWebpackPlugin', (compilation) => { + compilation.hooks.processAssets.tap( + { + name: 'BuildModeWebpackPlugin', + stage: webpack.Compilation.PROCESS_ASSETS_STAGE_ADDITIONS, + }, + async () => { + const assets = compilation.getAssets(); + for (const asset of assets) { + if (asset.name.endsWith('plugin.json')) { + const pluginJsonString = asset.source.source().toString(); + const pluginJsonWithBuildMode = JSON.stringify( + { + ...JSON.parse(pluginJsonString), + buildMode: compilation.options.mode, + }, + null, + 4 + ); + compilation.updateAsset(asset.name, new webpack.sources.RawSource(pluginJsonWithBuildMode)); + } + } + } + ); + }); + } +} + export type Env = { [key: string]: true | string | Env; }; @@ -253,6 +283,8 @@ const config = async (env: Env): Promise => { ], }, ]), + // Add buildMode to plugin.json + new BuildModeWebpackPlugin(), ...(env.development ? [ new ForkTsCheckerWebpackPlugin({ diff --git a/pkg/api/frontendsettings.go b/pkg/api/frontendsettings.go index 2895fd14cf7..3554eb84244 100644 --- a/pkg/api/frontendsettings.go +++ b/pkg/api/frontendsettings.go @@ -637,6 +637,7 @@ func (hs *HTTPServer) newAppDTO(ctx context.Context, plugin pluginstore.Plugin, Dependencies: plugin.Dependencies, ModuleHash: hs.pluginAssets.ModuleHash(ctx, plugin), Translations: plugin.Translations, + BuildMode: plugin.BuildMode, } if settings.Enabled { diff --git a/pkg/plugins/models.go b/pkg/plugins/models.go index e5f3a2c93f2..e546d23b95b 100644 --- a/pkg/plugins/models.go +++ b/pkg/plugins/models.go @@ -339,6 +339,7 @@ type AppDTO struct { Dependencies Dependencies `json:"dependencies"` ModuleHash string `json:"moduleHash,omitempty"` Translations map[string]string `json:"translations,omitempty"` + BuildMode string `json:"buildMode,omitempty"` } const ( diff --git a/pkg/plugins/plugins.go b/pkg/plugins/plugins.go index 16dd8d946f8..2c394dcc632 100644 --- a/pkg/plugins/plugins.go +++ b/pkg/plugins/plugins.go @@ -133,6 +133,9 @@ type JSONData struct { // List of languages supported by the plugin Languages []string `json:"languages,omitempty"` + + // Build mode of the plugin (set automatically at build time) + BuildMode string `json:"buildMode,omitempty"` } func ReadPluginJSON(reader io.Reader) (JSONData, error) {