Skip to content

Commit

Permalink
[APM] Reduce initially loaded bundles by 98% (#191658)
Browse files Browse the repository at this point in the history
## 📓 Summary

Closes #191600 

Moving on invocation site the dynamic import to instantiate the apm
locator and registering the embeddable removed the async import on the
biggest APM js chunks.

In practice, we passed from loading ~900kb of JS to ~10kb, with a total
reduction of about **~16%** of all the code loaded by Kibana for any
page.

There is also deeper code splitting for the APM routes to only load
specific features when required on while using the APM app.

| Before | After |
|--------|--------|
| <img width="622" alt="Screenshot 2024-08-28 at 17 58 59"
src="https://github.com/user-attachments/assets/55198b98-0026-41aa-a7aa-d274b854257f">
| <img width="670" alt="Screenshot 2024-08-28 at 17 59 30"
src="https://github.com/user-attachments/assets/3c9136ea-4437-45e8-b3e6-3fe8555ec7e1">
|

## Mandatory celebration GIF

![](https://media1.tenor.com/m/gRAe8dfvrKMAAAAC/television-tv-shows.gif)

---------

Co-authored-by: Marco Antonio Ghiani <marcoantonio.ghiani@elastic.co>
Co-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com>
  • Loading branch information
3 people authored Sep 3, 2024
1 parent 5d77095 commit b7a909f
Show file tree
Hide file tree
Showing 11 changed files with 127 additions and 65 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ describe('Dependencies', () => {
describe('top-level dependencies page', () => {
it('has a list of dependencies and you can navigate to the page for one', () => {
cy.visitKibana(`/app/apm/services?${new URLSearchParams(timeRange)}`);
cy.getByTestSubj('superDatePickerstartDatePopoverButton');
cy.contains('nav a', 'Dependencies').click();

// `force: true` because Cypress says the element is 0x0
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,24 +9,48 @@ import { toBooleanRt, toNumberRt } from '@kbn/io-ts-utils';
import { Outlet } from '@kbn/typed-react-router-config';
import * as t from 'io-ts';
import React, { ComponentProps } from 'react';
import { dynamic } from '@kbn/shared-ux-utility';
import { offsetRt } from '../../../../common/comparison_rt';
import { ENVIRONMENT_ALL } from '../../../../common/environment_filter_values';
import { environmentRt } from '../../../../common/environment_rt';
import { TraceSearchType } from '../../../../common/trace_explorer';
import { ApmTimeRangeMetadataContextProvider } from '../../../context/time_range_metadata/time_range_metadata_context';
import { ServiceInventory } from '../../app/service_inventory';
import { ServiceMapHome } from '../../app/service_map';
import { TopTracesOverview } from '../../app/top_traces_overview';
import { TraceExplorer } from '../../app/trace_explorer';
import { TraceExplorerAggregatedCriticalPath } from '../../app/trace_explorer/trace_explorer_aggregated_critical_path';
import { TraceExplorerWaterfall } from '../../app/trace_explorer/trace_explorer_waterfall';
import { TraceOverview } from '../../app/trace_overview';
import { TransactionTab } from '../../app/transaction_details/waterfall_with_summary/transaction_tabs';
import { RedirectTo } from '../redirect_to';
import { ServiceGroupTemplate } from '../templates/service_group_template';
import { dependencies } from './dependencies';
import { legacyBackends } from './legacy_backends';
import { storageExplorer } from './storage_explorer';
import { TransactionTab } from '../../app/transaction_details/waterfall_with_summary/transaction_tabs';

const ServiceGroupTemplate = dynamic(() =>
import('../templates/service_group_template').then((mod) => ({
default: mod.ServiceGroupTemplate,
}))
);
const ServiceInventory = dynamic(() =>
import('../../app/service_inventory').then((mod) => ({ default: mod.ServiceInventory }))
);
const ServiceMapHome = dynamic(() =>
import('../../app/service_map').then((mod) => ({ default: mod.ServiceMapHome }))
);
const TopTracesOverview = dynamic(() =>
import('../../app/top_traces_overview').then((mod) => ({ default: mod.TopTracesOverview }))
);
const TraceExplorer = dynamic(() =>
import('../../app/trace_explorer').then((mod) => ({ default: mod.TraceExplorer }))
);
const TraceExplorerAggregatedCriticalPath = dynamic(() =>
import('../../app/trace_explorer/trace_explorer_aggregated_critical_path').then((mod) => ({
default: mod.TraceExplorerAggregatedCriticalPath,
}))
);
const TraceExplorerWaterfall = dynamic(() =>
import('../../app/trace_explorer/trace_explorer_waterfall').then((mod) => ({
default: mod.TraceExplorerWaterfall,
}))
);
const TraceOverview = dynamic(() =>
import('../../app/trace_overview').then((mod) => ({ default: mod.TraceOverview }))
);

function serviceGroupPage<TPath extends string>({
path,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import React from 'react';
import { i18n } from '@kbn/i18n';
import * as t from 'io-ts';
import { EuiLink } from '@elastic/eui';
import { StorageExplorer } from '../../app/storage_explorer';
import { dynamic } from '@kbn/shared-ux-utility';
import { ApmMainTemplate } from '../templates/apm_main_template';
import { Breadcrumb } from '../../app/breadcrumb';
import {
Expand All @@ -18,6 +18,10 @@ import {
} from '../../../../common/storage_explorer_types';
import { getStorageExplorerFeedbackHref } from '../../app/storage_explorer/get_storage_explorer_links';

const StorageExplorer = dynamic(() =>
import('../../app/storage_explorer').then((mod) => ({ default: mod.StorageExplorer }))
);

export const storageExplorer = {
'/storage-explorer': {
element: (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,13 @@

import * as t from 'io-ts';
import React from 'react';
import { Onboarding } from '../../app/onboarding';
import { dynamic } from '@kbn/shared-ux-utility';
import { INSTRUCTION_VARIANT } from '../../app/onboarding/instruction_variants';

const Onboarding = dynamic(() =>
import('../../app/onboarding').then((mod) => ({ default: mod.Onboarding }))
);

export const onboarding = {
'/onboarding': {
element: <Onboarding />,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import * as t from 'io-ts';
import qs from 'query-string';
import React from 'react';
import { Redirect } from 'react-router-dom';
import { dynamic } from '@kbn/shared-ux-utility';
import { offsetRt } from '../../../../common/comparison_rt';
import { ENVIRONMENT_ALL } from '../../../../common/environment_filter_values';
import { environmentRt } from '../../../../common/environment_rt';
Expand All @@ -21,25 +22,47 @@ import {
} from '../../../../common/latency_aggregation_types';
import { ApmTimeRangeMetadataContextProvider } from '../../../context/time_range_metadata/time_range_metadata_context';
import { useApmParams } from '../../../hooks/use_apm_params';
import { AlertsOverview, ALERT_STATUS_ALL } from '../../app/alerts_overview';
import { ErrorGroupDetails } from '../../app/error_group_details';
import { ErrorGroupOverview } from '../../app/error_group_overview';
import { InfraOverview } from '../../app/infra_overview';
import { ALERT_STATUS_ALL, AlertsOverview } from '../../app/alerts_overview';
import { InfraTab } from '../../app/infra_overview/infra_tabs/use_tabs';
import { Metrics } from '../../app/metrics';
import { MetricsDetails } from '../../app/metrics_details';
import { ServiceDependencies } from '../../app/service_dependencies';
import { ServiceLogs } from '../../app/service_logs';
import { ServiceMapServiceDetail } from '../../app/service_map';
import { ServiceOverview } from '../../app/service_overview';
import { TransactionDetails } from '../../app/transaction_details';
import { TransactionOverview } from '../../app/transaction_overview';
import { ApmServiceTemplate } from '../templates/apm_service_template';
import { ApmServiceWrapper } from './apm_service_wrapper';
import { RedirectToDefaultServiceRouteView } from './redirect_to_default_service_route_view';
import { ProfilingOverview } from '../../app/profiling_overview';
import { SearchBar } from '../../shared/search_bar/search_bar';
import { ServiceDependencies } from '../../app/service_dependencies';
import { ServiceDashboards } from '../../app/service_dashboards';
import { ErrorGroupDetails } from '../../app/error_group_details';

const ErrorGroupOverview = dynamic(() =>
import('../../app/error_group_overview').then((mod) => ({ default: mod.ErrorGroupOverview }))
);
const InfraOverview = dynamic(() =>
import('../../app/infra_overview').then((mod) => ({ default: mod.InfraOverview }))
);
const Metrics = dynamic(() =>
import('../../app/metrics').then((mod) => ({ default: mod.Metrics }))
);
const MetricsDetails = dynamic(() =>
import('../../app/metrics_details').then((mod) => ({ default: mod.MetricsDetails }))
);

const ServiceLogs = dynamic(() =>
import('../../app/service_logs').then((mod) => ({ default: mod.ServiceLogs }))
);
const ServiceMapServiceDetail = dynamic(() =>
import('../../app/service_map').then((mod) => ({ default: mod.ServiceMapServiceDetail }))
);
const ServiceOverview = dynamic(() =>
import('../../app/service_overview').then((mod) => ({ default: mod.ServiceOverview }))
);
const TransactionDetails = dynamic(() =>
import('../../app/transaction_details').then((mod) => ({ default: mod.TransactionDetails }))
);
const TransactionOverview = dynamic(() =>
import('../../app/transaction_overview').then((mod) => ({ default: mod.TransactionOverview }))
);
const ProfilingOverview = dynamic(() =>
import('../../app/profiling_overview').then((mod) => ({ default: mod.ProfilingOverview }))
);

function page({
title,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,7 @@ import type { EmbeddableApmAlertingVizProps } from '../types';
import type { EmbeddableDeps } from '../../types';
import { ApmEmbeddableContext } from '../../embeddable_context';
import { APMAlertingFailedTransactionsChart } from './chart';

export const APM_ALERTING_FAILED_TRANSACTIONS_CHART_EMBEDDABLE =
'APM_ALERTING_FAILED_TRANSACTIONS_CHART_EMBEDDABLE';
import { APM_ALERTING_FAILED_TRANSACTIONS_CHART_EMBEDDABLE } from '../constants';

export const getApmAlertingFailedTransactionsChartEmbeddableFactory = (deps: EmbeddableDeps) => {
const factory: ReactEmbeddableFactory<
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,7 @@ import type { EmbeddableApmAlertingLatencyVizProps } from '../types';
import type { EmbeddableDeps } from '../../types';
import { ApmEmbeddableContext } from '../../embeddable_context';
import { APMAlertingLatencyChart } from './chart';

export const APM_ALERTING_LATENCY_CHART_EMBEDDABLE = 'APM_ALERTING_LATENCY_CHART_EMBEDDABLE';
import { APM_ALERTING_LATENCY_CHART_EMBEDDABLE } from '../constants';

export const getApmAlertingLatencyChartEmbeddableFactory = (deps: EmbeddableDeps) => {
const factory: ReactEmbeddableFactory<
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,7 @@ import type { EmbeddableApmAlertingVizProps } from '../types';
import type { EmbeddableDeps } from '../../types';
import { ApmEmbeddableContext } from '../../embeddable_context';
import { APMAlertingThroughputChart } from './chart';

export const APM_ALERTING_THROUGHPUT_CHART_EMBEDDABLE = 'APM_ALERTING_THROUGHPUT_CHART_EMBEDDABLE';
import { APM_ALERTING_THROUGHPUT_CHART_EMBEDDABLE } from '../constants';

export const getApmAlertingThroughputChartEmbeddableFactory = (deps: EmbeddableDeps) => {
const factory: ReactEmbeddableFactory<
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/

export const APM_ALERTING_FAILED_TRANSACTIONS_CHART_EMBEDDABLE =
'APM_ALERTING_FAILED_TRANSACTIONS_CHART_EMBEDDABLE';
export const APM_ALERTING_LATENCY_CHART_EMBEDDABLE = 'APM_ALERTING_LATENCY_CHART_EMBEDDABLE';
export const APM_ALERTING_THROUGHPUT_CHART_EMBEDDABLE = 'APM_ALERTING_THROUGHPUT_CHART_EMBEDDABLE';
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,11 @@ import { CoreSetup } from '@kbn/core/public';

import { ApmPluginStartDeps, ApmPluginStart } from '../plugin';
import { EmbeddableDeps } from './types';
import {
APM_ALERTING_FAILED_TRANSACTIONS_CHART_EMBEDDABLE,
APM_ALERTING_LATENCY_CHART_EMBEDDABLE,
APM_ALERTING_THROUGHPUT_CHART_EMBEDDABLE,
} from './alerting/constants';

export async function registerEmbeddables(
deps: Omit<EmbeddableDeps, 'coreStart' | 'pluginsStart'>
Expand All @@ -16,36 +21,32 @@ export async function registerEmbeddables(
const pluginsSetup = deps.pluginsSetup;
const [coreStart, pluginsStart] = await coreSetup.getStartServices();
const registerReactEmbeddableFactory = pluginsSetup.embeddable.registerReactEmbeddableFactory;
const registerApmAlertingLatencyChartEmbeddable = async () => {
const { getApmAlertingLatencyChartEmbeddableFactory, APM_ALERTING_LATENCY_CHART_EMBEDDABLE } =
await import('./alerting/alerting_latency_chart/react_embeddable_factory');
registerReactEmbeddableFactory(APM_ALERTING_LATENCY_CHART_EMBEDDABLE, async () => {
return getApmAlertingLatencyChartEmbeddableFactory({ ...deps, coreStart, pluginsStart });
});
};
const registerApmAlertingThroughputChartEmbeddable = async () => {
const {
getApmAlertingThroughputChartEmbeddableFactory,
APM_ALERTING_THROUGHPUT_CHART_EMBEDDABLE,
} = await import('./alerting/alerting_throughput_chart/react_embeddable_factory');
registerReactEmbeddableFactory(APM_ALERTING_THROUGHPUT_CHART_EMBEDDABLE, async () => {
return getApmAlertingThroughputChartEmbeddableFactory({ ...deps, coreStart, pluginsStart });
});
};
const registerApmAlertingFailedTransactionsChartEmbeddable = async () => {
const {
getApmAlertingFailedTransactionsChartEmbeddableFactory,
APM_ALERTING_FAILED_TRANSACTIONS_CHART_EMBEDDABLE,
} = await import('./alerting/alerting_failed_transactions_chart/react_embeddable_factory');
registerReactEmbeddableFactory(APM_ALERTING_FAILED_TRANSACTIONS_CHART_EMBEDDABLE, async () => {
return getApmAlertingFailedTransactionsChartEmbeddableFactory({
...deps,
coreStart,
pluginsStart,
});

registerReactEmbeddableFactory(APM_ALERTING_LATENCY_CHART_EMBEDDABLE, async () => {
const { getApmAlertingLatencyChartEmbeddableFactory } = await import(
'./alerting/alerting_latency_chart/react_embeddable_factory'
);

return getApmAlertingLatencyChartEmbeddableFactory({ ...deps, coreStart, pluginsStart });
});

registerReactEmbeddableFactory(APM_ALERTING_THROUGHPUT_CHART_EMBEDDABLE, async () => {
const { getApmAlertingThroughputChartEmbeddableFactory } = await import(
'./alerting/alerting_throughput_chart/react_embeddable_factory'
);

return getApmAlertingThroughputChartEmbeddableFactory({ ...deps, coreStart, pluginsStart });
});

registerReactEmbeddableFactory(APM_ALERTING_FAILED_TRANSACTIONS_CHART_EMBEDDABLE, async () => {
const { getApmAlertingFailedTransactionsChartEmbeddableFactory } = await import(
'./alerting/alerting_failed_transactions_chart/react_embeddable_factory'
);

return getApmAlertingFailedTransactionsChartEmbeddableFactory({
...deps,
coreStart,
pluginsStart,
});
};
registerApmAlertingLatencyChartEmbeddable();
registerApmAlertingThroughputChartEmbeddable();
registerApmAlertingFailedTransactionsChartEmbeddable();
});
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,6 @@ import { ENVIRONMENT_ALL } from '../../common/environment_filter_values';
import type { TimePickerTimeDefaults } from '../components/shared/date_picker/typings';
import type { APMLocatorPayload } from './helpers';

const helpersModule = import('./helpers');

export const APM_APP_LOCATOR_ID = 'APM_LOCATOR';

export class APMServiceDetailLocator implements LocatorDefinition<APMLocatorPayload> {
Expand All @@ -28,7 +26,7 @@ export class APMServiceDetailLocator implements LocatorDefinition<APMLocatorPayl
}

async getLocation(payload: APMLocatorPayload) {
const { getPathForServiceDetail } = await helpersModule;
const { getPathForServiceDetail } = await import('./helpers');

const defaultTimeRange = this.uiSettings.get<TimePickerTimeDefaults>(
UI_SETTINGS.TIMEPICKER_TIME_DEFAULTS
Expand Down

0 comments on commit b7a909f

Please sign in to comment.