@spinajs/templates-puppeteer 2.0.481 → 2.0.482

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.
@@ -0,0 +1,175 @@
1
+ import { RenderPhase } from '@spinajs/templates';
2
+ /** Minimum gap between resource-driven emissions (ms). */
3
+ const THROTTLE_MS = 150;
4
+ /** Re-emit interval during long phases so the bar moves even when nothing changes (ms). */
5
+ const HEARTBEAT_MS = 750;
6
+ /** Percent band [start, end] each phase occupies. */
7
+ const PHASE_BANDS = {
8
+ [RenderPhase.Starting]: [0, 10],
9
+ [RenderPhase.Preparing]: [10, 15],
10
+ [RenderPhase.Loading]: [15, 80],
11
+ [RenderPhase.Rendering]: [80, 95],
12
+ [RenderPhase.Done]: [100, 100],
13
+ [RenderPhase.Failed]: [0, 0],
14
+ };
15
+ /**
16
+ * Tracks a single puppeteer render and delivers throttled {@link IRenderProgress}
17
+ * snapshots to a callback. Resource counts come from the page's request lifecycle
18
+ * events; the percentage is phase-weighted (see {@link PHASE_BANDS}), and a
19
+ * heartbeat keeps it ticking during the long Loading/Rendering phases.
20
+ *
21
+ * When constructed without a callback it is entirely inert - no listeners, no
22
+ * timers, no allocations on the hot path - so callers can always create one.
23
+ */
24
+ export class RenderProgressReporter {
25
+ constructor(filePath, callback) {
26
+ this.filePath = filePath;
27
+ this.startedAt = Date.now();
28
+ this.phaseNow = RenderPhase.Starting;
29
+ this.loaded = 0;
30
+ this.pending = 0;
31
+ this.failed = 0;
32
+ this.lastEmitAt = 0;
33
+ this.lastPercent = 0;
34
+ this.heartbeat = null;
35
+ this.page = null;
36
+ // pre-bound so add/remove reference the same function identities
37
+ this.onRequest = () => {
38
+ this.pending++;
39
+ };
40
+ this.onRequestFinished = () => {
41
+ this.pending = Math.max(0, this.pending - 1);
42
+ this.loaded++;
43
+ this.emit();
44
+ };
45
+ this.onRequestFailed = () => {
46
+ this.pending = Math.max(0, this.pending - 1);
47
+ this.failed++;
48
+ this.emit();
49
+ };
50
+ this.enabled = !!callback;
51
+ this.callback = callback ?? (() => undefined);
52
+ }
53
+ /** Attach resource-lifecycle counters to the page. Call once, after newPage(). */
54
+ attach(page) {
55
+ if (!this.enabled) {
56
+ return;
57
+ }
58
+ this.page = page;
59
+ page.on('request', this.onRequest);
60
+ page.on('requestfinished', this.onRequestFinished);
61
+ page.on('requestfailed', this.onRequestFailed);
62
+ }
63
+ /** Transition to a new phase and emit immediately (bypassing the throttle). */
64
+ phase(phase, message) {
65
+ if (!this.enabled) {
66
+ return;
67
+ }
68
+ this.phaseNow = phase;
69
+ // Heartbeat only during the phases that can take a long time.
70
+ if (phase === RenderPhase.Loading || phase === RenderPhase.Rendering) {
71
+ this.startHeartbeat();
72
+ }
73
+ else {
74
+ this.stopHeartbeat();
75
+ }
76
+ this.emit(message, true);
77
+ }
78
+ /** Stop the heartbeat and detach page listeners. Safe to call multiple times. */
79
+ dispose() {
80
+ this.stopHeartbeat();
81
+ if (this.page) {
82
+ this.page.off('request', this.onRequest);
83
+ this.page.off('requestfinished', this.onRequestFinished);
84
+ this.page.off('requestfailed', this.onRequestFailed);
85
+ this.page = null;
86
+ }
87
+ }
88
+ startHeartbeat() {
89
+ if (this.heartbeat) {
90
+ return;
91
+ }
92
+ this.heartbeat = setInterval(() => this.emit(), HEARTBEAT_MS);
93
+ // never keep the process alive just to tick progress
94
+ this.heartbeat.unref?.();
95
+ }
96
+ stopHeartbeat() {
97
+ if (this.heartbeat) {
98
+ clearInterval(this.heartbeat);
99
+ this.heartbeat = null;
100
+ }
101
+ }
102
+ computePercent() {
103
+ if (this.phaseNow === RenderPhase.Failed) {
104
+ return this.lastPercent;
105
+ }
106
+ const [start, end] = PHASE_BANDS[this.phaseNow];
107
+ if (this.phaseNow === RenderPhase.Loading) {
108
+ // total is unknown up front; approximate with completed / seen-so-far
109
+ const seen = this.loaded + this.pending;
110
+ const ratio = seen > 0 ? this.loaded / seen : 0;
111
+ return Math.max(this.lastPercent, Math.min(end, Math.round(start + (end - start) * ratio)));
112
+ }
113
+ // milestone phases sit at their band start (Done -> 100); never regress
114
+ return Math.max(this.lastPercent, start);
115
+ }
116
+ emit(message, force = false) {
117
+ if (!this.enabled) {
118
+ return;
119
+ }
120
+ const now = Date.now();
121
+ if (!force && now - this.lastEmitAt < THROTTLE_MS) {
122
+ return;
123
+ }
124
+ this.lastEmitAt = now;
125
+ const percent = this.computePercent();
126
+ this.lastPercent = percent;
127
+ const progress = {
128
+ phase: this.phaseNow,
129
+ percent,
130
+ resourcesLoaded: this.loaded,
131
+ resourcesPending: this.pending,
132
+ resourcesFailed: this.failed,
133
+ elapsedMs: now - this.startedAt,
134
+ filePath: this.filePath,
135
+ message: message ?? this.defaultMessage(),
136
+ };
137
+ // progress must never stall or break a render: don't await, swallow errors
138
+ try {
139
+ const result = this.callback(progress);
140
+ if (result && typeof result.then === 'function') {
141
+ result.catch(() => {
142
+ /* swallow async listener errors */
143
+ });
144
+ }
145
+ }
146
+ catch {
147
+ /* swallow sync listener errors */
148
+ }
149
+ }
150
+ defaultMessage() {
151
+ switch (this.phaseNow) {
152
+ case RenderPhase.Starting:
153
+ return 'Starting renderer';
154
+ case RenderPhase.Preparing:
155
+ return 'Preparing HTML';
156
+ case RenderPhase.Loading: {
157
+ const extra = [`${this.loaded} done`];
158
+ if (this.pending)
159
+ extra.push(`${this.pending} pending`);
160
+ if (this.failed)
161
+ extra.push(`${this.failed} failed`);
162
+ return `Loading resources (${extra.join(', ')})`;
163
+ }
164
+ case RenderPhase.Rendering:
165
+ return 'Generating output';
166
+ case RenderPhase.Done:
167
+ return 'Done';
168
+ case RenderPhase.Failed:
169
+ return 'Failed';
170
+ default:
171
+ return '';
172
+ }
173
+ }
174
+ }
175
+ //# sourceMappingURL=progress.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"progress.js","sourceRoot":"","sources":["../../src/progress.ts"],"names":[],"mappings":"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"}