Tempo: Reduce initial bundle size (#97084)

* feat(grafana-plugin-configs): externalise rxjs/operators

* feat(plugin-configs): add bundle analyser behind stats env var

* chore(tempo): add a build:stats script for bundle analysis

* feat(tempo): make query and config editors default export

* feat(tempo): lazy load query and config editors

* feat(tempo): lazy cheat sheet

* chore(tempo): remove webpackchunkname hints
This commit is contained in:
Jack Westbrook 2024-12-05 12:59:43 +01:00 committed by GitHub
parent 53cdbd8a2d
commit 20e619e445
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
8 changed files with 79 additions and 22 deletions

View File

@ -10,6 +10,7 @@
"@grafana/tsconfig": "^2.0.0", "@grafana/tsconfig": "^2.0.0",
"@swc/core": "1.9.3", "@swc/core": "1.9.3",
"@types/eslint": "9.6.1", "@types/eslint": "9.6.1",
"@types/webpack-bundle-analyzer": "^4.7.0",
"copy-webpack-plugin": "12.0.2", "copy-webpack-plugin": "12.0.2",
"eslint": "9.14.0", "eslint": "9.14.0",
"eslint-webpack-plugin": "4.2.0", "eslint-webpack-plugin": "4.2.0",
@ -18,7 +19,8 @@
"replace-in-file-webpack-plugin": "1.0.6", "replace-in-file-webpack-plugin": "1.0.6",
"swc-loader": "0.2.6", "swc-loader": "0.2.6",
"typescript": "5.5.4", "typescript": "5.5.4",
"webpack": "5.95.0" "webpack": "5.95.0",
"webpack-bundle-analyzer": "^4.10.2"
}, },
"packageManager": "yarn@4.5.3" "packageManager": "yarn@4.5.3"
} }

View File

@ -5,6 +5,7 @@ import path from 'path';
// @ts-expect-error - there are no types for this package // @ts-expect-error - there are no types for this package
import ReplaceInFileWebpackPlugin from 'replace-in-file-webpack-plugin'; import ReplaceInFileWebpackPlugin from 'replace-in-file-webpack-plugin';
import { Configuration } from 'webpack'; import { Configuration } from 'webpack';
import { BundleAnalyzerPlugin } from 'webpack-bundle-analyzer';
import { DIST_DIR } from './constants'; import { DIST_DIR } from './constants';
import { getPackageJson, getPluginJson, getEntries, hasLicense } from './utils'; import { getPackageJson, getPluginJson, getEntries, hasLicense } from './utils';
@ -62,6 +63,7 @@ const config = async (env: Record<string, unknown>): Promise<Configuration> => {
'react-redux', 'react-redux',
'redux', 'redux',
'rxjs', 'rxjs',
'rxjs/operators',
'react-router', 'react-router',
'd3', 'd3',
'angular', 'angular',
@ -230,6 +232,11 @@ const config = async (env: Record<string, unknown>): Promise<Configuration> => {
}, },
}; };
if (env.stats) {
baseConfig.stats = 'normal';
baseConfig.plugins?.push(new BundleAnalyzerPlugin());
}
return baseConfig; return baseConfig;
}; };

View File

@ -178,4 +178,6 @@ class TempoQueryFieldComponent extends PureComponent<Props, State> {
} }
} }
export const TempoQueryField = withTheme2(TempoQueryFieldComponent); const TempoQueryField = withTheme2(TempoQueryFieldComponent);
export default TempoQueryField;

View File

@ -26,9 +26,9 @@ import { ServiceGraphSettings } from './ServiceGraphSettings';
import { StreamingSection } from './StreamingSection'; import { StreamingSection } from './StreamingSection';
import { TraceQLSearchSettings } from './TraceQLSearchSettings'; import { TraceQLSearchSettings } from './TraceQLSearchSettings';
export type Props = DataSourcePluginOptionsEditorProps; export type ConfigEditorProps = DataSourcePluginOptionsEditorProps;
export const ConfigEditor = ({ options, onOptionsChange }: Props) => { const ConfigEditor = ({ options, onOptionsChange }: ConfigEditorProps) => {
const styles = useStyles2(getStyles); const styles = useStyles2(getStyles);
return ( return (
@ -130,3 +130,5 @@ const getStyles = (theme: GrafanaTheme2) => ({
maxWidth: '900px', maxWidth: '900px',
}), }),
}); });
export default ConfigEditor;

View File

@ -1,17 +0,0 @@
import { DataSourcePlugin, DashboardLoadedEvent } from '@grafana/data';
import { getAppEvents } from '@grafana/runtime';
import CheatSheet from './CheatSheet';
import { TempoQueryField } from './QueryField';
import { ConfigEditor } from './configuration/ConfigEditor';
import { TempoDatasource } from './datasource';
import { onDashboardLoadedHandler } from './tracking';
import { TempoQuery } from './types';
export const plugin = new DataSourcePlugin(TempoDatasource)
.setQueryEditor(TempoQueryField)
.setConfigEditor(ConfigEditor)
.setQueryEditorHelp(CheatSheet);
// Subscribe to on dashboard loaded event so that we can track plugin adoption
getAppEvents().subscribe<DashboardLoadedEvent<TempoQuery>>(DashboardLoadedEvent, onDashboardLoadedHandler);

View File

@ -0,0 +1,47 @@
import { lazy, Suspense } from 'react';
import { DataSourcePlugin, DashboardLoadedEvent, type QueryEditorProps } from '@grafana/data';
import { getAppEvents } from '@grafana/runtime';
import { LoadingPlaceholder } from '@grafana/ui';
import type { ConfigEditorProps } from './configuration/ConfigEditor';
import { TempoDatasource } from './datasource';
import { onDashboardLoadedHandler } from './tracking';
import type { TempoQuery } from './types';
// Lazy load the QueryField and ConfigEditor components to reduce the size of the initial bundle
const TempoQueryFieldLazy = lazy(() => import('./QueryField'));
const ConfigEditorLazy = lazy(() => import('./configuration/ConfigEditor'));
const CheatSheetLazy = lazy(() => import('./CheatSheet'));
function TempoQueryField(props: QueryEditorProps<TempoDatasource, TempoQuery>) {
return (
<Suspense fallback={<LoadingPlaceholder text={'Loading editor'} />}>
<TempoQueryFieldLazy {...props} />
</Suspense>
);
}
function ConfigEditor(props: ConfigEditorProps) {
return (
<Suspense fallback={<LoadingPlaceholder text={'Loading editor'} />}>
<ConfigEditorLazy {...props} />
</Suspense>
);
}
function CheatSheet() {
return (
<Suspense fallback={null}>
<CheatSheetLazy />
</Suspense>
);
}
export const plugin = new DataSourcePlugin(TempoDatasource)
.setQueryEditor(TempoQueryField)
.setConfigEditor(ConfigEditor)
.setQueryEditorHelp(CheatSheet);
// Subscribe to on dashboard loaded event so that we can track plugin adoption
getAppEvents().subscribe<DashboardLoadedEvent<TempoQuery>>(DashboardLoadedEvent, onDashboardLoadedHandler);

View File

@ -63,6 +63,7 @@
}, },
"scripts": { "scripts": {
"build": "webpack -c ./webpack.config.ts --env production", "build": "webpack -c ./webpack.config.ts --env production",
"build:stats": "yarn build --env stats --profile --json=compilation-stats.json",
"build:commit": "webpack -c ./webpack.config.ts --env production --env commit=$(git rev-parse --short HEAD)", "build:commit": "webpack -c ./webpack.config.ts --env production --env commit=$(git rev-parse --short HEAD)",
"dev": "webpack -w -c ./webpack.config.ts --env development" "dev": "webpack -w -c ./webpack.config.ts --env development"
}, },

View File

@ -3563,6 +3563,7 @@ __metadata:
"@grafana/tsconfig": "npm:^2.0.0" "@grafana/tsconfig": "npm:^2.0.0"
"@swc/core": "npm:1.9.3" "@swc/core": "npm:1.9.3"
"@types/eslint": "npm:9.6.1" "@types/eslint": "npm:9.6.1"
"@types/webpack-bundle-analyzer": "npm:^4.7.0"
copy-webpack-plugin: "npm:12.0.2" copy-webpack-plugin: "npm:12.0.2"
eslint: "npm:9.14.0" eslint: "npm:9.14.0"
eslint-webpack-plugin: "npm:4.2.0" eslint-webpack-plugin: "npm:4.2.0"
@ -3573,6 +3574,7 @@ __metadata:
tslib: "npm:2.7.0" tslib: "npm:2.7.0"
typescript: "npm:5.5.4" typescript: "npm:5.5.4"
webpack: "npm:5.95.0" webpack: "npm:5.95.0"
webpack-bundle-analyzer: "npm:^4.10.2"
languageName: unknown languageName: unknown
linkType: soft linkType: soft
@ -9840,6 +9842,17 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"@types/webpack-bundle-analyzer@npm:^4.7.0":
version: 4.7.0
resolution: "@types/webpack-bundle-analyzer@npm:4.7.0"
dependencies:
"@types/node": "npm:*"
tapable: "npm:^2.2.0"
webpack: "npm:^5"
checksum: 10/2d9a2d4e26b1239623df97caceddd37a14c258623bccf27aca9da65b963cad33fdbfdc3a4770a58dbd2f9e6f591f62990616938aa52edf58aae3f6166c0045c1
languageName: node
linkType: hard
"@types/webpack-env@npm:^1.18.4": "@types/webpack-env@npm:^1.18.4":
version: 1.18.5 version: 1.18.5
resolution: "@types/webpack-env@npm:1.18.5" resolution: "@types/webpack-env@npm:1.18.5"
@ -29940,7 +29953,7 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"webpack-bundle-analyzer@npm:4.10.2": "webpack-bundle-analyzer@npm:4.10.2, webpack-bundle-analyzer@npm:^4.10.2":
version: 4.10.2 version: 4.10.2
resolution: "webpack-bundle-analyzer@npm:4.10.2" resolution: "webpack-bundle-analyzer@npm:4.10.2"
dependencies: dependencies: