leglas 0.8.0 → 0.9.0
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 +14 -5
- package/dist/bin.js +62 -5
- package/dist/index.js +62 -5
- package/dist/shell/assets/index-BMpAHiSA.js +14 -0
- package/dist/shell/assets/index-pfmBGQQ0.css +1 -0
- package/dist/shell/index.html +2 -2
- package/package.json +1 -1
- package/dist/shell/assets/index-CpYCCElH.css +0 -1
- package/dist/shell/assets/index-Ct9pp-D-.js +0 -14
package/README.md
CHANGED
|
@@ -12,6 +12,7 @@
|
|
|
12
12
|
<a href="https://www.npmjs.com/package/leglas"><img src="https://img.shields.io/npm/v/leglas" alt="npm"></a>
|
|
13
13
|
<a href="https://github.com/FredAmartey/leglas/actions/workflows/ci.yml"><img src="https://github.com/FredAmartey/leglas/actions/workflows/ci.yml/badge.svg" alt="CI"></a>
|
|
14
14
|
<a href="LICENSE"><img src="https://img.shields.io/npm/l/leglas" alt="license"></a>
|
|
15
|
+
<a href="https://leglas.vercel.app/changelog/"><img src="https://img.shields.io/badge/changelog-what's%20new-0B1839" alt="changelog"></a>
|
|
15
16
|
</p>
|
|
16
17
|
|
|
17
18
|
<p align="center">
|
|
@@ -534,6 +535,7 @@ pnpm install
|
|
|
534
535
|
pnpm build # build every package
|
|
535
536
|
pnpm test # run the test suite
|
|
536
537
|
pnpm typecheck # type check every package
|
|
538
|
+
pnpm site # build the site, homepage and changelog, into dist/site
|
|
537
539
|
```
|
|
538
540
|
|
|
539
541
|
| Package | Contents |
|
|
@@ -549,11 +551,18 @@ terminal and `pnpm --filter @leglas/shell dev` in another.
|
|
|
549
551
|
Two packages are published, both unscoped: `leglas`, which bundles the
|
|
550
552
|
server and the built interface, and `leglas-mcp`. Releases are
|
|
551
553
|
tag-driven: set the same version in both packages and `plugin.json`, turn
|
|
552
|
-
the changelog's Unreleased section into that version
|
|
553
|
-
tag, and CI runs the suite and
|
|
554
|
-
A tag that disagrees with the
|
|
555
|
-
when `api-surface.txt` has
|
|
556
|
-
exists anywhere in the project.
|
|
554
|
+
the changelog's Unreleased section into that version with a title for what
|
|
555
|
+
the release was about, push a `v<version>` tag, and CI runs the suite and
|
|
556
|
+
publishes through npm trusted publishing. A tag that disagrees with the
|
|
557
|
+
manifests is refused, and so is a patch tag when `api-surface.txt` has
|
|
558
|
+
moved since the previous one. No npm token exists anywhere in the project.
|
|
559
|
+
|
|
560
|
+
The [site](https://leglas.vercel.app/) is two pages, the homepage and the
|
|
561
|
+
[changelog](https://leglas.vercel.app/changelog/), written by `site.ts`. The
|
|
562
|
+
changelog page is made from `CHANGELOG.md` and nothing else, so describing a
|
|
563
|
+
release in the changelog is the whole job. Vercel builds it from
|
|
564
|
+
`vercel.json` on every push, so main is the live site and every pull request
|
|
565
|
+
gets a preview.
|
|
557
566
|
|
|
558
567
|
## License
|
|
559
568
|
|
package/dist/bin.js
CHANGED
|
@@ -2211,6 +2211,32 @@ function createBrowserPool(options = {}) {
|
|
|
2211
2211
|
};
|
|
2212
2212
|
}
|
|
2213
2213
|
|
|
2214
|
+
// ../server/dist/hydration.js
|
|
2215
|
+
function hydrationEvidence(messages) {
|
|
2216
|
+
for (const raw of messages) {
|
|
2217
|
+
const message2 = raw.split("\n", 1)[0]?.trim() ?? "";
|
|
2218
|
+
if (/Minified React error #(418|419|422|423|425)\b/.test(message2)) {
|
|
2219
|
+
return { framework: "React", message: message2 };
|
|
2220
|
+
}
|
|
2221
|
+
if (/Hydration failed because/.test(message2) || /error while hydrating/i.test(message2) || /Text content (did not|does not) match/i.test(message2) || /Expected server HTML to contain/i.test(message2) || /did not match\. Server:/.test(message2)) {
|
|
2222
|
+
return { framework: "React", message: message2 };
|
|
2223
|
+
}
|
|
2224
|
+
if (/Hydration (node|text|children|class|style|attribute) mismatch/i.test(message2) || /Hydration completed but contains mismatches/i.test(message2)) {
|
|
2225
|
+
return { framework: "Vue", message: message2 };
|
|
2226
|
+
}
|
|
2227
|
+
if (/hydration_mismatch/.test(message2)) {
|
|
2228
|
+
return { framework: "Svelte", message: message2 };
|
|
2229
|
+
}
|
|
2230
|
+
if (/Hydration Mismatch\. Unable to find DOM nodes/.test(message2)) {
|
|
2231
|
+
return { framework: "Solid", message: message2 };
|
|
2232
|
+
}
|
|
2233
|
+
if (/hydrat/i.test(message2) && (/expected .+ but found/i.test(message2) || /mismatch/i.test(message2) && /(node|element|markup|dom|tag|text|attribute|server|client)/i.test(message2))) {
|
|
2234
|
+
return { framework: "the app", message: message2 };
|
|
2235
|
+
}
|
|
2236
|
+
}
|
|
2237
|
+
return null;
|
|
2238
|
+
}
|
|
2239
|
+
|
|
2214
2240
|
// ../server/dist/capture.js
|
|
2215
2241
|
var FRAME_MAX_HEIGHT = 4e3;
|
|
2216
2242
|
var MIN_WIDTH = 320;
|
|
@@ -2304,10 +2330,12 @@ function locatorExpression(focus) {
|
|
|
2304
2330
|
async function render(page, input) {
|
|
2305
2331
|
const width = clamp(Math.round(input.width), MIN_WIDTH, MAX_WIDTH);
|
|
2306
2332
|
const errors = [];
|
|
2333
|
+
let hydration = null;
|
|
2307
2334
|
const remember = (value) => {
|
|
2335
|
+
const message2 = String(value ?? "").trim().slice(0, 240);
|
|
2336
|
+
hydration ??= hydrationEvidence([message2]);
|
|
2308
2337
|
if (errors.length >= 10)
|
|
2309
2338
|
return;
|
|
2310
|
-
const message2 = String(value ?? "").slice(0, 240);
|
|
2311
2339
|
if (message2 === "" || /favicon/i.test(message2))
|
|
2312
2340
|
return;
|
|
2313
2341
|
errors.push(message2);
|
|
@@ -2455,7 +2483,7 @@ async function render(page, input) {
|
|
|
2455
2483
|
resolved
|
|
2456
2484
|
});
|
|
2457
2485
|
}
|
|
2458
|
-
return { frame, crops, errors, cut };
|
|
2486
|
+
return { frame, crops, errors, hydration, cut };
|
|
2459
2487
|
} finally {
|
|
2460
2488
|
for (const stop of unlisten)
|
|
2461
2489
|
stop();
|
|
@@ -2599,7 +2627,13 @@ async function attachRequest(cwd, requestId, input, deps) {
|
|
|
2599
2627
|
const capture = deps.capture ?? capturePage;
|
|
2600
2628
|
const deadlineMs = deps.deadlineMs ?? 12e3;
|
|
2601
2629
|
const destination = join5(cwd, CAPTURES_DIR, requestId);
|
|
2602
|
-
const captured = {
|
|
2630
|
+
const captured = {
|
|
2631
|
+
attachments: [],
|
|
2632
|
+
errors: [],
|
|
2633
|
+
hydration: null,
|
|
2634
|
+
cut: false,
|
|
2635
|
+
skipped: null
|
|
2636
|
+
};
|
|
2603
2637
|
const references = [];
|
|
2604
2638
|
requestedWidths.set(captured, Math.min(MAX_WIDTH, Math.max(MIN_WIDTH, Math.round(input.width))));
|
|
2605
2639
|
const controller = new AbortController();
|
|
@@ -2649,6 +2683,7 @@ async function attachRequest(cwd, requestId, input, deps) {
|
|
|
2649
2683
|
viewport: direction.frame.width
|
|
2650
2684
|
});
|
|
2651
2685
|
captured.errors = direction.errors;
|
|
2686
|
+
captured.hydration = direction.hydration;
|
|
2652
2687
|
captured.cut = direction.cut;
|
|
2653
2688
|
for (let index = 0; index < direction.crops.length; index += 1) {
|
|
2654
2689
|
const crop = direction.crops[index];
|
|
@@ -3344,10 +3379,10 @@ function scope(leglasCommand, quotedTitle) {
|
|
|
3344
3379
|
|
|
3345
3380
|
This is a scoped design change: no test run, no build, and no survey of the rest of the project is needed. The result is checked visually in a live preview, not by tooling.
|
|
3346
3381
|
|
|
3347
|
-
Leave every other direction exactly as it is; they are alternatives being compared side by side, so changing a sibling destroys the comparison. Keep the change additive: do not rewrite shared components that other directions rely on.`;
|
|
3382
|
+
Leave every other direction exactly as it is; they are alternatives being compared side by side, so changing a sibling destroys the comparison. Keep the change additive: do not rewrite shared components that other directions rely on. A shared script may gain one small per-direction override, at the point it reads what it renders, that defaults to what it renders today; every other direction then renders exactly as before, so that counts as additive.`;
|
|
3348
3383
|
}
|
|
3349
3384
|
function capturedBlock(captured) {
|
|
3350
|
-
if (captured === null || captured.attachments.length === 0 && captured.errors.length === 0 && captured.skipped === null)
|
|
3385
|
+
if (captured === null || captured.attachments.length === 0 && captured.errors.length === 0 && captured.hydration === null && captured.skipped === null)
|
|
3351
3386
|
return "";
|
|
3352
3387
|
const lines2 = [];
|
|
3353
3388
|
const frames = captured.attachments.filter((attachment) => attachment.kind === "frame" || attachment.kind === "note");
|
|
@@ -3379,6 +3414,9 @@ function capturedBlock(captured) {
|
|
|
3379
3414
|
for (const error of captured.errors)
|
|
3380
3415
|
lines2.push(` - ${error}`);
|
|
3381
3416
|
}
|
|
3417
|
+
if (captured.hydration !== null) {
|
|
3418
|
+
lines2.push(`After load, ${captured.hydration.framework} rebuilt this page in the browser from the app's own JavaScript and data (${captured.hydration.message}). Markup edited in the served HTML shows for a moment and is then replaced, so make the change where that JavaScript gets what it renders: the data or source it reads, or a per-direction override that a shared script reads with the original as its default. Look at the result a few seconds after load, not at first paint.`);
|
|
3419
|
+
}
|
|
3382
3420
|
if (captured.skipped !== null) {
|
|
3383
3421
|
lines2.push(`(${captured.skipped} Use the live preview instead.)`);
|
|
3384
3422
|
}
|
|
@@ -6060,6 +6098,7 @@ async function startServer(options) {
|
|
|
6060
6098
|
height: shot.height,
|
|
6061
6099
|
viewport: result2.frame.width,
|
|
6062
6100
|
errors: result2.errors,
|
|
6101
|
+
hydration: result2.hydration,
|
|
6063
6102
|
cut: result2.cut
|
|
6064
6103
|
});
|
|
6065
6104
|
} catch (error) {
|
|
@@ -6803,6 +6842,14 @@ When asked for design variations, alternatives, or "a few options":
|
|
|
6803
6842
|
and register it with \`npx leglas add --title "\u2026" --url "/" --branch <branch>\`
|
|
6804
6843
|
(the config needs \`devCommand\` with \`{port}\`). Everything below is the
|
|
6805
6844
|
ordinary, in-app path.
|
|
6845
|
+
A page the app rebuilds in the browser after load (anything that hydrates:
|
|
6846
|
+
Next, Nuxt, SvelteKit, a captured production site) is not its served HTML.
|
|
6847
|
+
Markup edited there shows for a moment and is then replaced from the app's
|
|
6848
|
+
own JavaScript and data, so make the change where that JavaScript gets what
|
|
6849
|
+
it renders. When that is a script other directions share, give it a
|
|
6850
|
+
per-direction override that defaults to what it renders today: every other
|
|
6851
|
+
direction renders exactly as before, which is adding beside, not rewriting.
|
|
6852
|
+
\`npx leglas show\` says when a page was rebuilt after load.
|
|
6806
6853
|
2. Run \`npx leglas explore <surface> --count <n>\` first, adding
|
|
6807
6854
|
\`--based-on "<title>"\` when the user wants variations of a direction they
|
|
6808
6855
|
already like. It prints what the set needs and how to register it. In
|
|
@@ -7566,6 +7613,10 @@ async function runShow(options, deps) {
|
|
|
7566
7613
|
height: captured.height,
|
|
7567
7614
|
viewport: captured.viewport,
|
|
7568
7615
|
errors: Array.isArray(captured.errors) ? captured.errors.filter((error) => typeof error === "string") : [],
|
|
7616
|
+
hydration: typeof captured.hydration === "object" && captured.hydration !== null && typeof captured.hydration.framework === "string" && typeof captured.hydration.message === "string" ? {
|
|
7617
|
+
framework: captured.hydration.framework,
|
|
7618
|
+
message: captured.hydration.message
|
|
7619
|
+
} : null,
|
|
7569
7620
|
cut: captured.cut === true
|
|
7570
7621
|
};
|
|
7571
7622
|
}
|
|
@@ -7593,6 +7644,12 @@ async function runShow(options, deps) {
|
|
|
7593
7644
|
if (envelope2.screenshot.cut) {
|
|
7594
7645
|
deps.log(" the top of the page only; it is taller than one capture");
|
|
7595
7646
|
}
|
|
7647
|
+
if (envelope2.screenshot.hydration !== null) {
|
|
7648
|
+
deps.log(
|
|
7649
|
+
` hydration ${envelope2.screenshot.hydration.framework} rebuilt the page in the browser after load; the served markup is not what is on screen`
|
|
7650
|
+
);
|
|
7651
|
+
deps.log(` ${envelope2.screenshot.hydration.message}`);
|
|
7652
|
+
}
|
|
7596
7653
|
if (envelope2.screenshot.errors.length > 0) {
|
|
7597
7654
|
const count = envelope2.screenshot.errors.length;
|
|
7598
7655
|
deps.log(` console ${count} ${count === 1 ? "error" : "errors"} on load`);
|
package/dist/index.js
CHANGED
|
@@ -688,6 +688,14 @@ When asked for design variations, alternatives, or "a few options":
|
|
|
688
688
|
and register it with \`npx leglas add --title "\u2026" --url "/" --branch <branch>\`
|
|
689
689
|
(the config needs \`devCommand\` with \`{port}\`). Everything below is the
|
|
690
690
|
ordinary, in-app path.
|
|
691
|
+
A page the app rebuilds in the browser after load (anything that hydrates:
|
|
692
|
+
Next, Nuxt, SvelteKit, a captured production site) is not its served HTML.
|
|
693
|
+
Markup edited there shows for a moment and is then replaced from the app's
|
|
694
|
+
own JavaScript and data, so make the change where that JavaScript gets what
|
|
695
|
+
it renders. When that is a script other directions share, give it a
|
|
696
|
+
per-direction override that defaults to what it renders today: every other
|
|
697
|
+
direction renders exactly as before, which is adding beside, not rewriting.
|
|
698
|
+
\`npx leglas show\` says when a page was rebuilt after load.
|
|
691
699
|
2. Run \`npx leglas explore <surface> --count <n>\` first, adding
|
|
692
700
|
\`--based-on "<title>"\` when the user wants variations of a direction they
|
|
693
701
|
already like. It prints what the set needs and how to register it. In
|
|
@@ -2593,6 +2601,32 @@ function createBrowserPool(options = {}) {
|
|
|
2593
2601
|
};
|
|
2594
2602
|
}
|
|
2595
2603
|
|
|
2604
|
+
// ../server/dist/hydration.js
|
|
2605
|
+
function hydrationEvidence(messages) {
|
|
2606
|
+
for (const raw of messages) {
|
|
2607
|
+
const message2 = raw.split("\n", 1)[0]?.trim() ?? "";
|
|
2608
|
+
if (/Minified React error #(418|419|422|423|425)\b/.test(message2)) {
|
|
2609
|
+
return { framework: "React", message: message2 };
|
|
2610
|
+
}
|
|
2611
|
+
if (/Hydration failed because/.test(message2) || /error while hydrating/i.test(message2) || /Text content (did not|does not) match/i.test(message2) || /Expected server HTML to contain/i.test(message2) || /did not match\. Server:/.test(message2)) {
|
|
2612
|
+
return { framework: "React", message: message2 };
|
|
2613
|
+
}
|
|
2614
|
+
if (/Hydration (node|text|children|class|style|attribute) mismatch/i.test(message2) || /Hydration completed but contains mismatches/i.test(message2)) {
|
|
2615
|
+
return { framework: "Vue", message: message2 };
|
|
2616
|
+
}
|
|
2617
|
+
if (/hydration_mismatch/.test(message2)) {
|
|
2618
|
+
return { framework: "Svelte", message: message2 };
|
|
2619
|
+
}
|
|
2620
|
+
if (/Hydration Mismatch\. Unable to find DOM nodes/.test(message2)) {
|
|
2621
|
+
return { framework: "Solid", message: message2 };
|
|
2622
|
+
}
|
|
2623
|
+
if (/hydrat/i.test(message2) && (/expected .+ but found/i.test(message2) || /mismatch/i.test(message2) && /(node|element|markup|dom|tag|text|attribute|server|client)/i.test(message2))) {
|
|
2624
|
+
return { framework: "the app", message: message2 };
|
|
2625
|
+
}
|
|
2626
|
+
}
|
|
2627
|
+
return null;
|
|
2628
|
+
}
|
|
2629
|
+
|
|
2596
2630
|
// ../server/dist/capture.js
|
|
2597
2631
|
var FRAME_MAX_HEIGHT = 4e3;
|
|
2598
2632
|
var MIN_WIDTH = 320;
|
|
@@ -2686,10 +2720,12 @@ function locatorExpression(focus) {
|
|
|
2686
2720
|
async function render(page, input) {
|
|
2687
2721
|
const width = clamp(Math.round(input.width), MIN_WIDTH, MAX_WIDTH);
|
|
2688
2722
|
const errors = [];
|
|
2723
|
+
let hydration = null;
|
|
2689
2724
|
const remember = (value) => {
|
|
2725
|
+
const message2 = String(value ?? "").trim().slice(0, 240);
|
|
2726
|
+
hydration ??= hydrationEvidence([message2]);
|
|
2690
2727
|
if (errors.length >= 10)
|
|
2691
2728
|
return;
|
|
2692
|
-
const message2 = String(value ?? "").slice(0, 240);
|
|
2693
2729
|
if (message2 === "" || /favicon/i.test(message2))
|
|
2694
2730
|
return;
|
|
2695
2731
|
errors.push(message2);
|
|
@@ -2837,7 +2873,7 @@ async function render(page, input) {
|
|
|
2837
2873
|
resolved
|
|
2838
2874
|
});
|
|
2839
2875
|
}
|
|
2840
|
-
return { frame, crops, errors, cut };
|
|
2876
|
+
return { frame, crops, errors, hydration, cut };
|
|
2841
2877
|
} finally {
|
|
2842
2878
|
for (const stop of unlisten)
|
|
2843
2879
|
stop();
|
|
@@ -2981,7 +3017,13 @@ async function attachRequest(cwd, requestId, input, deps) {
|
|
|
2981
3017
|
const capture = deps.capture ?? capturePage;
|
|
2982
3018
|
const deadlineMs = deps.deadlineMs ?? 12e3;
|
|
2983
3019
|
const destination = join5(cwd, CAPTURES_DIR, requestId);
|
|
2984
|
-
const captured = {
|
|
3020
|
+
const captured = {
|
|
3021
|
+
attachments: [],
|
|
3022
|
+
errors: [],
|
|
3023
|
+
hydration: null,
|
|
3024
|
+
cut: false,
|
|
3025
|
+
skipped: null
|
|
3026
|
+
};
|
|
2985
3027
|
const references = [];
|
|
2986
3028
|
requestedWidths.set(captured, Math.min(MAX_WIDTH, Math.max(MIN_WIDTH, Math.round(input.width))));
|
|
2987
3029
|
const controller = new AbortController();
|
|
@@ -3031,6 +3073,7 @@ async function attachRequest(cwd, requestId, input, deps) {
|
|
|
3031
3073
|
viewport: direction.frame.width
|
|
3032
3074
|
});
|
|
3033
3075
|
captured.errors = direction.errors;
|
|
3076
|
+
captured.hydration = direction.hydration;
|
|
3034
3077
|
captured.cut = direction.cut;
|
|
3035
3078
|
for (let index = 0; index < direction.crops.length; index += 1) {
|
|
3036
3079
|
const crop = direction.crops[index];
|
|
@@ -3726,10 +3769,10 @@ function scope(leglasCommand, quotedTitle) {
|
|
|
3726
3769
|
|
|
3727
3770
|
This is a scoped design change: no test run, no build, and no survey of the rest of the project is needed. The result is checked visually in a live preview, not by tooling.
|
|
3728
3771
|
|
|
3729
|
-
Leave every other direction exactly as it is; they are alternatives being compared side by side, so changing a sibling destroys the comparison. Keep the change additive: do not rewrite shared components that other directions rely on.`;
|
|
3772
|
+
Leave every other direction exactly as it is; they are alternatives being compared side by side, so changing a sibling destroys the comparison. Keep the change additive: do not rewrite shared components that other directions rely on. A shared script may gain one small per-direction override, at the point it reads what it renders, that defaults to what it renders today; every other direction then renders exactly as before, so that counts as additive.`;
|
|
3730
3773
|
}
|
|
3731
3774
|
function capturedBlock(captured) {
|
|
3732
|
-
if (captured === null || captured.attachments.length === 0 && captured.errors.length === 0 && captured.skipped === null)
|
|
3775
|
+
if (captured === null || captured.attachments.length === 0 && captured.errors.length === 0 && captured.hydration === null && captured.skipped === null)
|
|
3733
3776
|
return "";
|
|
3734
3777
|
const lines2 = [];
|
|
3735
3778
|
const frames = captured.attachments.filter((attachment) => attachment.kind === "frame" || attachment.kind === "note");
|
|
@@ -3761,6 +3804,9 @@ function capturedBlock(captured) {
|
|
|
3761
3804
|
for (const error of captured.errors)
|
|
3762
3805
|
lines2.push(` - ${error}`);
|
|
3763
3806
|
}
|
|
3807
|
+
if (captured.hydration !== null) {
|
|
3808
|
+
lines2.push(`After load, ${captured.hydration.framework} rebuilt this page in the browser from the app's own JavaScript and data (${captured.hydration.message}). Markup edited in the served HTML shows for a moment and is then replaced, so make the change where that JavaScript gets what it renders: the data or source it reads, or a per-direction override that a shared script reads with the original as its default. Look at the result a few seconds after load, not at first paint.`);
|
|
3809
|
+
}
|
|
3764
3810
|
if (captured.skipped !== null) {
|
|
3765
3811
|
lines2.push(`(${captured.skipped} Use the live preview instead.)`);
|
|
3766
3812
|
}
|
|
@@ -6442,6 +6488,7 @@ async function startServer(options) {
|
|
|
6442
6488
|
height: shot.height,
|
|
6443
6489
|
viewport: result.frame.width,
|
|
6444
6490
|
errors: result.errors,
|
|
6491
|
+
hydration: result.hydration,
|
|
6445
6492
|
cut: result.cut
|
|
6446
6493
|
});
|
|
6447
6494
|
} catch (error) {
|
|
@@ -7474,6 +7521,10 @@ async function runShow(options, deps) {
|
|
|
7474
7521
|
height: captured.height,
|
|
7475
7522
|
viewport: captured.viewport,
|
|
7476
7523
|
errors: Array.isArray(captured.errors) ? captured.errors.filter((error) => typeof error === "string") : [],
|
|
7524
|
+
hydration: typeof captured.hydration === "object" && captured.hydration !== null && typeof captured.hydration.framework === "string" && typeof captured.hydration.message === "string" ? {
|
|
7525
|
+
framework: captured.hydration.framework,
|
|
7526
|
+
message: captured.hydration.message
|
|
7527
|
+
} : null,
|
|
7477
7528
|
cut: captured.cut === true
|
|
7478
7529
|
};
|
|
7479
7530
|
}
|
|
@@ -7501,6 +7552,12 @@ async function runShow(options, deps) {
|
|
|
7501
7552
|
if (envelope2.screenshot.cut) {
|
|
7502
7553
|
deps.log(" the top of the page only; it is taller than one capture");
|
|
7503
7554
|
}
|
|
7555
|
+
if (envelope2.screenshot.hydration !== null) {
|
|
7556
|
+
deps.log(
|
|
7557
|
+
` hydration ${envelope2.screenshot.hydration.framework} rebuilt the page in the browser after load; the served markup is not what is on screen`
|
|
7558
|
+
);
|
|
7559
|
+
deps.log(` ${envelope2.screenshot.hydration.message}`);
|
|
7560
|
+
}
|
|
7504
7561
|
if (envelope2.screenshot.errors.length > 0) {
|
|
7505
7562
|
const count = envelope2.screenshot.errors.length;
|
|
7506
7563
|
deps.log(` console ${count} ${count === 1 ? "error" : "errors"} on load`);
|