diff --git a/x-pack/plugins/apm/public/components/app/RumDashboard/UXMetrics/index.tsx b/x-pack/plugins/apm/public/components/app/RumDashboard/UXMetrics/index.tsx
index 392b42cba12e5..29d5750231762 100644
--- a/x-pack/plugins/apm/public/components/app/RumDashboard/UXMetrics/index.tsx
+++ b/x-pack/plugins/apm/public/components/app/RumDashboard/UXMetrics/index.tsx
@@ -4,7 +4,7 @@
* you may not use this file except in compliance with the Elastic License.
*/
-import React, { useContext } from 'react';
+import React, { useContext, useMemo } from 'react';
import {
EuiFlexGroup,
EuiFlexItem,
@@ -17,7 +17,7 @@ import { I18LABELS } from '../translations';
import { KeyUXMetrics } from './KeyUXMetrics';
import { useFetcher } from '../../../../hooks/use_fetcher';
import { useUxQuery } from '../hooks/useUxQuery';
-import { CoreVitals } from '../../../../../../observability/public';
+import { getCoreVitalsComponent } from '../../../../../../observability/public';
import { CsmSharedContext } from '../CsmSharedContext';
import { useUrlParams } from '../../../../context/url_params_context/use_url_params';
import { getPercentileLabel } from './translations';
@@ -48,6 +48,18 @@ export function UXMetrics() {
sharedData: { totalPageViews },
} = useContext(CsmSharedContext);
+ const CoreVitals = useMemo(
+ () =>
+ getCoreVitalsComponent({
+ data,
+ totalPageViews,
+ loading: status !== 'success',
+ displayTrafficMetric: true,
+ }),
+ // eslint-disable-next-line react-hooks/exhaustive-deps
+ [status]
+ );
+
return (
@@ -67,12 +79,7 @@ export function UXMetrics() {
-
+ {CoreVitals}
diff --git a/x-pack/plugins/observability/public/components/app/header/index.tsx b/x-pack/plugins/observability/public/components/app/header/index.tsx
index b195bb52e7ed2..097871fe020e5 100644
--- a/x-pack/plugins/observability/public/components/app/header/index.tsx
+++ b/x-pack/plugins/observability/public/components/app/header/index.tsx
@@ -17,7 +17,7 @@ import { i18n } from '@kbn/i18n';
import React, { ReactNode } from 'react';
import styled from 'styled-components';
import { usePluginContext } from '../../../hooks/use_plugin_context';
-import { HeaderMenuPortal } from '../../shared/header_menu_portal';
+import HeaderMenuPortal from '../../shared/header_menu_portal';
const Container = styled.div<{ color: string }>`
background: ${(props) => props.color};
diff --git a/x-pack/plugins/observability/public/components/app/section/ux/index.tsx b/x-pack/plugins/observability/public/components/app/section/ux/index.tsx
index 43f1072d06fc2..7074a895d058b 100644
--- a/x-pack/plugins/observability/public/components/app/section/ux/index.tsx
+++ b/x-pack/plugins/observability/public/components/app/section/ux/index.tsx
@@ -12,7 +12,7 @@ import { FETCH_STATUS, useFetcher } from '../../../../hooks/use_fetcher';
import { useHasData } from '../../../../hooks/use_has_data';
import { useTimeRange } from '../../../../hooks/use_time_range';
import { UXHasDataResponse } from '../../../../typings';
-import { CoreVitals } from '../../../shared/core_web_vitals';
+import CoreVitals from '../../../shared/core_web_vitals';
interface Props {
bucketSize: string;
diff --git a/x-pack/plugins/observability/public/components/shared/core_web_vitals/index.tsx b/x-pack/plugins/observability/public/components/shared/core_web_vitals/index.tsx
index f573c8cfc1f97..7d40ce089cec4 100644
--- a/x-pack/plugins/observability/public/components/shared/core_web_vitals/index.tsx
+++ b/x-pack/plugins/observability/public/components/shared/core_web_vitals/index.tsx
@@ -16,6 +16,7 @@ import {
import { CoreVitalItem } from './core_vital_item';
import { WebCoreVitalsTitle } from './web_core_vitals_title';
import { ServiceName } from './service_name';
+import { CoreVitalProps } from '../types';
export interface UXMetrics {
cls: number | null;
@@ -29,7 +30,7 @@ export interface UXMetrics {
clsRanks: number[];
}
-export function formatToSec(value?: number | string, fromUnit = 'MicroSec'): string {
+function formatToSec(value?: number | string, fromUnit = 'MicroSec'): string {
const valueInMs = Number(value ?? 0) / (fromUnit === 'MicroSec' ? 1000 : 1);
if (valueInMs < 1000) {
@@ -51,23 +52,15 @@ const CoreVitalsThresholds = {
CLS: { good: '0.1', bad: '0.25' },
};
-interface Props {
- loading: boolean;
- data?: UXMetrics | null;
- displayServiceName?: boolean;
- serviceName?: string;
- totalPageViews?: number;
- displayTrafficMetric?: boolean;
-}
-
-export function CoreVitals({
+// eslint-disable-next-line import/no-default-export
+export default function CoreVitals({
data,
loading,
displayServiceName,
serviceName,
totalPageViews,
displayTrafficMetric = false,
-}: Props) {
+}: CoreVitalProps) {
const { lcp, lcpRanks, fid, fidRanks, cls, clsRanks, coreVitalPages } = data || {};
return (
diff --git a/x-pack/plugins/observability/public/components/shared/header_menu_portal.tsx b/x-pack/plugins/observability/public/components/shared/header_menu_portal.tsx
index ca03eb6ddb45a..e209e830d0f37 100644
--- a/x-pack/plugins/observability/public/components/shared/header_menu_portal.tsx
+++ b/x-pack/plugins/observability/public/components/shared/header_menu_portal.tsx
@@ -4,17 +4,13 @@
* you may not use this file except in compliance with the Elastic License.
*/
-import React, { ReactNode, useEffect, useMemo } from 'react';
+import React, { useEffect, useMemo } from 'react';
import { createPortalNode, InPortal, OutPortal } from 'react-reverse-portal';
-import { AppMountParameters } from '../../../../../../src/core/public';
import { toMountPoint } from '../../../../../../src/plugins/kibana_react/public';
+import { HeaderMenuPortalProps } from './types';
-interface HeaderMenuPortalProps {
- children: ReactNode;
- setHeaderActionMenu: AppMountParameters['setHeaderActionMenu'];
-}
-
-export function HeaderMenuPortal({ children, setHeaderActionMenu }: HeaderMenuPortalProps) {
+// eslint-disable-next-line import/no-default-export
+export default function HeaderMenuPortal({ children, setHeaderActionMenu }: HeaderMenuPortalProps) {
const portalNode = useMemo(() => createPortalNode(), []);
useEffect(() => {
diff --git a/x-pack/plugins/observability/public/components/shared/index.tsx b/x-pack/plugins/observability/public/components/shared/index.tsx
new file mode 100644
index 0000000000000..6e3835129beb2
--- /dev/null
+++ b/x-pack/plugins/observability/public/components/shared/index.tsx
@@ -0,0 +1,26 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+
+import React, { lazy, Suspense } from 'react';
+import { CoreVitalProps, HeaderMenuPortalProps } from './types';
+
+export function getCoreVitalsComponent(props: CoreVitalProps) {
+ const CoreVitalsLazy = lazy(() => import('./core_web_vitals/index'));
+ return (
+
+
+
+ );
+}
+
+export function HeaderMenuPortal(props: HeaderMenuPortalProps) {
+ const HeaderMenuPortalLazy = lazy(() => import('./header_menu_portal'));
+ return (
+
+
+
+ );
+}
diff --git a/x-pack/plugins/observability/public/components/shared/types.ts b/x-pack/plugins/observability/public/components/shared/types.ts
new file mode 100644
index 0000000000000..9039f444f550f
--- /dev/null
+++ b/x-pack/plugins/observability/public/components/shared/types.ts
@@ -0,0 +1,23 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+
+import { ReactNode } from 'react';
+import { AppMountParameters } from '../../../../../../src/core/public';
+import { UXMetrics } from './core_web_vitals';
+
+export interface HeaderMenuPortalProps {
+ children: ReactNode;
+ setHeaderActionMenu: AppMountParameters['setHeaderActionMenu'];
+}
+
+export interface CoreVitalProps {
+ loading: boolean;
+ data?: UXMetrics | null;
+ displayServiceName?: boolean;
+ serviceName?: string;
+ totalPageViews?: number;
+ displayTrafficMetric?: boolean;
+}
diff --git a/x-pack/plugins/observability/public/index.ts b/x-pack/plugins/observability/public/index.ts
index 22cc5faf23967..c052541956c13 100644
--- a/x-pack/plugins/observability/public/index.ts
+++ b/x-pack/plugins/observability/public/index.ts
@@ -6,8 +6,7 @@
import { PluginInitializerContext, PluginInitializer } from 'kibana/public';
import { Plugin, ObservabilityPluginSetup, ObservabilityPluginStart } from './plugin';
-export { HeaderMenuPortal } from './components/shared/header_menu_portal';
-export { ObservabilityPluginSetup, ObservabilityPluginStart };
+export type { ObservabilityPluginSetup, ObservabilityPluginStart };
export const plugin: PluginInitializer = (
context: PluginInitializerContext
@@ -17,7 +16,8 @@ export const plugin: PluginInitializer