From b7a909f3e82877afacb4e4b4e68283dc1b220a83 Mon Sep 17 00:00:00 2001 From: Marco Antonio Ghiani Date: Tue, 3 Sep 2024 14:46:19 +0200 Subject: [PATCH] [APM] Reduce initially loaded bundles by 98% (#191658) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## 📓 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 | |--------|--------| | Screenshot 2024-08-28 at 17 58 59 | Screenshot 2024-08-28 at 17 59 30 | ## Mandatory celebration GIF ![](https://media1.tenor.com/m/gRAe8dfvrKMAAAAC/television-tv-shows.gif) --------- Co-authored-by: Marco Antonio Ghiani Co-authored-by: Elastic Machine --- .../e2e/dependencies/dependencies.cy.ts | 1 + .../public/components/routing/home/index.tsx | 42 ++++++++++--- .../routing/home/storage_explorer.tsx | 6 +- .../components/routing/onboarding/index.tsx | 6 +- .../routing/service_detail/index.tsx | 49 +++++++++++---- .../react_embeddable_factory.tsx | 4 +- .../react_embeddable_factory.tsx | 3 +- .../react_embeddable_factory.tsx | 3 +- .../public/embeddable/alerting/constants.ts | 11 ++++ .../embeddable/register_embeddables.tsx | 63 ++++++++++--------- .../public/locator/service_detail_locator.ts | 4 +- 11 files changed, 127 insertions(+), 65 deletions(-) create mode 100644 x-pack/plugins/observability_solution/apm/public/embeddable/alerting/constants.ts diff --git a/x-pack/plugins/observability_solution/apm/ftr_e2e/cypress/e2e/dependencies/dependencies.cy.ts b/x-pack/plugins/observability_solution/apm/ftr_e2e/cypress/e2e/dependencies/dependencies.cy.ts index d5e22e38c5d5e4..14ea4bb15b7869 100644 --- a/x-pack/plugins/observability_solution/apm/ftr_e2e/cypress/e2e/dependencies/dependencies.cy.ts +++ b/x-pack/plugins/observability_solution/apm/ftr_e2e/cypress/e2e/dependencies/dependencies.cy.ts @@ -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 diff --git a/x-pack/plugins/observability_solution/apm/public/components/routing/home/index.tsx b/x-pack/plugins/observability_solution/apm/public/components/routing/home/index.tsx index d517ae654468bf..63ee44baae2530 100644 --- a/x-pack/plugins/observability_solution/apm/public/components/routing/home/index.tsx +++ b/x-pack/plugins/observability_solution/apm/public/components/routing/home/index.tsx @@ -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({ path, diff --git a/x-pack/plugins/observability_solution/apm/public/components/routing/home/storage_explorer.tsx b/x-pack/plugins/observability_solution/apm/public/components/routing/home/storage_explorer.tsx index fb2bbf83b92b78..901934f67a3d04 100644 --- a/x-pack/plugins/observability_solution/apm/public/components/routing/home/storage_explorer.tsx +++ b/x-pack/plugins/observability_solution/apm/public/components/routing/home/storage_explorer.tsx @@ -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 { @@ -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: ( diff --git a/x-pack/plugins/observability_solution/apm/public/components/routing/onboarding/index.tsx b/x-pack/plugins/observability_solution/apm/public/components/routing/onboarding/index.tsx index 6fb6624b94e827..17fccd398da69e 100644 --- a/x-pack/plugins/observability_solution/apm/public/components/routing/onboarding/index.tsx +++ b/x-pack/plugins/observability_solution/apm/public/components/routing/onboarding/index.tsx @@ -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: , diff --git a/x-pack/plugins/observability_solution/apm/public/components/routing/service_detail/index.tsx b/x-pack/plugins/observability_solution/apm/public/components/routing/service_detail/index.tsx index 024af3bdd79a48..ea5a94a47ccd01 100644 --- a/x-pack/plugins/observability_solution/apm/public/components/routing/service_detail/index.tsx +++ b/x-pack/plugins/observability_solution/apm/public/components/routing/service_detail/index.tsx @@ -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'; @@ -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, diff --git a/x-pack/plugins/observability_solution/apm/public/embeddable/alerting/alerting_failed_transactions_chart/react_embeddable_factory.tsx b/x-pack/plugins/observability_solution/apm/public/embeddable/alerting/alerting_failed_transactions_chart/react_embeddable_factory.tsx index 6418799c4ad38a..f9513ad09fde7c 100644 --- a/x-pack/plugins/observability_solution/apm/public/embeddable/alerting/alerting_failed_transactions_chart/react_embeddable_factory.tsx +++ b/x-pack/plugins/observability_solution/apm/public/embeddable/alerting/alerting_failed_transactions_chart/react_embeddable_factory.tsx @@ -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< diff --git a/x-pack/plugins/observability_solution/apm/public/embeddable/alerting/alerting_latency_chart/react_embeddable_factory.tsx b/x-pack/plugins/observability_solution/apm/public/embeddable/alerting/alerting_latency_chart/react_embeddable_factory.tsx index 0795c821fc4657..1cb032d1d8fc50 100644 --- a/x-pack/plugins/observability_solution/apm/public/embeddable/alerting/alerting_latency_chart/react_embeddable_factory.tsx +++ b/x-pack/plugins/observability_solution/apm/public/embeddable/alerting/alerting_latency_chart/react_embeddable_factory.tsx @@ -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< diff --git a/x-pack/plugins/observability_solution/apm/public/embeddable/alerting/alerting_throughput_chart/react_embeddable_factory.tsx b/x-pack/plugins/observability_solution/apm/public/embeddable/alerting/alerting_throughput_chart/react_embeddable_factory.tsx index 6fe2135d8ec623..1126c376e2f0d7 100644 --- a/x-pack/plugins/observability_solution/apm/public/embeddable/alerting/alerting_throughput_chart/react_embeddable_factory.tsx +++ b/x-pack/plugins/observability_solution/apm/public/embeddable/alerting/alerting_throughput_chart/react_embeddable_factory.tsx @@ -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< diff --git a/x-pack/plugins/observability_solution/apm/public/embeddable/alerting/constants.ts b/x-pack/plugins/observability_solution/apm/public/embeddable/alerting/constants.ts new file mode 100644 index 00000000000000..eacb230058848d --- /dev/null +++ b/x-pack/plugins/observability_solution/apm/public/embeddable/alerting/constants.ts @@ -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'; diff --git a/x-pack/plugins/observability_solution/apm/public/embeddable/register_embeddables.tsx b/x-pack/plugins/observability_solution/apm/public/embeddable/register_embeddables.tsx index d3845215561d07..215959007a6bb9 100644 --- a/x-pack/plugins/observability_solution/apm/public/embeddable/register_embeddables.tsx +++ b/x-pack/plugins/observability_solution/apm/public/embeddable/register_embeddables.tsx @@ -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 @@ -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(); + }); } diff --git a/x-pack/plugins/observability_solution/apm/public/locator/service_detail_locator.ts b/x-pack/plugins/observability_solution/apm/public/locator/service_detail_locator.ts index 251aba86348371..6d4a53f1f6e261 100644 --- a/x-pack/plugins/observability_solution/apm/public/locator/service_detail_locator.ts +++ b/x-pack/plugins/observability_solution/apm/public/locator/service_detail_locator.ts @@ -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 { @@ -28,7 +26,7 @@ export class APMServiceDetailLocator implements LocatorDefinition( UI_SETTINGS.TIMEPICKER_TIME_DEFAULTS