next
Version:
The React Framework
171 lines (170 loc) • 6.44 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
0 && (module.exports = {
ClientComponentLoadTracker: null,
getClientComponentLoaderMetrics: null,
wrapClientComponentLoader: null
});
function _export(target, all) {
for(var name in all)Object.defineProperty(target, name, {
enumerable: true,
get: all[name]
});
}
_export(exports, {
ClientComponentLoadTracker: function() {
return ClientComponentLoadTracker;
},
getClientComponentLoaderMetrics: function() {
return getClientComponentLoaderMetrics;
},
wrapClientComponentLoader: function() {
return wrapClientComponentLoader;
}
});
const _workasyncstorageexternal = require("./app-render/work-async-storage.external");
class ClientComponentLoadTracker {
constructor(report = ()=>{}){
this.report = report;
this.clientComponentLoadStart = 0;
this.clientComponentLoadEnd = 0;
this.clientComponentLoadTimes = 0;
this.clientComponentLoadCount = 0;
this.hasLoads = false;
this.pending = 0;
this.sealed = false;
this.resolveCompletion = undefined;
}
isSealed() {
return this.sealed;
}
beginRequire(startTime) {
this.recordStart(startTime);
this.clientComponentLoadCount++;
this.pending++;
}
finishRequire(startTime, endTime) {
this.recordSettlement(startTime, endTime);
}
beginChunk(startTime) {
this.recordStart(startTime);
this.pending++;
}
finishChunk(startTime, endTime) {
this.recordSettlement(startTime, endTime);
}
snapshot() {
if (!this.hasLoads) {
return undefined;
}
return {
clientComponentLoadStart: this.clientComponentLoadStart,
clientComponentLoadEnd: this.clientComponentLoadEnd,
clientComponentLoadTimes: this.clientComponentLoadTimes,
clientComponentLoadCount: this.clientComponentLoadCount
};
}
/** Stop accepting new loads and report after any in-flight loads settle. */ finish() {
if (this.sealed) return;
this.sealed = true;
let completion;
if (this.pending === 0) {
completion = Promise.resolve(this.snapshot());
} else {
completion = new Promise((resolve)=>{
this.resolveCompletion = resolve;
});
}
// Telemetry is best-effort and must not keep the response open or mask a
// render error, including when reporting fails.
void completion.then(this.report).catch((error)=>{
console.error('Failed to report client component loading metrics:', error);
});
}
recordStart(startTime) {
if (!this.hasLoads) {
this.hasLoads = true;
this.clientComponentLoadStart = startTime;
}
}
recordSettlement(startTime, endTime) {
this.clientComponentLoadEnd = endTime;
this.clientComponentLoadTimes += endTime - startTime;
this.pending--;
if (this.sealed && this.pending === 0 && this.resolveCompletion) {
const resolve = this.resolveCompletion;
this.resolveCompletion = undefined;
resolve(this.snapshot());
}
}
}
function wrapClientComponentLoader(ComponentMod) {
if (!('performance' in globalThis)) {
return ComponentMod.__next_app__;
}
return {
require: (...args)=>{
var _workAsyncStorage_getStore;
const tracker = (_workAsyncStorage_getStore = _workasyncstorageexternal.workAsyncStorage.getStore()) == null ? void 0 : _workAsyncStorage_getStore.clientComponentLoadTracker;
if (tracker === undefined || tracker.isSealed()) {
return ComponentMod.__next_app__.require(...args);
}
const startTime = performance.now();
tracker.beginRequire(startTime);
let result;
try {
result = ComponentMod.__next_app__.require(...args);
} catch (error) {
tracker.finishRequire(startTime, performance.now());
throw error;
}
// Webpack and Turbopack return native Promises for async modules. A
// synchronous module may export `then`, so do not probe arbitrary exports.
if (result instanceof Promise) {
const onSettled = ()=>{
tracker.finishRequire(startTime, performance.now());
};
result.then(onSettled, onSettled);
} else {
tracker.finishRequire(startTime, performance.now());
}
return result;
},
loadChunk: (...args)=>{
var _workAsyncStorage_getStore;
const tracker = (_workAsyncStorage_getStore = _workasyncstorageexternal.workAsyncStorage.getStore()) == null ? void 0 : _workAsyncStorage_getStore.clientComponentLoadTracker;
if (tracker === undefined || tracker.isSealed()) {
return ComponentMod.__next_app__.loadChunk(...args);
}
const startTime = performance.now();
tracker.beginChunk(startTime);
let result;
try {
result = ComponentMod.__next_app__.loadChunk(...args);
} catch (error) {
tracker.finishChunk(startTime, performance.now());
throw error;
}
// React can depend on the original promise identity.
const onSettled = ()=>{
tracker.finishChunk(startTime, performance.now());
};
result.then(onSettled, onSettled);
return result;
}
};
}
function getClientComponentLoaderMetrics(options = {}) {
const workStore = _workasyncstorageexternal.workAsyncStorage.getStore();
const tracker = workStore == null ? void 0 : workStore.clientComponentLoadTracker;
const metrics = tracker == null ? void 0 : tracker.snapshot();
if (options.reset && workStore) {
// Pending settlements still hold their original tracker. Detaching it only
// affects subsequent reads and loads in this render.
workStore.clientComponentLoadTracker = undefined;
}
return metrics;
}
//# sourceMappingURL=client-component-renderer-logger.js.map