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');
+}

Reply via email to