This is an automated email from the ASF dual-hosted git repository.
wusheng pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/skywalking-client-js.git
The following commit(s) were added to refs/heads/master by this push:
new c60a946 feat: detect supported browser APIs for core web vitals (#157)
c60a946 is described below
commit c60a94615a1726e50cce57abff4236698391b083
Author: Fine0830 <[email protected]>
AuthorDate: Thu Feb 13 12:34:17 2025 +0800
feat: detect supported browser APIs for core web vitals (#157)
---
README.md | 4 ++--
src/performance/index.ts | 32 ++++++++++++++++++++++----------
src/services/apiDetectSupported.ts | 27 +++++++++++++++++++++++++++
3 files changed, 51 insertions(+), 12 deletions(-)
diff --git a/README.md b/README.md
index d820634..d92d7cc 100644
--- a/README.md
+++ b/README.md
@@ -52,7 +52,7 @@ The register method supports the following parameters.
|jsErrors|Boolean|Support js errors monitoring|false|true|
|apiErrors|Boolean|Support API errors monitoring|false|true|
|resourceErrors|Boolean|Support resource errors monitoring|false|true|
-|useFmp|Boolean|Collect FMP (first meaningful paint) data of the first screen.
Deprecated: This is no longer recommended. Please use the useWebVitals instead.
|false|false|
+|useFmp|Boolean|Collect FMP (first meaningful paint) data of the first screen.
Deprecated: This is no longer recommended. Please use the `useWebVitals`
instead. |false|false|
|enableSPA|Boolean|Monitor the page hashchange event and report PV, which is
suitable for [single page application
scenarios](https://github.com/apache/skywalking-client-js#spa-page).
|false|false|
|autoTracePerf|Boolean|Support sending of performance data
automatically.|false|true|
|vue|Vue|Support vue2 errors monitoring. Deprecated: This is no longer
recommended. Please use the [Catching errors in
frames](https://github.com/apache/skywalking-client-js#catching-errors-in-frames-including-react-angular-vue)
scenario instead. |false|undefined|
@@ -61,7 +61,7 @@ The register method supports the following parameters.
|noTraceOrigins|(string \| RegExp)[]|Origin in the `noTraceOrigins` list will
not be traced.|false|[]|
|traceTimeInterval|Number|Support setting time interval to report
segments.|false|60000|
|customTags|Array|Custom Tags|false|-|
-|useWebVitals|Boolean|Collect three core web vitals|false|false|
+|useWebVitals|Boolean|Collect three core web vitals. NOTE, Safari does not
support all core web vitals, and Firefox does not support `CLS`.|false|false|
## Collect Metrics Manually
Use the `setPerformance` method to report metrics at the moment of page loaded
or any other moment meaningful.
diff --git a/src/performance/index.ts b/src/performance/index.ts
index 5fa2932..9d914e9 100644
--- a/src/performance/index.ts
+++ b/src/performance/index.ts
@@ -17,16 +17,17 @@
import {CustomOptionsType} from '../types';
import Report from '../services/report';
-import {prerenderChangeListener, onHidden, runOnce, idlePeriod} from
"../services/eventsListener";
+import {prerenderChangeListener, onHidden, runOnce, idlePeriod} from
'../services/eventsListener';
import pagePerf from './perf';
import FMP from './fmp';
-import {observe} from "../services/observe";
-import {LCPMetric, INPMetric, CLSMetric} from "./type";
-import {LayoutShift} from "../services/types";
-import {getVisibilityObserver} from "../services/getVisibilityObserver";
-import {getActivationStart, getResourceEntry} from "../services/getEntries";
-import {onBFCacheRestore} from "../services/bfcache";
-import {handleInteractionEntry, clearInteractions, getLongestInteraction,
DEFAULT_DURATION_THRESHOLD} from "../services/interactions";
+import {observe} from '../services/observe';
+import {LCPMetric, INPMetric, CLSMetric} from './type';
+import {LayoutShift} from '../services/types';
+import {getVisibilityObserver} from '../services/getVisibilityObserver';
+import {getActivationStart, getResourceEntry} from '../services/getEntries';
+import {onBFCacheRestore} from '../services/bfcache';
+import {handleInteractionEntry, clearInteractions, getLongestInteraction,
DEFAULT_DURATION_THRESHOLD} from '../services/interactions';
+import {isLayoutShiftSupported, isEventSupported,
isLargestContentfulPaintSupported} from '../services/apiDetectSupported';
const handler = {
set(target: {[key: string]: unknown}, prop: string, value: unknown) {
@@ -121,10 +122,13 @@ class TracePerf {
this.INP();
this.CLS();
setTimeout(() => {
- this.coreWebMetrics.fmpTime = Math.floor(FMP.fmpTime);
+ this.coreWebMetrics.fmpTime = Math.floor(FMP.fmpTime) || 0;
}, 5000);
}
private CLS() {
+ if (!isLayoutShiftSupported()) {
+ return this.coreWebMetrics.clsTime = 0;
+ }
let partValue = 0;
let entryList: LayoutShift[] = [];
@@ -147,7 +151,9 @@ class TracePerf {
}
});
if (partValue > 0) {
- this.coreWebMetrics.clsTime = Math.floor(partValue);
+ setTimeout(() => {
+ this.coreWebMetrics.clsTime = partValue;
+ }, 3000);
}
};
@@ -162,6 +168,9 @@ class TracePerf {
});
}
private LCP() {
+ if (!isLargestContentfulPaintSupported()) {
+ return this.coreWebMetrics.lcpTime = 0;
+ }
prerenderChangeListener(() => {
const visibilityObserver = getVisibilityObserver();
const processEntries = (entries: LCPMetric['entries']) => {
@@ -191,6 +200,9 @@ class TracePerf {
})
}
private INP() {
+ if (!isEventSupported()) {
+ return;
+ }
prerenderChangeListener(() => {
const processEntries = (entries: INPMetric['entries']) => {
idlePeriod(() => {
diff --git a/src/services/apiDetectSupported.ts
b/src/services/apiDetectSupported.ts
new file mode 100644
index 0000000..c1ded19
--- /dev/null
+++ b/src/services/apiDetectSupported.ts
@@ -0,0 +1,27 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+export function isLayoutShiftSupported() {
+ return PerformanceObserver.supportedEntryTypes.includes('layout-shift');
+}
+
+export function isLargestContentfulPaintSupported() {
+ return
PerformanceObserver.supportedEntryTypes.includes('largest-contentful-paint');
+}
+
+export function isEventSupported() {
+ return PerformanceObserver.supportedEntryTypes.includes('event');
+}