Skip to content

Commit 7985aa1

Browse files
authored
Performance/Webpack: Introduces more aggressive code-splitting and other perf improvements (grafana#18544)
* Performance/Webpack: Introduces more aggressive code-splitting and other perf improvements - Introduces dynamic imports for built-in plugins - Uses dynamic imports for various packages (rst2html, brace) - Introduces route-based dynamic imports - Splits angular and moment into separate bundles
1 parent 409874b commit 7985aa1

File tree

34 files changed

+289
-200
lines changed

34 files changed

+289
-200
lines changed

.babelrc

+5-2
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,11 @@
33
[
44
"@babel/preset-env",
55
{
6-
"targets": { "browsers": "last 3 versions" },
7-
"useBuiltIns": "entry"
6+
"targets": {
7+
"browsers": "last 3 versions"
8+
},
9+
"useBuiltIns": "entry",
10+
"modules": "false",
811
}
912
]
1013
]

.gitignore

+3
Original file line numberDiff line numberDiff line change
@@ -94,3 +94,6 @@ theOutput/
9494

9595
# Ignore go local build dependencies
9696
/scripts/go/bin/**
97+
98+
# Ignore compilation stats from `yarn stats`
99+
compilation-stats.json

package.json

+1
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,7 @@
147147
"start:hot": "grafana-toolkit core:start --hot --watchTheme",
148148
"start:ignoreTheme": "grafana-toolkit core:start --hot",
149149
"start:noTsCheck": "grafana-toolkit core:start --noTsCheck",
150+
"stats": "webpack --mode production --config scripts/webpack/webpack.prod.js --profile --json > compilation-stats.json",
150151
"watch": "yarn start -d watch,start core:start --watchTheme ",
151152
"build": "grunt build",
152153
"test": "grunt test",

packages/grafana-data/src/utils/fieldReducer.test.ts

+3-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
1+
import difference from 'lodash/difference';
2+
13
import { fieldReducers, ReducerID, reduceField } from './fieldReducer';
24

3-
import _ from 'lodash';
45
import { Field, FieldType } from '../types/index';
56
import { MutableDataFrame } from './dataFrameHelper';
67
import { ArrayVector } from './vector';
@@ -42,7 +43,7 @@ describe('Stats Calculators', () => {
4243
expect(stats.length).toBe(2);
4344

4445
const found = stats.map(v => v.id);
45-
const notFound = _.difference(names, found);
46+
const notFound = difference(names, found);
4647
expect(notFound.length).toBe(2);
4748

4849
expect(notFound[0]).toBe('not a stat');

packages/grafana-data/src/utils/rangeutil.ts

+4-4
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
// @ts-ignore
2-
import _ from 'lodash';
1+
import each from 'lodash/each';
2+
import groupBy from 'lodash/groupBy';
33

44
import { RawTimeRange } from '../types/time';
55

@@ -64,12 +64,12 @@ const rangeOptions = [
6464
const absoluteFormat = 'YYYY-MM-DD HH:mm:ss';
6565

6666
const rangeIndex: any = {};
67-
_.each(rangeOptions, (frame: any) => {
67+
each(rangeOptions, (frame: any) => {
6868
rangeIndex[frame.from + ' to ' + frame.to] = frame;
6969
});
7070

7171
export function getRelativeTimesList(timepickerSettings: any, currentDisplay: any) {
72-
const groups = _.groupBy(rangeOptions, (option: any) => {
72+
const groups = groupBy(rangeOptions, (option: any) => {
7373
option.active = option.display === currentDisplay;
7474
return option.section;
7575
});

packages/grafana-toolkit/src/config/webpack.plugin.config.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -183,7 +183,7 @@ export const getWebpackConfig: WebpackConfigurationGetter = options => {
183183
{
184184
loader: 'babel-loader',
185185
options: {
186-
presets: ['@babel/preset-env'],
186+
presets: ['@babel/preset-env', { modules: false }],
187187
plugins: ['angularjs-annotate'],
188188
},
189189
},

packages/grafana-ui/src/components/Graph/GraphWithLegend.tsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
// Libraries
2-
import _ from 'lodash';
2+
33
import React from 'react';
44
import { css } from 'emotion';
55
import { GraphSeriesValue, AbsoluteTimeRange } from '@grafana/data';

public/app/core/components/Footer/Footer.tsx

+5-5
Original file line numberDiff line numberDiff line change
@@ -16,22 +16,22 @@ export const Footer: FC<Props> = React.memo(
1616
<div className="text-center">
1717
<ul>
1818
<li>
19-
<a href="http://docs.grafana.org" target="_blank">
19+
<a href="http://docs.grafana.org" target="_blank" rel="noopener">
2020
<i className="fa fa-file-code-o" /> Docs
2121
</a>
2222
</li>
2323
<li>
24-
<a href="https://grafana.com/services/support" target="_blank">
24+
<a href="https://grafana.com/services/support" target="_blank" rel="noopener">
2525
<i className="fa fa-support" /> Support Plans
2626
</a>
2727
</li>
2828
<li>
29-
<a href="https://community.grafana.com/" target="_blank">
29+
<a href="https://community.grafana.com/" target="_blank" rel="noopener">
3030
<i className="fa fa-comments-o" /> Community
3131
</a>
3232
</li>
3333
<li>
34-
<a href="https://grafana.com" target="_blank">
34+
<a href="https://grafana.com" target="_blank" rel="noopener">
3535
{appName}
3636
</a>{' '}
3737
<span>
@@ -41,7 +41,7 @@ export const Footer: FC<Props> = React.memo(
4141
{newGrafanaVersionExists && (
4242
<li>
4343
<Tooltip placement="auto" content={newGrafanaVersion}>
44-
<a href="https://grafana.com/get" target="_blank">
44+
<a href="https://grafana.com/get" target="_blank" rel="noopener">
4545
New version available!
4646
</a>
4747
</Tooltip>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
declare module 'brace/*' {
2+
let brace: any;
3+
export default brace;
4+
}

public/app/core/components/code_editor/code_editor.ts

+18-15
Original file line numberDiff line numberDiff line change
@@ -30,20 +30,6 @@
3030

3131
import coreModule from 'app/core/core_module';
3232
import config from 'app/core/config';
33-
import ace from 'brace';
34-
import './theme-grafana-dark';
35-
import 'brace/ext/language_tools';
36-
import 'brace/theme/textmate';
37-
import 'brace/mode/text';
38-
import 'brace/snippets/text';
39-
import 'brace/mode/sql';
40-
import 'brace/snippets/sql';
41-
import 'brace/mode/sqlserver';
42-
import 'brace/snippets/sqlserver';
43-
import 'brace/mode/markdown';
44-
import 'brace/snippets/markdown';
45-
import 'brace/mode/json';
46-
import 'brace/snippets/json';
4733

4834
const DEFAULT_THEME_DARK = 'ace/theme/grafana-dark';
4935
const DEFAULT_THEME_LIGHT = 'ace/theme/textmate';
@@ -55,7 +41,7 @@ const DEFAULT_SNIPPETS = true;
5541

5642
const editorTemplate = `<div></div>`;
5743

58-
function link(scope: any, elem: any, attrs: any) {
44+
async function link(scope: any, elem: any, attrs: any) {
5945
// Options
6046
const langMode = attrs.mode || DEFAULT_MODE;
6147
const maxLines = attrs.maxLines || DEFAULT_MAX_LINES;
@@ -66,6 +52,23 @@ function link(scope: any, elem: any, attrs: any) {
6652

6753
// Initialize editor
6854
const aceElem = elem.get(0);
55+
const { default: ace } = await import(/* webpackChunkName: "brace" */ 'brace');
56+
await import('brace/ext/language_tools');
57+
await import('brace/theme/textmate');
58+
await import('brace/mode/text');
59+
await import('brace/snippets/text');
60+
await import('brace/mode/sql');
61+
await import('brace/snippets/sql');
62+
await import('brace/mode/sqlserver');
63+
await import('brace/snippets/sqlserver');
64+
await import('brace/mode/markdown');
65+
await import('brace/snippets/markdown');
66+
await import('brace/mode/json');
67+
await import('brace/snippets/json');
68+
69+
// @ts-ignore
70+
await import('./theme-grafana-dark');
71+
6972
const codeEditor = ace.edit(aceElem);
7073
const editorSession = codeEditor.getSession();
7174

public/app/features/admin/__snapshots__/ServerStats.test.tsx.snap

+4
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,7 @@ exports[`ServerStats Should render table with stats 1`] = `
160160
<li>
161161
<a
162162
href="http://docs.grafana.org"
163+
rel="noopener"
163164
target="_blank"
164165
>
165166
<i
@@ -171,6 +172,7 @@ exports[`ServerStats Should render table with stats 1`] = `
171172
<li>
172173
<a
173174
href="https://grafana.com/services/support"
175+
rel="noopener"
174176
target="_blank"
175177
>
176178
<i
@@ -182,6 +184,7 @@ exports[`ServerStats Should render table with stats 1`] = `
182184
<li>
183185
<a
184186
href="https://community.grafana.com/"
187+
rel="noopener"
185188
target="_blank"
186189
>
187190
<i
@@ -193,6 +196,7 @@ exports[`ServerStats Should render table with stats 1`] = `
193196
<li>
194197
<a
195198
href="https://grafana.com"
199+
rel="noopener"
196200
target="_blank"
197201
>
198202
Grafana

public/app/features/datasources/NewDataSourcePage.tsx

+2
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,7 @@ class NewDataSourcePage extends PureComponent<Props> {
131131
className="btn btn-inverse"
132132
href="https://grafana.com/plugins?type=datasource&utm_source=new-data-source"
133133
target="_blank"
134+
rel="noopener"
134135
>
135136
Find more data source plugins on grafana.com
136137
</a>
@@ -198,6 +199,7 @@ const DataSourceTypeCard: FC<DataSourceTypeCardProps> = props => {
198199
className="btn btn-inverse"
199200
href={`${learnMoreLink}?utm_source=grafana_add_ds`}
200201
target="_blank"
202+
rel="noopener"
201203
onClick={onLearnMoreClick}
202204
>
203205
Learn more <i className="fa fa-external-link add-datasource-item-actions__btn-icon" />

public/app/features/explore/NoDataSourceCallToAction.tsx

+1
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ export const NoDataSourceCallToAction = () => {
1414
<a
1515
href="http://docs.grafana.org/administration/provisioning/#datasources?utm_source=explore"
1616
target="_blank"
17+
rel="noopener"
1718
className="text-link"
1819
>
1920
Learn more

public/app/features/explore/QueryRow.tsx

+4-3
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
// Libraries
22
import React, { PureComponent } from 'react';
3-
import _ from 'lodash';
3+
import debounce from 'lodash/debounce';
4+
import has from 'lodash/has';
45
import { hot } from 'react-hot-loader';
56
// @ts-ignore
67
import { connect } from 'react-redux';
@@ -97,7 +98,7 @@ export class QueryRow extends PureComponent<QueryRowProps, QueryRowState> {
9798
this.setState({ textEditModeEnabled: !this.state.textEditModeEnabled });
9899
};
99100

100-
updateLogsHighlights = _.debounce((value: DataQuery) => {
101+
updateLogsHighlights = debounce((value: DataQuery) => {
101102
const { datasourceInstance } = this.props;
102103
if (datasourceInstance.getHighlighterExpression) {
103104
const { exploreId } = this.props;
@@ -120,7 +121,7 @@ export class QueryRow extends PureComponent<QueryRowProps, QueryRowState> {
120121
mode,
121122
} = this.props;
122123
const canToggleEditorModes =
123-
mode === ExploreMode.Metrics && _.has(datasourceInstance, 'components.QueryCtrl.prototype.toggleEditorMode');
124+
mode === ExploreMode.Metrics && has(datasourceInstance, 'components.QueryCtrl.prototype.toggleEditorMode');
124125
const queryErrors = queryResponse.error && queryResponse.error.refId === query.refId ? [queryResponse.error] : [];
125126
let QueryField;
126127

public/app/features/plugins/PluginPage.tsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -278,7 +278,7 @@ class PluginPage extends PureComponent<Props, State> {
278278
{info.links.map(link => {
279279
return (
280280
<li key={link.url}>
281-
<a href={link.url} className="external-link" target="_blank">
281+
<a href={link.url} className="external-link" target="_blank" rel="noopener">
282282
{link.name}
283283
</a>
284284
</li>

public/app/features/plugins/built_in_plugins.ts

+34-18
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,36 @@
1-
import * as graphitePlugin from 'app/plugins/datasource/graphite/module';
2-
import * as cloudwatchPlugin from 'app/plugins/datasource/cloudwatch/module';
3-
import * as dashboardDSPlugin from 'app/plugins/datasource/dashboard/module';
4-
import * as elasticsearchPlugin from 'app/plugins/datasource/elasticsearch/module';
5-
import * as opentsdbPlugin from 'app/plugins/datasource/opentsdb/module';
6-
import * as grafanaPlugin from 'app/plugins/datasource/grafana/module';
7-
import * as influxdbPlugin from 'app/plugins/datasource/influxdb/module';
8-
import * as lokiPlugin from 'app/plugins/datasource/loki/module';
9-
import * as mixedPlugin from 'app/plugins/datasource/mixed/module';
10-
import * as mysqlPlugin from 'app/plugins/datasource/mysql/module';
11-
import * as postgresPlugin from 'app/plugins/datasource/postgres/module';
12-
import * as prometheusPlugin from 'app/plugins/datasource/prometheus/module';
13-
import * as mssqlPlugin from 'app/plugins/datasource/mssql/module';
14-
import * as testDataDSPlugin from 'app/plugins/datasource/testdata/module';
15-
import * as inputDatasourcePlugin from 'app/plugins/datasource/input/module';
16-
import * as stackdriverPlugin from 'app/plugins/datasource/stackdriver/module';
17-
import * as azureMonitorPlugin from 'app/plugins/datasource/grafana-azure-monitor-datasource/module';
1+
const graphitePlugin = async () =>
2+
await import(/* webpackChunkName: "graphitePlugin" */ 'app/plugins/datasource/graphite/module');
3+
const cloudwatchPlugin = async () =>
4+
await import(/* webpackChunkName: "cloudwatchPlugin" */ 'app/plugins/datasource/cloudwatch/module');
5+
const dashboardDSPlugin = async () =>
6+
await import(/* webpackChunkName "dashboardDSPlugin" */ 'app/plugins/datasource/dashboard/module');
7+
const elasticsearchPlugin = async () =>
8+
await import(/* webpackChunkName: "elasticsearchPlugin" */ 'app/plugins/datasource/elasticsearch/module');
9+
const opentsdbPlugin = async () =>
10+
await import(/* webpackChunkName: "opentsdbPlugin" */ 'app/plugins/datasource/opentsdb/module');
11+
const grafanaPlugin = async () =>
12+
await import(/* webpackChunkName: "grafanaPlugin" */ 'app/plugins/datasource/grafana/module');
13+
const influxdbPlugin = async () =>
14+
await import(/* webpackChunkName: "influxdbPlugin" */ 'app/plugins/datasource/influxdb/module');
15+
const lokiPlugin = async () => await import(/* webpackChunkName: "lokiPlugin" */ 'app/plugins/datasource/loki/module');
16+
const mixedPlugin = async () =>
17+
await import(/* webpackChunkName: "mixedPlugin" */ 'app/plugins/datasource/mixed/module');
18+
const mysqlPlugin = async () =>
19+
await import(/* webpackChunkName: "mysqlPlugin" */ 'app/plugins/datasource/mysql/module');
20+
const postgresPlugin = async () =>
21+
await import(/* webpackChunkName: "postgresPlugin" */ 'app/plugins/datasource/postgres/module');
22+
const prometheusPlugin = async () =>
23+
await import(/* webpackChunkName: "prometheusPlugin" */ 'app/plugins/datasource/prometheus/module');
24+
const mssqlPlugin = async () =>
25+
await import(/* webpackChunkName: "mssqlPlugin" */ 'app/plugins/datasource/mssql/module');
26+
const testDataDSPlugin = async () =>
27+
await import(/* webpackChunkName: "testDataDSPlugin" */ 'app/plugins/datasource/testdata/module');
28+
const inputDatasourcePlugin = async () =>
29+
await import(/* webpackChunkName: "inputDatasourcePlugin" */ 'app/plugins/datasource/input/module');
30+
const stackdriverPlugin = async () =>
31+
await import(/* webpackChunkName: "stackdriverPlugin" */ 'app/plugins/datasource/stackdriver/module');
32+
const azureMonitorPlugin = async () =>
33+
await import(/* webpackChunkName: "azureMonitorPlugin" */ 'app/plugins/datasource/grafana-azure-monitor-datasource/module');
1834

1935
import * as textPanel from 'app/plugins/panel/text/module';
2036
import * as text2Panel from 'app/plugins/panel/text2/module';
@@ -35,7 +51,7 @@ import * as pieChartPanel from 'app/plugins/panel/piechart/module';
3551
import * as barGaugePanel from 'app/plugins/panel/bargauge/module';
3652
import * as logsPanel from 'app/plugins/panel/logs/module';
3753

38-
import * as exampleApp from 'app/plugins/app/example-app/module';
54+
const exampleApp = async () => await import(/* webpackChunkName: "exampleApp" */ 'app/plugins/app/example-app/module');
3955

4056
const builtInPlugins: any = {
4157
'app/plugins/datasource/graphite/module': graphitePlugin,

public/app/features/plugins/plugin_loader.ts

+7-2
Original file line numberDiff line numberDiff line change
@@ -162,10 +162,15 @@ for (const flotDep of flotDeps) {
162162
exposeToPlugin(flotDep, { fakeDep: 1 });
163163
}
164164

165-
export function importPluginModule(path: string): Promise<any> {
165+
export async function importPluginModule(path: string): Promise<any> {
166166
const builtIn = builtInPlugins[path];
167167
if (builtIn) {
168-
return Promise.resolve(builtIn);
168+
// for handling dynamic imports
169+
if (typeof builtIn === 'function') {
170+
return await builtIn();
171+
} else {
172+
return Promise.resolve(builtIn);
173+
}
169174
}
170175
return grafanaRuntime.SystemJS.import(path);
171176
}

public/app/features/users/UsersActionBar.tsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ export class UsersActionBar extends PureComponent<Props> {
6868
</a>
6969
)}
7070
{externalUserMngLinkUrl && (
71-
<a className="btn btn-primary" href={externalUserMngLinkUrl} target="_blank">
71+
<a className="btn btn-primary" href={externalUserMngLinkUrl} target="_blank" rel="noopener">
7272
<i className="fa fa-external-link-square" /> {externalUserMngLinkName}
7373
</a>
7474
)}

public/app/features/users/__snapshots__/UsersActionBar.test.tsx.snap

+1
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,7 @@ exports[`Render should show external user management button 1`] = `
8686
<a
8787
className="btn btn-primary"
8888
href="some/url"
89+
rel="noopener"
8990
target="_blank"
9091
>
9192
<i

0 commit comments

Comments
 (0)