@camstack/server 1.2.48 → 1.2.49
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.
|
@@ -54,6 +54,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
54
54
|
exports.acceptsBrotli = acceptsBrotli;
|
|
55
55
|
exports.isCompressibleAsset = isCompressibleAsset;
|
|
56
56
|
exports.resolvePrecompressedAsset = resolvePrecompressedAsset;
|
|
57
|
+
exports.warmPrecompressedAssets = warmPrecompressedAssets;
|
|
57
58
|
exports.resetPrecompressedWarning = resetPrecompressedWarning;
|
|
58
59
|
exports.precompressedSiblingExists = precompressedSiblingExists;
|
|
59
60
|
const fs = __importStar(require("node:fs"));
|
|
@@ -166,6 +167,50 @@ async function resolvePrecompressedAsset(filePath, acceptEncoding, log) {
|
|
|
166
167
|
inFlight.delete(filePath);
|
|
167
168
|
}
|
|
168
169
|
}
|
|
170
|
+
/**
|
|
171
|
+
* Compress a dist's assets in the background, so no CLIENT pays for the first
|
|
172
|
+
* one.
|
|
173
|
+
*
|
|
174
|
+
* Measured on the live hub: the viewer's 5 MB bundle takes 6.7 s at quality 11.
|
|
175
|
+
* Every request after it is served in 14 ms — but without this, one unlucky
|
|
176
|
+
* operator right after a deploy waits those 6.7 s, which is WORSE than the
|
|
177
|
+
* 0.6 s the per-request compression used to cost. Warming turns a cliff into a
|
|
178
|
+
* bit of boot-time CPU nobody is waiting on.
|
|
179
|
+
*
|
|
180
|
+
* Deliberately not awaited by the caller, and deliberately serial: this runs
|
|
181
|
+
* while the hub is booting the rest of itself, and saturating the CPU to make
|
|
182
|
+
* a page load faster would be a bad trade. Failures are silent here — the
|
|
183
|
+
* request path logs them if it ever hits one.
|
|
184
|
+
*/
|
|
185
|
+
function warmPrecompressedAssets(root, log) {
|
|
186
|
+
void (async () => {
|
|
187
|
+
let warmed = 0;
|
|
188
|
+
for (const file of await listCompressible(root)) {
|
|
189
|
+
const resolved = await resolvePrecompressedAsset(file, 'br').catch(() => null);
|
|
190
|
+
if (resolved?.encoding === 'br')
|
|
191
|
+
warmed += 1;
|
|
192
|
+
}
|
|
193
|
+
if (warmed > 0)
|
|
194
|
+
log?.('warmed the precompressed asset cache', { root, files: warmed });
|
|
195
|
+
})();
|
|
196
|
+
}
|
|
197
|
+
async function listCompressible(dir, out = []) {
|
|
198
|
+
let entries;
|
|
199
|
+
try {
|
|
200
|
+
entries = await fsp.readdir(dir, { withFileTypes: true });
|
|
201
|
+
}
|
|
202
|
+
catch {
|
|
203
|
+
return out;
|
|
204
|
+
}
|
|
205
|
+
for (const entry of entries) {
|
|
206
|
+
const full = path.join(dir, entry.name);
|
|
207
|
+
if (entry.isDirectory())
|
|
208
|
+
await listCompressible(full, out);
|
|
209
|
+
else if (isCompressibleAsset(entry.name) && !entry.name.endsWith('.br'))
|
|
210
|
+
out.push(full);
|
|
211
|
+
}
|
|
212
|
+
return out;
|
|
213
|
+
}
|
|
169
214
|
/** Test seam — the "read-only dist" warning is once per process. */
|
|
170
215
|
function resetPrecompressedWarning() {
|
|
171
216
|
warnedUnwritable = false;
|
package/dist/main.js
CHANGED
|
@@ -1136,6 +1136,10 @@ async function bootstrap() {
|
|
|
1136
1136
|
reply.header('cache-control', 'no-cache, must-revalidate');
|
|
1137
1137
|
return reply.type('text/html').send(fs.createReadStream(spaIndexHtml));
|
|
1138
1138
|
});
|
|
1139
|
+
// Compress the dist in the background so the first CLIENT does not pay
|
|
1140
|
+
// for it — a 5 MB bundle takes ~6.7s at quality 11, and that is a worse
|
|
1141
|
+
// first load than the per-request compression this replaced.
|
|
1142
|
+
(0, precompressed_asset_js_1.warmPrecompressedAssets)(staticDir, (msg, meta) => console.log(`[static] ${msg} ${JSON.stringify(meta)}`));
|
|
1139
1143
|
const { version } = await adminUI.getVersion();
|
|
1140
1144
|
console.log(`[bootstrap] Admin UI served from: ${staticDir} (v${version})`);
|
|
1141
1145
|
}
|
|
@@ -1215,6 +1219,7 @@ async function bootstrap() {
|
|
|
1215
1219
|
reply.header('cache-control', 'no-cache, must-revalidate');
|
|
1216
1220
|
return reply.type('text/html').send(fs.createReadStream(indexPath));
|
|
1217
1221
|
});
|
|
1222
|
+
(0, precompressed_asset_js_1.warmPrecompressedAssets)(staticDir, (msg, meta) => console.log(`[static] ${msg} ${JSON.stringify(meta)}`));
|
|
1218
1223
|
const { version } = await viewerUI.getVersion();
|
|
1219
1224
|
console.log(`[bootstrap] Viewer UI served from: ${staticDir} at ${VIEWER_MOUNT} (v${version})`);
|
|
1220
1225
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@camstack/server",
|
|
3
|
-
"version": "1.2.
|
|
3
|
+
"version": "1.2.49",
|
|
4
4
|
"private": false,
|
|
5
5
|
"files": [
|
|
6
6
|
"dist",
|
|
@@ -39,7 +39,7 @@
|
|
|
39
39
|
"@camstack/addon-decoder-nodeav": "1.2.9",
|
|
40
40
|
"@camstack/addon-notifiers": "1.2.12",
|
|
41
41
|
"@camstack/addon-pipeline": "1.2.40",
|
|
42
|
-
"@camstack/addon-pipeline-orchestrator": "1.2.
|
|
42
|
+
"@camstack/addon-pipeline-orchestrator": "1.2.22",
|
|
43
43
|
"@camstack/addon-post-analysis": "1.2.31",
|
|
44
44
|
"@camstack/sdk": "1.2.9",
|
|
45
45
|
"@camstack/shm-ring": "1.1.9",
|