@be-link/cls-logger 1.0.1-beta.20 → 1.0.1-beta.21
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +280 -68
- package/dist/index.esm.js +104 -127
- package/dist/index.js +104 -127
- package/dist/index.umd.js +106 -131
- package/dist/mini/performanceMonitor.d.ts.map +1 -1
- package/dist/mini.esm.js +0 -1
- package/dist/mini.js +0 -1
- package/dist/types.d.ts +9 -3
- package/dist/types.d.ts.map +1 -1
- package/dist/web/performanceMonitor.d.ts.map +1 -1
- package/dist/web.esm.js +103 -126
- package/dist/web.js +103 -126
- package/package.json +3 -2
package/dist/index.esm.js
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { onFCP, onLCP, onCLS, onINP, onTTFB } from 'web-vitals';
|
|
2
|
+
|
|
1
3
|
function isPlainObject(value) {
|
|
2
4
|
return Object.prototype.toString.call(value) === '[object Object]';
|
|
3
5
|
}
|
|
@@ -1958,14 +1960,10 @@ function getPagePath() {
|
|
|
1958
1960
|
return '';
|
|
1959
1961
|
}
|
|
1960
1962
|
}
|
|
1961
|
-
|
|
1962
|
-
|
|
1963
|
-
|
|
1964
|
-
|
|
1965
|
-
value,
|
|
1966
|
-
...extra,
|
|
1967
|
-
});
|
|
1968
|
-
}
|
|
1963
|
+
/**
|
|
1964
|
+
* 安装浏览器性能监控
|
|
1965
|
+
* 使用 Google web-vitals 库实现 Core Web Vitals 指标采集
|
|
1966
|
+
*/
|
|
1969
1967
|
function installBrowserPerformanceMonitor(report, options) {
|
|
1970
1968
|
if (typeof window === 'undefined')
|
|
1971
1969
|
return;
|
|
@@ -1974,145 +1972,100 @@ function installBrowserPerformanceMonitor(report, options) {
|
|
|
1974
1972
|
return;
|
|
1975
1973
|
w.__beLinkClsLoggerPerfInstalled__ = true;
|
|
1976
1974
|
const ignoreUrls = [...DEFAULT_IGNORE, ...(options.ignoreUrls ?? [])];
|
|
1977
|
-
//
|
|
1978
|
-
|
|
1975
|
+
// Web Vitals: 使用 Google web-vitals 库
|
|
1976
|
+
// 这个库会自动处理:
|
|
1977
|
+
// - LCP 在用户交互后停止观察
|
|
1978
|
+
// - firstHiddenTime 过滤(页面隐藏后的数据不计入)
|
|
1979
|
+
// - CLS 5秒会话窗口算法
|
|
1980
|
+
// - BFCache 恢复时自动重置指标
|
|
1981
|
+
if (options.webVitals) {
|
|
1982
|
+
// FCP
|
|
1979
1983
|
try {
|
|
1980
|
-
|
|
1981
|
-
|
|
1982
|
-
|
|
1983
|
-
|
|
1984
|
-
|
|
1985
|
-
:
|
|
1986
|
-
|
|
1987
|
-
|
|
1988
|
-
|
|
1984
|
+
onFCP((metric) => {
|
|
1985
|
+
report(options.reportType, {
|
|
1986
|
+
pagePath: getPagePath(),
|
|
1987
|
+
metric: 'FCP',
|
|
1988
|
+
value: metric.value,
|
|
1989
|
+
unit: 'ms',
|
|
1990
|
+
rating: metric.rating,
|
|
1991
|
+
id: metric.id,
|
|
1992
|
+
navigationType: metric.navigationType,
|
|
1993
|
+
});
|
|
1994
|
+
});
|
|
1989
1995
|
}
|
|
1990
1996
|
catch {
|
|
1991
1997
|
// ignore
|
|
1992
1998
|
}
|
|
1993
|
-
|
|
1994
|
-
// Web Vitals: FCP/LCP/CLS/FID
|
|
1995
|
-
if (options.webVitals && typeof globalThis.PerformanceObserver === 'function') {
|
|
1996
|
-
// FCP
|
|
1999
|
+
// LCP(自动处理用户交互后停止)
|
|
1997
2000
|
try {
|
|
1998
|
-
|
|
1999
|
-
|
|
2000
|
-
|
|
2001
|
-
|
|
2002
|
-
|
|
2003
|
-
|
|
2004
|
-
|
|
2005
|
-
|
|
2006
|
-
|
|
2007
|
-
}
|
|
2008
|
-
catch {
|
|
2009
|
-
// ignore
|
|
2010
|
-
}
|
|
2001
|
+
onLCP((metric) => {
|
|
2002
|
+
report(options.reportType, {
|
|
2003
|
+
pagePath: getPagePath(),
|
|
2004
|
+
metric: 'LCP',
|
|
2005
|
+
value: metric.value,
|
|
2006
|
+
unit: 'ms',
|
|
2007
|
+
rating: metric.rating,
|
|
2008
|
+
id: metric.id,
|
|
2009
|
+
navigationType: metric.navigationType,
|
|
2010
|
+
});
|
|
2011
2011
|
});
|
|
2012
|
-
po.observe({ type: 'paint', buffered: true });
|
|
2013
2012
|
}
|
|
2014
2013
|
catch {
|
|
2015
2014
|
// ignore
|
|
2016
2015
|
}
|
|
2017
|
-
//
|
|
2018
|
-
let lastLcp = null;
|
|
2016
|
+
// CLS(自动处理会话窗口)
|
|
2019
2017
|
try {
|
|
2020
|
-
|
|
2021
|
-
|
|
2022
|
-
|
|
2023
|
-
|
|
2024
|
-
|
|
2025
|
-
|
|
2026
|
-
|
|
2027
|
-
|
|
2028
|
-
|
|
2018
|
+
onCLS((metric) => {
|
|
2019
|
+
report(options.reportType, {
|
|
2020
|
+
pagePath: getPagePath(),
|
|
2021
|
+
metric: 'CLS',
|
|
2022
|
+
value: metric.value,
|
|
2023
|
+
unit: 'score',
|
|
2024
|
+
rating: metric.rating,
|
|
2025
|
+
id: metric.id,
|
|
2026
|
+
navigationType: metric.navigationType,
|
|
2027
|
+
});
|
|
2029
2028
|
});
|
|
2030
|
-
po.observe({ type: 'largest-contentful-paint', buffered: true });
|
|
2031
|
-
const flushLcp = () => {
|
|
2032
|
-
try {
|
|
2033
|
-
if (!lastLcp)
|
|
2034
|
-
return;
|
|
2035
|
-
if (!sampleHit$1(options.sampleRate))
|
|
2036
|
-
return;
|
|
2037
|
-
if (typeof lastLcp.startTime === 'number')
|
|
2038
|
-
reportMetric(report, options.reportType, 'LCP', lastLcp.startTime, { unit: 'ms' });
|
|
2039
|
-
lastLcp = null;
|
|
2040
|
-
}
|
|
2041
|
-
catch {
|
|
2042
|
-
// ignore
|
|
2043
|
-
}
|
|
2044
|
-
};
|
|
2045
|
-
window.addEventListener('pagehide', flushLcp, { once: true });
|
|
2046
|
-
document.addEventListener('visibilitychange', () => {
|
|
2047
|
-
if (document.visibilityState === 'hidden')
|
|
2048
|
-
flushLcp();
|
|
2049
|
-
}, { once: true });
|
|
2050
2029
|
}
|
|
2051
2030
|
catch {
|
|
2052
2031
|
// ignore
|
|
2053
2032
|
}
|
|
2054
|
-
//
|
|
2033
|
+
// INP(替代 FID,2024年3月起成为核心指标)
|
|
2055
2034
|
try {
|
|
2056
|
-
|
|
2057
|
-
|
|
2058
|
-
|
|
2059
|
-
|
|
2060
|
-
|
|
2061
|
-
|
|
2062
|
-
|
|
2063
|
-
|
|
2064
|
-
|
|
2065
|
-
}
|
|
2066
|
-
catch {
|
|
2067
|
-
// ignore
|
|
2068
|
-
}
|
|
2035
|
+
onINP((metric) => {
|
|
2036
|
+
report(options.reportType, {
|
|
2037
|
+
pagePath: getPagePath(),
|
|
2038
|
+
metric: 'INP',
|
|
2039
|
+
value: metric.value,
|
|
2040
|
+
unit: 'ms',
|
|
2041
|
+
rating: metric.rating,
|
|
2042
|
+
id: metric.id,
|
|
2043
|
+
navigationType: metric.navigationType,
|
|
2044
|
+
});
|
|
2069
2045
|
});
|
|
2070
|
-
po.observe({ type: 'layout-shift', buffered: true });
|
|
2071
|
-
const flushCls = () => {
|
|
2072
|
-
try {
|
|
2073
|
-
if (!sampleHit$1(options.sampleRate))
|
|
2074
|
-
return;
|
|
2075
|
-
reportMetric(report, options.reportType, 'CLS', clsValue, { unit: 'score' });
|
|
2076
|
-
}
|
|
2077
|
-
catch {
|
|
2078
|
-
// ignore
|
|
2079
|
-
}
|
|
2080
|
-
};
|
|
2081
|
-
window.addEventListener('pagehide', flushCls, { once: true });
|
|
2082
|
-
document.addEventListener('visibilitychange', () => {
|
|
2083
|
-
if (document.visibilityState === 'hidden')
|
|
2084
|
-
flushCls();
|
|
2085
|
-
}, { once: true });
|
|
2086
2046
|
}
|
|
2087
2047
|
catch {
|
|
2088
2048
|
// ignore
|
|
2089
2049
|
}
|
|
2090
|
-
//
|
|
2050
|
+
// TTFB
|
|
2091
2051
|
try {
|
|
2092
|
-
|
|
2093
|
-
|
|
2094
|
-
|
|
2095
|
-
|
|
2096
|
-
|
|
2097
|
-
|
|
2098
|
-
|
|
2099
|
-
|
|
2100
|
-
|
|
2101
|
-
|
|
2102
|
-
}
|
|
2103
|
-
}
|
|
2104
|
-
}
|
|
2105
|
-
catch {
|
|
2106
|
-
// ignore
|
|
2107
|
-
}
|
|
2052
|
+
onTTFB((metric) => {
|
|
2053
|
+
report(options.reportType, {
|
|
2054
|
+
pagePath: getPagePath(),
|
|
2055
|
+
metric: 'TTFB',
|
|
2056
|
+
value: metric.value,
|
|
2057
|
+
unit: 'ms',
|
|
2058
|
+
rating: metric.rating,
|
|
2059
|
+
id: metric.id,
|
|
2060
|
+
navigationType: metric.navigationType,
|
|
2061
|
+
});
|
|
2108
2062
|
});
|
|
2109
|
-
po.observe({ type: 'first-input', buffered: true });
|
|
2110
2063
|
}
|
|
2111
2064
|
catch {
|
|
2112
2065
|
// ignore
|
|
2113
2066
|
}
|
|
2114
2067
|
}
|
|
2115
|
-
// Resource timing
|
|
2068
|
+
// Resource timing:资源加载耗时(web-vitals 不包含此功能,保留原有实现)
|
|
2116
2069
|
if (options.resourceTiming && typeof globalThis.PerformanceObserver === 'function') {
|
|
2117
2070
|
try {
|
|
2118
2071
|
const po = new PerformanceObserver((list) => {
|
|
@@ -2124,9 +2077,25 @@ function installBrowserPerformanceMonitor(report, options) {
|
|
|
2124
2077
|
if (!name || shouldIgnoreUrl(name, ignoreUrls))
|
|
2125
2078
|
continue;
|
|
2126
2079
|
const initiatorType = String(entry?.initiatorType ?? '');
|
|
2127
|
-
//
|
|
2080
|
+
// 关注 fetch/xhr/img/script(同时允许 css/other 但不强制)
|
|
2128
2081
|
if (!['xmlhttprequest', 'fetch', 'img', 'script', 'css'].includes(initiatorType))
|
|
2129
2082
|
continue;
|
|
2083
|
+
// 时序分解(便于定位慢在哪个阶段)
|
|
2084
|
+
const domainLookupStart = entry.domainLookupStart ?? 0;
|
|
2085
|
+
const domainLookupEnd = entry.domainLookupEnd ?? 0;
|
|
2086
|
+
const connectStart = entry.connectStart ?? 0;
|
|
2087
|
+
const connectEnd = entry.connectEnd ?? 0;
|
|
2088
|
+
const requestStart = entry.requestStart ?? 0;
|
|
2089
|
+
const responseStart = entry.responseStart ?? 0;
|
|
2090
|
+
const responseEnd = entry.responseEnd ?? 0;
|
|
2091
|
+
const dns = domainLookupEnd - domainLookupStart;
|
|
2092
|
+
const tcp = connectEnd - connectStart;
|
|
2093
|
+
const ttfb = responseStart - requestStart;
|
|
2094
|
+
const download = responseEnd - responseStart;
|
|
2095
|
+
// 缓存检测:transferSize=0 且 decodedBodySize>0 表示缓存命中
|
|
2096
|
+
const transferSize = entry.transferSize ?? 0;
|
|
2097
|
+
const decodedBodySize = entry.decodedBodySize ?? 0;
|
|
2098
|
+
const cached = transferSize === 0 && decodedBodySize > 0;
|
|
2130
2099
|
const payload = {
|
|
2131
2100
|
pagePath: getPagePath(),
|
|
2132
2101
|
metric: 'resource',
|
|
@@ -2134,16 +2103,26 @@ function installBrowserPerformanceMonitor(report, options) {
|
|
|
2134
2103
|
url: truncate$1(name, options.maxTextLength),
|
|
2135
2104
|
startTime: typeof entry?.startTime === 'number' ? entry.startTime : undefined,
|
|
2136
2105
|
duration: typeof entry?.duration === 'number' ? entry.duration : undefined,
|
|
2106
|
+
// 时序分解(跨域资源可能为 0)
|
|
2107
|
+
dns: dns > 0 ? Math.round(dns) : undefined,
|
|
2108
|
+
tcp: tcp > 0 ? Math.round(tcp) : undefined,
|
|
2109
|
+
ttfb: ttfb > 0 ? Math.round(ttfb) : undefined,
|
|
2110
|
+
download: download > 0 ? Math.round(download) : undefined,
|
|
2111
|
+
// 缓存标记
|
|
2112
|
+
cached,
|
|
2137
2113
|
};
|
|
2138
|
-
//
|
|
2139
|
-
if (
|
|
2140
|
-
payload.transferSize =
|
|
2141
|
-
if (typeof entry?.encodedBodySize === 'number')
|
|
2114
|
+
// 尺寸字段(跨域资源可能为 0)
|
|
2115
|
+
if (transferSize > 0)
|
|
2116
|
+
payload.transferSize = transferSize;
|
|
2117
|
+
if (typeof entry?.encodedBodySize === 'number' && entry.encodedBodySize > 0) {
|
|
2142
2118
|
payload.encodedBodySize = entry.encodedBodySize;
|
|
2143
|
-
|
|
2144
|
-
|
|
2145
|
-
|
|
2119
|
+
}
|
|
2120
|
+
if (decodedBodySize > 0)
|
|
2121
|
+
payload.decodedBodySize = decodedBodySize;
|
|
2122
|
+
// 协议和状态
|
|
2123
|
+
if (typeof entry?.nextHopProtocol === 'string' && entry.nextHopProtocol) {
|
|
2146
2124
|
payload.nextHopProtocol = entry.nextHopProtocol;
|
|
2125
|
+
}
|
|
2147
2126
|
if (typeof entry?.responseStatus === 'number')
|
|
2148
2127
|
payload.status = entry.responseStatus;
|
|
2149
2128
|
report(options.reportType, payload);
|
|
@@ -2171,7 +2150,6 @@ function installWebPerformanceMonitor(report, opts = {}) {
|
|
|
2171
2150
|
sampleRate: raw.sampleRate ?? 1,
|
|
2172
2151
|
ignoreUrls: raw.ignoreUrls ?? [],
|
|
2173
2152
|
webVitals: raw.webVitals ?? true,
|
|
2174
|
-
navigationTiming: raw.navigationTiming ?? true,
|
|
2175
2153
|
resourceTiming: raw.resourceTiming ?? true,
|
|
2176
2154
|
maxTextLength: raw.maxTextLength ?? 2000,
|
|
2177
2155
|
};
|
|
@@ -2263,7 +2241,6 @@ function installMiniPerformanceMonitor(report, opts = {}) {
|
|
|
2263
2241
|
sampleRate: raw.sampleRate ?? 1,
|
|
2264
2242
|
ignoreUrls: raw.ignoreUrls ?? [],
|
|
2265
2243
|
webVitals: raw.webVitals ?? true,
|
|
2266
|
-
navigationTiming: raw.navigationTiming ?? true,
|
|
2267
2244
|
resourceTiming: raw.resourceTiming ?? true,
|
|
2268
2245
|
maxTextLength: raw.maxTextLength ?? 2000,
|
|
2269
2246
|
};
|
package/dist/index.js
CHANGED
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
4
|
|
|
5
|
+
var webVitals = require('web-vitals');
|
|
6
|
+
|
|
5
7
|
function isPlainObject(value) {
|
|
6
8
|
return Object.prototype.toString.call(value) === '[object Object]';
|
|
7
9
|
}
|
|
@@ -1962,14 +1964,10 @@ function getPagePath() {
|
|
|
1962
1964
|
return '';
|
|
1963
1965
|
}
|
|
1964
1966
|
}
|
|
1965
|
-
|
|
1966
|
-
|
|
1967
|
-
|
|
1968
|
-
|
|
1969
|
-
value,
|
|
1970
|
-
...extra,
|
|
1971
|
-
});
|
|
1972
|
-
}
|
|
1967
|
+
/**
|
|
1968
|
+
* 安装浏览器性能监控
|
|
1969
|
+
* 使用 Google web-vitals 库实现 Core Web Vitals 指标采集
|
|
1970
|
+
*/
|
|
1973
1971
|
function installBrowserPerformanceMonitor(report, options) {
|
|
1974
1972
|
if (typeof window === 'undefined')
|
|
1975
1973
|
return;
|
|
@@ -1978,145 +1976,100 @@ function installBrowserPerformanceMonitor(report, options) {
|
|
|
1978
1976
|
return;
|
|
1979
1977
|
w.__beLinkClsLoggerPerfInstalled__ = true;
|
|
1980
1978
|
const ignoreUrls = [...DEFAULT_IGNORE, ...(options.ignoreUrls ?? [])];
|
|
1981
|
-
//
|
|
1982
|
-
|
|
1979
|
+
// Web Vitals: 使用 Google web-vitals 库
|
|
1980
|
+
// 这个库会自动处理:
|
|
1981
|
+
// - LCP 在用户交互后停止观察
|
|
1982
|
+
// - firstHiddenTime 过滤(页面隐藏后的数据不计入)
|
|
1983
|
+
// - CLS 5秒会话窗口算法
|
|
1984
|
+
// - BFCache 恢复时自动重置指标
|
|
1985
|
+
if (options.webVitals) {
|
|
1986
|
+
// FCP
|
|
1983
1987
|
try {
|
|
1984
|
-
|
|
1985
|
-
|
|
1986
|
-
|
|
1987
|
-
|
|
1988
|
-
|
|
1989
|
-
:
|
|
1990
|
-
|
|
1991
|
-
|
|
1992
|
-
|
|
1988
|
+
webVitals.onFCP((metric) => {
|
|
1989
|
+
report(options.reportType, {
|
|
1990
|
+
pagePath: getPagePath(),
|
|
1991
|
+
metric: 'FCP',
|
|
1992
|
+
value: metric.value,
|
|
1993
|
+
unit: 'ms',
|
|
1994
|
+
rating: metric.rating,
|
|
1995
|
+
id: metric.id,
|
|
1996
|
+
navigationType: metric.navigationType,
|
|
1997
|
+
});
|
|
1998
|
+
});
|
|
1993
1999
|
}
|
|
1994
2000
|
catch {
|
|
1995
2001
|
// ignore
|
|
1996
2002
|
}
|
|
1997
|
-
|
|
1998
|
-
// Web Vitals: FCP/LCP/CLS/FID
|
|
1999
|
-
if (options.webVitals && typeof globalThis.PerformanceObserver === 'function') {
|
|
2000
|
-
// FCP
|
|
2003
|
+
// LCP(自动处理用户交互后停止)
|
|
2001
2004
|
try {
|
|
2002
|
-
|
|
2003
|
-
|
|
2004
|
-
|
|
2005
|
-
|
|
2006
|
-
|
|
2007
|
-
|
|
2008
|
-
|
|
2009
|
-
|
|
2010
|
-
|
|
2011
|
-
}
|
|
2012
|
-
catch {
|
|
2013
|
-
// ignore
|
|
2014
|
-
}
|
|
2005
|
+
webVitals.onLCP((metric) => {
|
|
2006
|
+
report(options.reportType, {
|
|
2007
|
+
pagePath: getPagePath(),
|
|
2008
|
+
metric: 'LCP',
|
|
2009
|
+
value: metric.value,
|
|
2010
|
+
unit: 'ms',
|
|
2011
|
+
rating: metric.rating,
|
|
2012
|
+
id: metric.id,
|
|
2013
|
+
navigationType: metric.navigationType,
|
|
2014
|
+
});
|
|
2015
2015
|
});
|
|
2016
|
-
po.observe({ type: 'paint', buffered: true });
|
|
2017
2016
|
}
|
|
2018
2017
|
catch {
|
|
2019
2018
|
// ignore
|
|
2020
2019
|
}
|
|
2021
|
-
//
|
|
2022
|
-
let lastLcp = null;
|
|
2020
|
+
// CLS(自动处理会话窗口)
|
|
2023
2021
|
try {
|
|
2024
|
-
|
|
2025
|
-
|
|
2026
|
-
|
|
2027
|
-
|
|
2028
|
-
|
|
2029
|
-
|
|
2030
|
-
|
|
2031
|
-
|
|
2032
|
-
|
|
2022
|
+
webVitals.onCLS((metric) => {
|
|
2023
|
+
report(options.reportType, {
|
|
2024
|
+
pagePath: getPagePath(),
|
|
2025
|
+
metric: 'CLS',
|
|
2026
|
+
value: metric.value,
|
|
2027
|
+
unit: 'score',
|
|
2028
|
+
rating: metric.rating,
|
|
2029
|
+
id: metric.id,
|
|
2030
|
+
navigationType: metric.navigationType,
|
|
2031
|
+
});
|
|
2033
2032
|
});
|
|
2034
|
-
po.observe({ type: 'largest-contentful-paint', buffered: true });
|
|
2035
|
-
const flushLcp = () => {
|
|
2036
|
-
try {
|
|
2037
|
-
if (!lastLcp)
|
|
2038
|
-
return;
|
|
2039
|
-
if (!sampleHit$1(options.sampleRate))
|
|
2040
|
-
return;
|
|
2041
|
-
if (typeof lastLcp.startTime === 'number')
|
|
2042
|
-
reportMetric(report, options.reportType, 'LCP', lastLcp.startTime, { unit: 'ms' });
|
|
2043
|
-
lastLcp = null;
|
|
2044
|
-
}
|
|
2045
|
-
catch {
|
|
2046
|
-
// ignore
|
|
2047
|
-
}
|
|
2048
|
-
};
|
|
2049
|
-
window.addEventListener('pagehide', flushLcp, { once: true });
|
|
2050
|
-
document.addEventListener('visibilitychange', () => {
|
|
2051
|
-
if (document.visibilityState === 'hidden')
|
|
2052
|
-
flushLcp();
|
|
2053
|
-
}, { once: true });
|
|
2054
2033
|
}
|
|
2055
2034
|
catch {
|
|
2056
2035
|
// ignore
|
|
2057
2036
|
}
|
|
2058
|
-
//
|
|
2037
|
+
// INP(替代 FID,2024年3月起成为核心指标)
|
|
2059
2038
|
try {
|
|
2060
|
-
|
|
2061
|
-
|
|
2062
|
-
|
|
2063
|
-
|
|
2064
|
-
|
|
2065
|
-
|
|
2066
|
-
|
|
2067
|
-
|
|
2068
|
-
|
|
2069
|
-
}
|
|
2070
|
-
catch {
|
|
2071
|
-
// ignore
|
|
2072
|
-
}
|
|
2039
|
+
webVitals.onINP((metric) => {
|
|
2040
|
+
report(options.reportType, {
|
|
2041
|
+
pagePath: getPagePath(),
|
|
2042
|
+
metric: 'INP',
|
|
2043
|
+
value: metric.value,
|
|
2044
|
+
unit: 'ms',
|
|
2045
|
+
rating: metric.rating,
|
|
2046
|
+
id: metric.id,
|
|
2047
|
+
navigationType: metric.navigationType,
|
|
2048
|
+
});
|
|
2073
2049
|
});
|
|
2074
|
-
po.observe({ type: 'layout-shift', buffered: true });
|
|
2075
|
-
const flushCls = () => {
|
|
2076
|
-
try {
|
|
2077
|
-
if (!sampleHit$1(options.sampleRate))
|
|
2078
|
-
return;
|
|
2079
|
-
reportMetric(report, options.reportType, 'CLS', clsValue, { unit: 'score' });
|
|
2080
|
-
}
|
|
2081
|
-
catch {
|
|
2082
|
-
// ignore
|
|
2083
|
-
}
|
|
2084
|
-
};
|
|
2085
|
-
window.addEventListener('pagehide', flushCls, { once: true });
|
|
2086
|
-
document.addEventListener('visibilitychange', () => {
|
|
2087
|
-
if (document.visibilityState === 'hidden')
|
|
2088
|
-
flushCls();
|
|
2089
|
-
}, { once: true });
|
|
2090
2050
|
}
|
|
2091
2051
|
catch {
|
|
2092
2052
|
// ignore
|
|
2093
2053
|
}
|
|
2094
|
-
//
|
|
2054
|
+
// TTFB
|
|
2095
2055
|
try {
|
|
2096
|
-
|
|
2097
|
-
|
|
2098
|
-
|
|
2099
|
-
|
|
2100
|
-
|
|
2101
|
-
|
|
2102
|
-
|
|
2103
|
-
|
|
2104
|
-
|
|
2105
|
-
|
|
2106
|
-
}
|
|
2107
|
-
}
|
|
2108
|
-
}
|
|
2109
|
-
catch {
|
|
2110
|
-
// ignore
|
|
2111
|
-
}
|
|
2056
|
+
webVitals.onTTFB((metric) => {
|
|
2057
|
+
report(options.reportType, {
|
|
2058
|
+
pagePath: getPagePath(),
|
|
2059
|
+
metric: 'TTFB',
|
|
2060
|
+
value: metric.value,
|
|
2061
|
+
unit: 'ms',
|
|
2062
|
+
rating: metric.rating,
|
|
2063
|
+
id: metric.id,
|
|
2064
|
+
navigationType: metric.navigationType,
|
|
2065
|
+
});
|
|
2112
2066
|
});
|
|
2113
|
-
po.observe({ type: 'first-input', buffered: true });
|
|
2114
2067
|
}
|
|
2115
2068
|
catch {
|
|
2116
2069
|
// ignore
|
|
2117
2070
|
}
|
|
2118
2071
|
}
|
|
2119
|
-
// Resource timing
|
|
2072
|
+
// Resource timing:资源加载耗时(web-vitals 不包含此功能,保留原有实现)
|
|
2120
2073
|
if (options.resourceTiming && typeof globalThis.PerformanceObserver === 'function') {
|
|
2121
2074
|
try {
|
|
2122
2075
|
const po = new PerformanceObserver((list) => {
|
|
@@ -2128,9 +2081,25 @@ function installBrowserPerformanceMonitor(report, options) {
|
|
|
2128
2081
|
if (!name || shouldIgnoreUrl(name, ignoreUrls))
|
|
2129
2082
|
continue;
|
|
2130
2083
|
const initiatorType = String(entry?.initiatorType ?? '');
|
|
2131
|
-
//
|
|
2084
|
+
// 关注 fetch/xhr/img/script(同时允许 css/other 但不强制)
|
|
2132
2085
|
if (!['xmlhttprequest', 'fetch', 'img', 'script', 'css'].includes(initiatorType))
|
|
2133
2086
|
continue;
|
|
2087
|
+
// 时序分解(便于定位慢在哪个阶段)
|
|
2088
|
+
const domainLookupStart = entry.domainLookupStart ?? 0;
|
|
2089
|
+
const domainLookupEnd = entry.domainLookupEnd ?? 0;
|
|
2090
|
+
const connectStart = entry.connectStart ?? 0;
|
|
2091
|
+
const connectEnd = entry.connectEnd ?? 0;
|
|
2092
|
+
const requestStart = entry.requestStart ?? 0;
|
|
2093
|
+
const responseStart = entry.responseStart ?? 0;
|
|
2094
|
+
const responseEnd = entry.responseEnd ?? 0;
|
|
2095
|
+
const dns = domainLookupEnd - domainLookupStart;
|
|
2096
|
+
const tcp = connectEnd - connectStart;
|
|
2097
|
+
const ttfb = responseStart - requestStart;
|
|
2098
|
+
const download = responseEnd - responseStart;
|
|
2099
|
+
// 缓存检测:transferSize=0 且 decodedBodySize>0 表示缓存命中
|
|
2100
|
+
const transferSize = entry.transferSize ?? 0;
|
|
2101
|
+
const decodedBodySize = entry.decodedBodySize ?? 0;
|
|
2102
|
+
const cached = transferSize === 0 && decodedBodySize > 0;
|
|
2134
2103
|
const payload = {
|
|
2135
2104
|
pagePath: getPagePath(),
|
|
2136
2105
|
metric: 'resource',
|
|
@@ -2138,16 +2107,26 @@ function installBrowserPerformanceMonitor(report, options) {
|
|
|
2138
2107
|
url: truncate$1(name, options.maxTextLength),
|
|
2139
2108
|
startTime: typeof entry?.startTime === 'number' ? entry.startTime : undefined,
|
|
2140
2109
|
duration: typeof entry?.duration === 'number' ? entry.duration : undefined,
|
|
2110
|
+
// 时序分解(跨域资源可能为 0)
|
|
2111
|
+
dns: dns > 0 ? Math.round(dns) : undefined,
|
|
2112
|
+
tcp: tcp > 0 ? Math.round(tcp) : undefined,
|
|
2113
|
+
ttfb: ttfb > 0 ? Math.round(ttfb) : undefined,
|
|
2114
|
+
download: download > 0 ? Math.round(download) : undefined,
|
|
2115
|
+
// 缓存标记
|
|
2116
|
+
cached,
|
|
2141
2117
|
};
|
|
2142
|
-
//
|
|
2143
|
-
if (
|
|
2144
|
-
payload.transferSize =
|
|
2145
|
-
if (typeof entry?.encodedBodySize === 'number')
|
|
2118
|
+
// 尺寸字段(跨域资源可能为 0)
|
|
2119
|
+
if (transferSize > 0)
|
|
2120
|
+
payload.transferSize = transferSize;
|
|
2121
|
+
if (typeof entry?.encodedBodySize === 'number' && entry.encodedBodySize > 0) {
|
|
2146
2122
|
payload.encodedBodySize = entry.encodedBodySize;
|
|
2147
|
-
|
|
2148
|
-
|
|
2149
|
-
|
|
2123
|
+
}
|
|
2124
|
+
if (decodedBodySize > 0)
|
|
2125
|
+
payload.decodedBodySize = decodedBodySize;
|
|
2126
|
+
// 协议和状态
|
|
2127
|
+
if (typeof entry?.nextHopProtocol === 'string' && entry.nextHopProtocol) {
|
|
2150
2128
|
payload.nextHopProtocol = entry.nextHopProtocol;
|
|
2129
|
+
}
|
|
2151
2130
|
if (typeof entry?.responseStatus === 'number')
|
|
2152
2131
|
payload.status = entry.responseStatus;
|
|
2153
2132
|
report(options.reportType, payload);
|
|
@@ -2175,7 +2154,6 @@ function installWebPerformanceMonitor(report, opts = {}) {
|
|
|
2175
2154
|
sampleRate: raw.sampleRate ?? 1,
|
|
2176
2155
|
ignoreUrls: raw.ignoreUrls ?? [],
|
|
2177
2156
|
webVitals: raw.webVitals ?? true,
|
|
2178
|
-
navigationTiming: raw.navigationTiming ?? true,
|
|
2179
2157
|
resourceTiming: raw.resourceTiming ?? true,
|
|
2180
2158
|
maxTextLength: raw.maxTextLength ?? 2000,
|
|
2181
2159
|
};
|
|
@@ -2267,7 +2245,6 @@ function installMiniPerformanceMonitor(report, opts = {}) {
|
|
|
2267
2245
|
sampleRate: raw.sampleRate ?? 1,
|
|
2268
2246
|
ignoreUrls: raw.ignoreUrls ?? [],
|
|
2269
2247
|
webVitals: raw.webVitals ?? true,
|
|
2270
|
-
navigationTiming: raw.navigationTiming ?? true,
|
|
2271
2248
|
resourceTiming: raw.resourceTiming ?? true,
|
|
2272
2249
|
maxTextLength: raw.maxTextLength ?? 2000,
|
|
2273
2250
|
};
|