@be-link/cls-logger 1.0.1-beta.20 → 1.0.1-beta.22
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/web.esm.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import * as tencentcloudClsSdkJsWeb from 'tencentcloud-cls-sdk-js-web';
|
|
2
|
+
import { onFCP, onLCP, onCLS, onINP, onTTFB } from 'web-vitals';
|
|
2
3
|
|
|
3
4
|
function isPlainObject(value) {
|
|
4
5
|
return Object.prototype.toString.call(value) === '[object Object]';
|
|
@@ -1433,14 +1434,10 @@ function getPagePath() {
|
|
|
1433
1434
|
return '';
|
|
1434
1435
|
}
|
|
1435
1436
|
}
|
|
1436
|
-
|
|
1437
|
-
|
|
1438
|
-
|
|
1439
|
-
|
|
1440
|
-
value,
|
|
1441
|
-
...extra,
|
|
1442
|
-
});
|
|
1443
|
-
}
|
|
1437
|
+
/**
|
|
1438
|
+
* 安装浏览器性能监控
|
|
1439
|
+
* 使用 Google web-vitals 库实现 Core Web Vitals 指标采集
|
|
1440
|
+
*/
|
|
1444
1441
|
function installBrowserPerformanceMonitor(report, options) {
|
|
1445
1442
|
if (typeof window === 'undefined')
|
|
1446
1443
|
return;
|
|
@@ -1449,145 +1446,100 @@ function installBrowserPerformanceMonitor(report, options) {
|
|
|
1449
1446
|
return;
|
|
1450
1447
|
w.__beLinkClsLoggerPerfInstalled__ = true;
|
|
1451
1448
|
const ignoreUrls = [...DEFAULT_IGNORE, ...(options.ignoreUrls ?? [])];
|
|
1452
|
-
//
|
|
1453
|
-
|
|
1449
|
+
// Web Vitals: 使用 Google web-vitals 库
|
|
1450
|
+
// 这个库会自动处理:
|
|
1451
|
+
// - LCP 在用户交互后停止观察
|
|
1452
|
+
// - firstHiddenTime 过滤(页面隐藏后的数据不计入)
|
|
1453
|
+
// - CLS 5秒会话窗口算法
|
|
1454
|
+
// - BFCache 恢复时自动重置指标
|
|
1455
|
+
if (options.webVitals) {
|
|
1456
|
+
// FCP
|
|
1454
1457
|
try {
|
|
1455
|
-
|
|
1456
|
-
|
|
1457
|
-
|
|
1458
|
-
|
|
1459
|
-
|
|
1460
|
-
:
|
|
1461
|
-
|
|
1462
|
-
|
|
1463
|
-
|
|
1458
|
+
onFCP((metric) => {
|
|
1459
|
+
report(options.reportType, {
|
|
1460
|
+
pagePath: getPagePath(),
|
|
1461
|
+
metric: 'FCP',
|
|
1462
|
+
value: metric.value,
|
|
1463
|
+
unit: 'ms',
|
|
1464
|
+
rating: metric.rating,
|
|
1465
|
+
id: metric.id,
|
|
1466
|
+
navigationType: metric.navigationType,
|
|
1467
|
+
});
|
|
1468
|
+
});
|
|
1464
1469
|
}
|
|
1465
1470
|
catch {
|
|
1466
1471
|
// ignore
|
|
1467
1472
|
}
|
|
1468
|
-
|
|
1469
|
-
// Web Vitals: FCP/LCP/CLS/FID
|
|
1470
|
-
if (options.webVitals && typeof globalThis.PerformanceObserver === 'function') {
|
|
1471
|
-
// FCP
|
|
1473
|
+
// LCP(自动处理用户交互后停止)
|
|
1472
1474
|
try {
|
|
1473
|
-
|
|
1474
|
-
|
|
1475
|
-
|
|
1476
|
-
|
|
1477
|
-
|
|
1478
|
-
|
|
1479
|
-
|
|
1480
|
-
|
|
1481
|
-
|
|
1482
|
-
}
|
|
1483
|
-
catch {
|
|
1484
|
-
// ignore
|
|
1485
|
-
}
|
|
1475
|
+
onLCP((metric) => {
|
|
1476
|
+
report(options.reportType, {
|
|
1477
|
+
pagePath: getPagePath(),
|
|
1478
|
+
metric: 'LCP',
|
|
1479
|
+
value: metric.value,
|
|
1480
|
+
unit: 'ms',
|
|
1481
|
+
rating: metric.rating,
|
|
1482
|
+
id: metric.id,
|
|
1483
|
+
navigationType: metric.navigationType,
|
|
1484
|
+
});
|
|
1486
1485
|
});
|
|
1487
|
-
po.observe({ type: 'paint', buffered: true });
|
|
1488
1486
|
}
|
|
1489
1487
|
catch {
|
|
1490
1488
|
// ignore
|
|
1491
1489
|
}
|
|
1492
|
-
//
|
|
1493
|
-
let lastLcp = null;
|
|
1490
|
+
// CLS(自动处理会话窗口)
|
|
1494
1491
|
try {
|
|
1495
|
-
|
|
1496
|
-
|
|
1497
|
-
|
|
1498
|
-
|
|
1499
|
-
|
|
1500
|
-
|
|
1501
|
-
|
|
1502
|
-
|
|
1503
|
-
|
|
1492
|
+
onCLS((metric) => {
|
|
1493
|
+
report(options.reportType, {
|
|
1494
|
+
pagePath: getPagePath(),
|
|
1495
|
+
metric: 'CLS',
|
|
1496
|
+
value: metric.value,
|
|
1497
|
+
unit: 'score',
|
|
1498
|
+
rating: metric.rating,
|
|
1499
|
+
id: metric.id,
|
|
1500
|
+
navigationType: metric.navigationType,
|
|
1501
|
+
});
|
|
1504
1502
|
});
|
|
1505
|
-
po.observe({ type: 'largest-contentful-paint', buffered: true });
|
|
1506
|
-
const flushLcp = () => {
|
|
1507
|
-
try {
|
|
1508
|
-
if (!lastLcp)
|
|
1509
|
-
return;
|
|
1510
|
-
if (!sampleHit(options.sampleRate))
|
|
1511
|
-
return;
|
|
1512
|
-
if (typeof lastLcp.startTime === 'number')
|
|
1513
|
-
reportMetric(report, options.reportType, 'LCP', lastLcp.startTime, { unit: 'ms' });
|
|
1514
|
-
lastLcp = null;
|
|
1515
|
-
}
|
|
1516
|
-
catch {
|
|
1517
|
-
// ignore
|
|
1518
|
-
}
|
|
1519
|
-
};
|
|
1520
|
-
window.addEventListener('pagehide', flushLcp, { once: true });
|
|
1521
|
-
document.addEventListener('visibilitychange', () => {
|
|
1522
|
-
if (document.visibilityState === 'hidden')
|
|
1523
|
-
flushLcp();
|
|
1524
|
-
}, { once: true });
|
|
1525
1503
|
}
|
|
1526
1504
|
catch {
|
|
1527
1505
|
// ignore
|
|
1528
1506
|
}
|
|
1529
|
-
//
|
|
1507
|
+
// INP(替代 FID,2024年3月起成为核心指标)
|
|
1530
1508
|
try {
|
|
1531
|
-
|
|
1532
|
-
|
|
1533
|
-
|
|
1534
|
-
|
|
1535
|
-
|
|
1536
|
-
|
|
1537
|
-
|
|
1538
|
-
|
|
1539
|
-
|
|
1540
|
-
}
|
|
1541
|
-
catch {
|
|
1542
|
-
// ignore
|
|
1543
|
-
}
|
|
1509
|
+
onINP((metric) => {
|
|
1510
|
+
report(options.reportType, {
|
|
1511
|
+
pagePath: getPagePath(),
|
|
1512
|
+
metric: 'INP',
|
|
1513
|
+
value: metric.value,
|
|
1514
|
+
unit: 'ms',
|
|
1515
|
+
rating: metric.rating,
|
|
1516
|
+
id: metric.id,
|
|
1517
|
+
navigationType: metric.navigationType,
|
|
1518
|
+
});
|
|
1544
1519
|
});
|
|
1545
|
-
po.observe({ type: 'layout-shift', buffered: true });
|
|
1546
|
-
const flushCls = () => {
|
|
1547
|
-
try {
|
|
1548
|
-
if (!sampleHit(options.sampleRate))
|
|
1549
|
-
return;
|
|
1550
|
-
reportMetric(report, options.reportType, 'CLS', clsValue, { unit: 'score' });
|
|
1551
|
-
}
|
|
1552
|
-
catch {
|
|
1553
|
-
// ignore
|
|
1554
|
-
}
|
|
1555
|
-
};
|
|
1556
|
-
window.addEventListener('pagehide', flushCls, { once: true });
|
|
1557
|
-
document.addEventListener('visibilitychange', () => {
|
|
1558
|
-
if (document.visibilityState === 'hidden')
|
|
1559
|
-
flushCls();
|
|
1560
|
-
}, { once: true });
|
|
1561
1520
|
}
|
|
1562
1521
|
catch {
|
|
1563
1522
|
// ignore
|
|
1564
1523
|
}
|
|
1565
|
-
//
|
|
1524
|
+
// TTFB
|
|
1566
1525
|
try {
|
|
1567
|
-
|
|
1568
|
-
|
|
1569
|
-
|
|
1570
|
-
|
|
1571
|
-
|
|
1572
|
-
|
|
1573
|
-
|
|
1574
|
-
|
|
1575
|
-
|
|
1576
|
-
|
|
1577
|
-
}
|
|
1578
|
-
}
|
|
1579
|
-
}
|
|
1580
|
-
catch {
|
|
1581
|
-
// ignore
|
|
1582
|
-
}
|
|
1526
|
+
onTTFB((metric) => {
|
|
1527
|
+
report(options.reportType, {
|
|
1528
|
+
pagePath: getPagePath(),
|
|
1529
|
+
metric: 'TTFB',
|
|
1530
|
+
value: metric.value,
|
|
1531
|
+
unit: 'ms',
|
|
1532
|
+
rating: metric.rating,
|
|
1533
|
+
id: metric.id,
|
|
1534
|
+
navigationType: metric.navigationType,
|
|
1535
|
+
});
|
|
1583
1536
|
});
|
|
1584
|
-
po.observe({ type: 'first-input', buffered: true });
|
|
1585
1537
|
}
|
|
1586
1538
|
catch {
|
|
1587
1539
|
// ignore
|
|
1588
1540
|
}
|
|
1589
1541
|
}
|
|
1590
|
-
// Resource timing
|
|
1542
|
+
// Resource timing:资源加载耗时(web-vitals 不包含此功能,保留原有实现)
|
|
1591
1543
|
if (options.resourceTiming && typeof globalThis.PerformanceObserver === 'function') {
|
|
1592
1544
|
try {
|
|
1593
1545
|
const po = new PerformanceObserver((list) => {
|
|
@@ -1599,9 +1551,25 @@ function installBrowserPerformanceMonitor(report, options) {
|
|
|
1599
1551
|
if (!name || shouldIgnoreUrl(name, ignoreUrls))
|
|
1600
1552
|
continue;
|
|
1601
1553
|
const initiatorType = String(entry?.initiatorType ?? '');
|
|
1602
|
-
//
|
|
1554
|
+
// 关注 fetch/xhr/img/script(同时允许 css/other 但不强制)
|
|
1603
1555
|
if (!['xmlhttprequest', 'fetch', 'img', 'script', 'css'].includes(initiatorType))
|
|
1604
1556
|
continue;
|
|
1557
|
+
// 时序分解(便于定位慢在哪个阶段)
|
|
1558
|
+
const domainLookupStart = entry.domainLookupStart ?? 0;
|
|
1559
|
+
const domainLookupEnd = entry.domainLookupEnd ?? 0;
|
|
1560
|
+
const connectStart = entry.connectStart ?? 0;
|
|
1561
|
+
const connectEnd = entry.connectEnd ?? 0;
|
|
1562
|
+
const requestStart = entry.requestStart ?? 0;
|
|
1563
|
+
const responseStart = entry.responseStart ?? 0;
|
|
1564
|
+
const responseEnd = entry.responseEnd ?? 0;
|
|
1565
|
+
const dns = domainLookupEnd - domainLookupStart;
|
|
1566
|
+
const tcp = connectEnd - connectStart;
|
|
1567
|
+
const ttfb = responseStart - requestStart;
|
|
1568
|
+
const download = responseEnd - responseStart;
|
|
1569
|
+
// 缓存检测:transferSize=0 且 decodedBodySize>0 表示缓存命中
|
|
1570
|
+
const transferSize = entry.transferSize ?? 0;
|
|
1571
|
+
const decodedBodySize = entry.decodedBodySize ?? 0;
|
|
1572
|
+
const cached = transferSize === 0 && decodedBodySize > 0;
|
|
1605
1573
|
const payload = {
|
|
1606
1574
|
pagePath: getPagePath(),
|
|
1607
1575
|
metric: 'resource',
|
|
@@ -1609,16 +1577,26 @@ function installBrowserPerformanceMonitor(report, options) {
|
|
|
1609
1577
|
url: truncate$1(name, options.maxTextLength),
|
|
1610
1578
|
startTime: typeof entry?.startTime === 'number' ? entry.startTime : undefined,
|
|
1611
1579
|
duration: typeof entry?.duration === 'number' ? entry.duration : undefined,
|
|
1580
|
+
// 时序分解(跨域资源可能为 0)
|
|
1581
|
+
dns: dns > 0 ? Math.round(dns) : undefined,
|
|
1582
|
+
tcp: tcp > 0 ? Math.round(tcp) : undefined,
|
|
1583
|
+
ttfb: ttfb > 0 ? Math.round(ttfb) : undefined,
|
|
1584
|
+
download: download > 0 ? Math.round(download) : undefined,
|
|
1585
|
+
// 缓存标记
|
|
1586
|
+
cached,
|
|
1612
1587
|
};
|
|
1613
|
-
//
|
|
1614
|
-
if (
|
|
1615
|
-
payload.transferSize =
|
|
1616
|
-
if (typeof entry?.encodedBodySize === 'number')
|
|
1588
|
+
// 尺寸字段(跨域资源可能为 0)
|
|
1589
|
+
if (transferSize > 0)
|
|
1590
|
+
payload.transferSize = transferSize;
|
|
1591
|
+
if (typeof entry?.encodedBodySize === 'number' && entry.encodedBodySize > 0) {
|
|
1617
1592
|
payload.encodedBodySize = entry.encodedBodySize;
|
|
1618
|
-
|
|
1619
|
-
|
|
1620
|
-
|
|
1593
|
+
}
|
|
1594
|
+
if (decodedBodySize > 0)
|
|
1595
|
+
payload.decodedBodySize = decodedBodySize;
|
|
1596
|
+
// 协议和状态
|
|
1597
|
+
if (typeof entry?.nextHopProtocol === 'string' && entry.nextHopProtocol) {
|
|
1621
1598
|
payload.nextHopProtocol = entry.nextHopProtocol;
|
|
1599
|
+
}
|
|
1622
1600
|
if (typeof entry?.responseStatus === 'number')
|
|
1623
1601
|
payload.status = entry.responseStatus;
|
|
1624
1602
|
report(options.reportType, payload);
|
|
@@ -1646,7 +1624,6 @@ function installWebPerformanceMonitor(report, opts = {}) {
|
|
|
1646
1624
|
sampleRate: raw.sampleRate ?? 1,
|
|
1647
1625
|
ignoreUrls: raw.ignoreUrls ?? [],
|
|
1648
1626
|
webVitals: raw.webVitals ?? true,
|
|
1649
|
-
navigationTiming: raw.navigationTiming ?? true,
|
|
1650
1627
|
resourceTiming: raw.resourceTiming ?? true,
|
|
1651
1628
|
maxTextLength: raw.maxTextLength ?? 2000,
|
|
1652
1629
|
};
|
package/dist/web.js
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
4
|
|
|
5
5
|
var tencentcloudClsSdkJsWeb = require('tencentcloud-cls-sdk-js-web');
|
|
6
|
+
var webVitals = require('web-vitals');
|
|
6
7
|
|
|
7
8
|
function _interopNamespaceDefault(e) {
|
|
8
9
|
var n = Object.create(null);
|
|
@@ -1456,14 +1457,10 @@ function getPagePath() {
|
|
|
1456
1457
|
return '';
|
|
1457
1458
|
}
|
|
1458
1459
|
}
|
|
1459
|
-
|
|
1460
|
-
|
|
1461
|
-
|
|
1462
|
-
|
|
1463
|
-
value,
|
|
1464
|
-
...extra,
|
|
1465
|
-
});
|
|
1466
|
-
}
|
|
1460
|
+
/**
|
|
1461
|
+
* 安装浏览器性能监控
|
|
1462
|
+
* 使用 Google web-vitals 库实现 Core Web Vitals 指标采集
|
|
1463
|
+
*/
|
|
1467
1464
|
function installBrowserPerformanceMonitor(report, options) {
|
|
1468
1465
|
if (typeof window === 'undefined')
|
|
1469
1466
|
return;
|
|
@@ -1472,145 +1469,100 @@ function installBrowserPerformanceMonitor(report, options) {
|
|
|
1472
1469
|
return;
|
|
1473
1470
|
w.__beLinkClsLoggerPerfInstalled__ = true;
|
|
1474
1471
|
const ignoreUrls = [...DEFAULT_IGNORE, ...(options.ignoreUrls ?? [])];
|
|
1475
|
-
//
|
|
1476
|
-
|
|
1472
|
+
// Web Vitals: 使用 Google web-vitals 库
|
|
1473
|
+
// 这个库会自动处理:
|
|
1474
|
+
// - LCP 在用户交互后停止观察
|
|
1475
|
+
// - firstHiddenTime 过滤(页面隐藏后的数据不计入)
|
|
1476
|
+
// - CLS 5秒会话窗口算法
|
|
1477
|
+
// - BFCache 恢复时自动重置指标
|
|
1478
|
+
if (options.webVitals) {
|
|
1479
|
+
// FCP
|
|
1477
1480
|
try {
|
|
1478
|
-
|
|
1479
|
-
|
|
1480
|
-
|
|
1481
|
-
|
|
1482
|
-
|
|
1483
|
-
:
|
|
1484
|
-
|
|
1485
|
-
|
|
1486
|
-
|
|
1481
|
+
webVitals.onFCP((metric) => {
|
|
1482
|
+
report(options.reportType, {
|
|
1483
|
+
pagePath: getPagePath(),
|
|
1484
|
+
metric: 'FCP',
|
|
1485
|
+
value: metric.value,
|
|
1486
|
+
unit: 'ms',
|
|
1487
|
+
rating: metric.rating,
|
|
1488
|
+
id: metric.id,
|
|
1489
|
+
navigationType: metric.navigationType,
|
|
1490
|
+
});
|
|
1491
|
+
});
|
|
1487
1492
|
}
|
|
1488
1493
|
catch {
|
|
1489
1494
|
// ignore
|
|
1490
1495
|
}
|
|
1491
|
-
|
|
1492
|
-
// Web Vitals: FCP/LCP/CLS/FID
|
|
1493
|
-
if (options.webVitals && typeof globalThis.PerformanceObserver === 'function') {
|
|
1494
|
-
// FCP
|
|
1496
|
+
// LCP(自动处理用户交互后停止)
|
|
1495
1497
|
try {
|
|
1496
|
-
|
|
1497
|
-
|
|
1498
|
-
|
|
1499
|
-
|
|
1500
|
-
|
|
1501
|
-
|
|
1502
|
-
|
|
1503
|
-
|
|
1504
|
-
|
|
1505
|
-
}
|
|
1506
|
-
catch {
|
|
1507
|
-
// ignore
|
|
1508
|
-
}
|
|
1498
|
+
webVitals.onLCP((metric) => {
|
|
1499
|
+
report(options.reportType, {
|
|
1500
|
+
pagePath: getPagePath(),
|
|
1501
|
+
metric: 'LCP',
|
|
1502
|
+
value: metric.value,
|
|
1503
|
+
unit: 'ms',
|
|
1504
|
+
rating: metric.rating,
|
|
1505
|
+
id: metric.id,
|
|
1506
|
+
navigationType: metric.navigationType,
|
|
1507
|
+
});
|
|
1509
1508
|
});
|
|
1510
|
-
po.observe({ type: 'paint', buffered: true });
|
|
1511
1509
|
}
|
|
1512
1510
|
catch {
|
|
1513
1511
|
// ignore
|
|
1514
1512
|
}
|
|
1515
|
-
//
|
|
1516
|
-
let lastLcp = null;
|
|
1513
|
+
// CLS(自动处理会话窗口)
|
|
1517
1514
|
try {
|
|
1518
|
-
|
|
1519
|
-
|
|
1520
|
-
|
|
1521
|
-
|
|
1522
|
-
|
|
1523
|
-
|
|
1524
|
-
|
|
1525
|
-
|
|
1526
|
-
|
|
1515
|
+
webVitals.onCLS((metric) => {
|
|
1516
|
+
report(options.reportType, {
|
|
1517
|
+
pagePath: getPagePath(),
|
|
1518
|
+
metric: 'CLS',
|
|
1519
|
+
value: metric.value,
|
|
1520
|
+
unit: 'score',
|
|
1521
|
+
rating: metric.rating,
|
|
1522
|
+
id: metric.id,
|
|
1523
|
+
navigationType: metric.navigationType,
|
|
1524
|
+
});
|
|
1527
1525
|
});
|
|
1528
|
-
po.observe({ type: 'largest-contentful-paint', buffered: true });
|
|
1529
|
-
const flushLcp = () => {
|
|
1530
|
-
try {
|
|
1531
|
-
if (!lastLcp)
|
|
1532
|
-
return;
|
|
1533
|
-
if (!sampleHit(options.sampleRate))
|
|
1534
|
-
return;
|
|
1535
|
-
if (typeof lastLcp.startTime === 'number')
|
|
1536
|
-
reportMetric(report, options.reportType, 'LCP', lastLcp.startTime, { unit: 'ms' });
|
|
1537
|
-
lastLcp = null;
|
|
1538
|
-
}
|
|
1539
|
-
catch {
|
|
1540
|
-
// ignore
|
|
1541
|
-
}
|
|
1542
|
-
};
|
|
1543
|
-
window.addEventListener('pagehide', flushLcp, { once: true });
|
|
1544
|
-
document.addEventListener('visibilitychange', () => {
|
|
1545
|
-
if (document.visibilityState === 'hidden')
|
|
1546
|
-
flushLcp();
|
|
1547
|
-
}, { once: true });
|
|
1548
1526
|
}
|
|
1549
1527
|
catch {
|
|
1550
1528
|
// ignore
|
|
1551
1529
|
}
|
|
1552
|
-
//
|
|
1530
|
+
// INP(替代 FID,2024年3月起成为核心指标)
|
|
1553
1531
|
try {
|
|
1554
|
-
|
|
1555
|
-
|
|
1556
|
-
|
|
1557
|
-
|
|
1558
|
-
|
|
1559
|
-
|
|
1560
|
-
|
|
1561
|
-
|
|
1562
|
-
|
|
1563
|
-
}
|
|
1564
|
-
catch {
|
|
1565
|
-
// ignore
|
|
1566
|
-
}
|
|
1532
|
+
webVitals.onINP((metric) => {
|
|
1533
|
+
report(options.reportType, {
|
|
1534
|
+
pagePath: getPagePath(),
|
|
1535
|
+
metric: 'INP',
|
|
1536
|
+
value: metric.value,
|
|
1537
|
+
unit: 'ms',
|
|
1538
|
+
rating: metric.rating,
|
|
1539
|
+
id: metric.id,
|
|
1540
|
+
navigationType: metric.navigationType,
|
|
1541
|
+
});
|
|
1567
1542
|
});
|
|
1568
|
-
po.observe({ type: 'layout-shift', buffered: true });
|
|
1569
|
-
const flushCls = () => {
|
|
1570
|
-
try {
|
|
1571
|
-
if (!sampleHit(options.sampleRate))
|
|
1572
|
-
return;
|
|
1573
|
-
reportMetric(report, options.reportType, 'CLS', clsValue, { unit: 'score' });
|
|
1574
|
-
}
|
|
1575
|
-
catch {
|
|
1576
|
-
// ignore
|
|
1577
|
-
}
|
|
1578
|
-
};
|
|
1579
|
-
window.addEventListener('pagehide', flushCls, { once: true });
|
|
1580
|
-
document.addEventListener('visibilitychange', () => {
|
|
1581
|
-
if (document.visibilityState === 'hidden')
|
|
1582
|
-
flushCls();
|
|
1583
|
-
}, { once: true });
|
|
1584
1543
|
}
|
|
1585
1544
|
catch {
|
|
1586
1545
|
// ignore
|
|
1587
1546
|
}
|
|
1588
|
-
//
|
|
1547
|
+
// TTFB
|
|
1589
1548
|
try {
|
|
1590
|
-
|
|
1591
|
-
|
|
1592
|
-
|
|
1593
|
-
|
|
1594
|
-
|
|
1595
|
-
|
|
1596
|
-
|
|
1597
|
-
|
|
1598
|
-
|
|
1599
|
-
|
|
1600
|
-
}
|
|
1601
|
-
}
|
|
1602
|
-
}
|
|
1603
|
-
catch {
|
|
1604
|
-
// ignore
|
|
1605
|
-
}
|
|
1549
|
+
webVitals.onTTFB((metric) => {
|
|
1550
|
+
report(options.reportType, {
|
|
1551
|
+
pagePath: getPagePath(),
|
|
1552
|
+
metric: 'TTFB',
|
|
1553
|
+
value: metric.value,
|
|
1554
|
+
unit: 'ms',
|
|
1555
|
+
rating: metric.rating,
|
|
1556
|
+
id: metric.id,
|
|
1557
|
+
navigationType: metric.navigationType,
|
|
1558
|
+
});
|
|
1606
1559
|
});
|
|
1607
|
-
po.observe({ type: 'first-input', buffered: true });
|
|
1608
1560
|
}
|
|
1609
1561
|
catch {
|
|
1610
1562
|
// ignore
|
|
1611
1563
|
}
|
|
1612
1564
|
}
|
|
1613
|
-
// Resource timing
|
|
1565
|
+
// Resource timing:资源加载耗时(web-vitals 不包含此功能,保留原有实现)
|
|
1614
1566
|
if (options.resourceTiming && typeof globalThis.PerformanceObserver === 'function') {
|
|
1615
1567
|
try {
|
|
1616
1568
|
const po = new PerformanceObserver((list) => {
|
|
@@ -1622,9 +1574,25 @@ function installBrowserPerformanceMonitor(report, options) {
|
|
|
1622
1574
|
if (!name || shouldIgnoreUrl(name, ignoreUrls))
|
|
1623
1575
|
continue;
|
|
1624
1576
|
const initiatorType = String(entry?.initiatorType ?? '');
|
|
1625
|
-
//
|
|
1577
|
+
// 关注 fetch/xhr/img/script(同时允许 css/other 但不强制)
|
|
1626
1578
|
if (!['xmlhttprequest', 'fetch', 'img', 'script', 'css'].includes(initiatorType))
|
|
1627
1579
|
continue;
|
|
1580
|
+
// 时序分解(便于定位慢在哪个阶段)
|
|
1581
|
+
const domainLookupStart = entry.domainLookupStart ?? 0;
|
|
1582
|
+
const domainLookupEnd = entry.domainLookupEnd ?? 0;
|
|
1583
|
+
const connectStart = entry.connectStart ?? 0;
|
|
1584
|
+
const connectEnd = entry.connectEnd ?? 0;
|
|
1585
|
+
const requestStart = entry.requestStart ?? 0;
|
|
1586
|
+
const responseStart = entry.responseStart ?? 0;
|
|
1587
|
+
const responseEnd = entry.responseEnd ?? 0;
|
|
1588
|
+
const dns = domainLookupEnd - domainLookupStart;
|
|
1589
|
+
const tcp = connectEnd - connectStart;
|
|
1590
|
+
const ttfb = responseStart - requestStart;
|
|
1591
|
+
const download = responseEnd - responseStart;
|
|
1592
|
+
// 缓存检测:transferSize=0 且 decodedBodySize>0 表示缓存命中
|
|
1593
|
+
const transferSize = entry.transferSize ?? 0;
|
|
1594
|
+
const decodedBodySize = entry.decodedBodySize ?? 0;
|
|
1595
|
+
const cached = transferSize === 0 && decodedBodySize > 0;
|
|
1628
1596
|
const payload = {
|
|
1629
1597
|
pagePath: getPagePath(),
|
|
1630
1598
|
metric: 'resource',
|
|
@@ -1632,16 +1600,26 @@ function installBrowserPerformanceMonitor(report, options) {
|
|
|
1632
1600
|
url: truncate$1(name, options.maxTextLength),
|
|
1633
1601
|
startTime: typeof entry?.startTime === 'number' ? entry.startTime : undefined,
|
|
1634
1602
|
duration: typeof entry?.duration === 'number' ? entry.duration : undefined,
|
|
1603
|
+
// 时序分解(跨域资源可能为 0)
|
|
1604
|
+
dns: dns > 0 ? Math.round(dns) : undefined,
|
|
1605
|
+
tcp: tcp > 0 ? Math.round(tcp) : undefined,
|
|
1606
|
+
ttfb: ttfb > 0 ? Math.round(ttfb) : undefined,
|
|
1607
|
+
download: download > 0 ? Math.round(download) : undefined,
|
|
1608
|
+
// 缓存标记
|
|
1609
|
+
cached,
|
|
1635
1610
|
};
|
|
1636
|
-
//
|
|
1637
|
-
if (
|
|
1638
|
-
payload.transferSize =
|
|
1639
|
-
if (typeof entry?.encodedBodySize === 'number')
|
|
1611
|
+
// 尺寸字段(跨域资源可能为 0)
|
|
1612
|
+
if (transferSize > 0)
|
|
1613
|
+
payload.transferSize = transferSize;
|
|
1614
|
+
if (typeof entry?.encodedBodySize === 'number' && entry.encodedBodySize > 0) {
|
|
1640
1615
|
payload.encodedBodySize = entry.encodedBodySize;
|
|
1641
|
-
|
|
1642
|
-
|
|
1643
|
-
|
|
1616
|
+
}
|
|
1617
|
+
if (decodedBodySize > 0)
|
|
1618
|
+
payload.decodedBodySize = decodedBodySize;
|
|
1619
|
+
// 协议和状态
|
|
1620
|
+
if (typeof entry?.nextHopProtocol === 'string' && entry.nextHopProtocol) {
|
|
1644
1621
|
payload.nextHopProtocol = entry.nextHopProtocol;
|
|
1622
|
+
}
|
|
1645
1623
|
if (typeof entry?.responseStatus === 'number')
|
|
1646
1624
|
payload.status = entry.responseStatus;
|
|
1647
1625
|
report(options.reportType, payload);
|
|
@@ -1669,7 +1647,6 @@ function installWebPerformanceMonitor(report, opts = {}) {
|
|
|
1669
1647
|
sampleRate: raw.sampleRate ?? 1,
|
|
1670
1648
|
ignoreUrls: raw.ignoreUrls ?? [],
|
|
1671
1649
|
webVitals: raw.webVitals ?? true,
|
|
1672
|
-
navigationTiming: raw.navigationTiming ?? true,
|
|
1673
1650
|
resourceTiming: raw.resourceTiming ?? true,
|
|
1674
1651
|
maxTextLength: raw.maxTextLength ?? 2000,
|
|
1675
1652
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@be-link/cls-logger",
|
|
3
|
-
"version": "1.0.1-beta.
|
|
3
|
+
"version": "1.0.1-beta.22",
|
|
4
4
|
"description": "@be-link cls-logger - 腾讯云 CLS 日志上报封装",
|
|
5
5
|
"homepage": "https://github.com/snowmountain-top/be-link",
|
|
6
6
|
"author": "zhuiyi",
|
|
@@ -45,7 +45,8 @@
|
|
|
45
45
|
],
|
|
46
46
|
"dependencies": {
|
|
47
47
|
"tencentcloud-cls-sdk-js-web": "^1.0.11",
|
|
48
|
-
"tencentcloud-cls-sdk-js-mini": "^1.0.3"
|
|
48
|
+
"tencentcloud-cls-sdk-js-mini": "^1.0.3",
|
|
49
|
+
"web-vitals": "^5.1.0"
|
|
49
50
|
},
|
|
50
51
|
"devDependencies": {
|
|
51
52
|
"rimraf": "^5.0.0",
|