@archastro/react-shot 0.1.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/LICENSE +21 -0
- package/README.md +183 -0
- package/bin/react-shot.mjs +2 -0
- package/dist/batch-paths.d.ts +4 -0
- package/dist/batch-paths.d.ts.map +1 -0
- package/dist/batch-paths.js +34 -0
- package/dist/batch-paths.js.map +1 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +217 -0
- package/dist/cli.js.map +1 -0
- package/dist/config.d.ts +5 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +75 -0
- package/dist/config.js.map +1 -0
- package/dist/create-server.d.ts +13 -0
- package/dist/create-server.d.ts.map +1 -0
- package/dist/create-server.js +254 -0
- package/dist/create-server.js.map +1 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -0
- package/dist/meta.d.ts +9 -0
- package/dist/meta.d.ts.map +1 -0
- package/dist/meta.js +23 -0
- package/dist/meta.js.map +1 -0
- package/dist/shot.d.ts +4 -0
- package/dist/shot.d.ts.map +1 -0
- package/dist/shot.js +259 -0
- package/dist/shot.js.map +1 -0
- package/dist/stubs.d.ts +6 -0
- package/dist/stubs.d.ts.map +1 -0
- package/dist/stubs.js +49 -0
- package/dist/stubs.js.map +1 -0
- package/dist/types.d.ts +79 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/host/index.html +22 -0
- package/package.json +81 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 ArchAstro
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
# @archastro/react-shot
|
|
2
|
+
|
|
3
|
+
Capture deterministic PNG screenshots from small React or TSX fixtures. The
|
|
4
|
+
CLI starts an isolated Vite page, renders the fixture in Chromium with
|
|
5
|
+
Playwright, and captures either a CSS selector or the full page.
|
|
6
|
+
|
|
7
|
+
This package is the React rendering engine. Use the unified
|
|
8
|
+
`@archastro/astroshot` package for command-line capture.
|
|
9
|
+
|
|
10
|
+
Use this for component documentation, release assets, and repeatable visual
|
|
11
|
+
fixtures. Use browser automation against your application when the screenshot
|
|
12
|
+
needs real authentication, routing, server data, or a complete product flow.
|
|
13
|
+
|
|
14
|
+
## Quick start
|
|
15
|
+
|
|
16
|
+
Node.js 22.14 or newer is required. Install the package's compatible Chromium
|
|
17
|
+
build once:
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
npx --@archastro:registry=https://registry.npmjs.org @archastro/astroshot install-browser
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
On a Linux machine that also needs Chromium's operating-system libraries, run
|
|
24
|
+
`npx --@archastro:registry=https://registry.npmjs.org @archastro/astroshot install-browser --with-deps`.
|
|
25
|
+
|
|
26
|
+
Then create `example.shot.tsx`:
|
|
27
|
+
|
|
28
|
+
```tsx
|
|
29
|
+
import type { ReactShotFixture } from "@archastro/astroshot/react";
|
|
30
|
+
|
|
31
|
+
function WelcomeCard() {
|
|
32
|
+
return (
|
|
33
|
+
<main
|
|
34
|
+
data-card
|
|
35
|
+
style={{ width: 480, padding: 32, background: "#f8fafc" }}
|
|
36
|
+
>
|
|
37
|
+
<h1>Hello from React</h1>
|
|
38
|
+
</main>
|
|
39
|
+
);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export default {
|
|
43
|
+
width: 800,
|
|
44
|
+
height: 600,
|
|
45
|
+
selector: "[data-card]",
|
|
46
|
+
component: <WelcomeCard />,
|
|
47
|
+
} satisfies ReactShotFixture;
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
Capture it without a permanent install:
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
npx --@archastro:registry=https://registry.npmjs.org \
|
|
54
|
+
@archastro/astroshot react example.shot.tsx --out welcome.png
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
Or install the unified package and use `astroshot` in project scripts:
|
|
58
|
+
|
|
59
|
+
```bash
|
|
60
|
+
npm install --save-dev @archastro/astroshot
|
|
61
|
+
npx astroshot react example.shot.tsx -o welcome.png
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
## Fixture API
|
|
65
|
+
|
|
66
|
+
The fixture's default export accepts:
|
|
67
|
+
|
|
68
|
+
| Field | Purpose |
|
|
69
|
+
| --- | --- |
|
|
70
|
+
| `component` | React tree to render; required |
|
|
71
|
+
| `width`, `height` | Viewport in CSS pixels; defaults to 1280 by 800 |
|
|
72
|
+
| `background` | Page background; defaults to transparent |
|
|
73
|
+
| `selector` | Element to capture; defaults to the fixture root |
|
|
74
|
+
| `waitFor` | CSS selector or `text=...` gate to await |
|
|
75
|
+
| `settleMs` | Extra layout settling time; defaults to 150 ms |
|
|
76
|
+
| `fullPage` | Capture the full page instead of one element |
|
|
77
|
+
| `stripOverlay` | Isolate the target from a full-screen parent overlay |
|
|
78
|
+
| `omitBackground` | Preserve transparent PNG pixels |
|
|
79
|
+
|
|
80
|
+
Selectors containing `[role=dialog]` automatically enable `stripOverlay` and
|
|
81
|
+
`omitBackground`. This avoids including a modal's full-screen dimmer and keeps
|
|
82
|
+
rounded corners transparent. Set either option explicitly to override it.
|
|
83
|
+
|
|
84
|
+
CLI `--width` and `--height` values override fixture dimensions. Values must be
|
|
85
|
+
whole CSS pixels between 1 and 10,000, and output paths must end in `.png`.
|
|
86
|
+
|
|
87
|
+
## Project configuration
|
|
88
|
+
|
|
89
|
+
Place `react-shot.config.ts` beside your application package. It is discovered
|
|
90
|
+
by walking upward from the fixture, or can be selected with `--config`.
|
|
91
|
+
Filesystem paths are resolved relative to the config file.
|
|
92
|
+
|
|
93
|
+
Without a config or `--root`, react-shot uses the closest directory containing
|
|
94
|
+
a `package.json`, so fixtures can import sibling application source files.
|
|
95
|
+
|
|
96
|
+
```ts
|
|
97
|
+
export default {
|
|
98
|
+
root: ".",
|
|
99
|
+
alias: {
|
|
100
|
+
"@": "./src",
|
|
101
|
+
},
|
|
102
|
+
styles: ["./src/global.css"],
|
|
103
|
+
postcssConfig: "./postcss.config.mjs",
|
|
104
|
+
dedupe: ["some-react-library"],
|
|
105
|
+
stubModules: ["server-only"],
|
|
106
|
+
};
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
Common imports from `next/navigation`, `next/link`, `next/image`,
|
|
110
|
+
`next/dynamic`, and `server-only` receive lightweight browser stubs. These
|
|
111
|
+
stubs are conveniences for presentation fixtures, not substitutes for testing
|
|
112
|
+
Next.js behavior.
|
|
113
|
+
|
|
114
|
+
If `@tailwindcss/vite` is installed in the target project, react-shot loads it
|
|
115
|
+
automatically. Otherwise Vite uses the configured PostCSS pipeline.
|
|
116
|
+
|
|
117
|
+
## Batch captures
|
|
118
|
+
|
|
119
|
+
Create a YAML or JSON manifest:
|
|
120
|
+
|
|
121
|
+
```yaml
|
|
122
|
+
root: .
|
|
123
|
+
shots:
|
|
124
|
+
- fixture: fixtures/welcome.shot.tsx
|
|
125
|
+
out: screenshots/welcome.png
|
|
126
|
+
width: 900
|
|
127
|
+
height: 700
|
|
128
|
+
- fixture: fixtures/settings.shot.tsx
|
|
129
|
+
out: screenshots/settings.png
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
Paths in a manifest, including per-shot `root` and `config`, are relative to
|
|
133
|
+
the manifest file. Destinations are normalized and checked as a complete batch
|
|
134
|
+
before capture; duplicate and case-only colliding output paths are rejected:
|
|
135
|
+
|
|
136
|
+
```bash
|
|
137
|
+
npx --@archastro:registry=https://registry.npmjs.org \
|
|
138
|
+
@archastro/astroshot react batch shots.yaml
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
## Programmatic API
|
|
142
|
+
|
|
143
|
+
```ts
|
|
144
|
+
import { closeSharedBrowser, takeShot } from "@archastro/react-shot";
|
|
145
|
+
|
|
146
|
+
try {
|
|
147
|
+
await takeShot({
|
|
148
|
+
fixturePath: "fixtures/welcome.shot.tsx",
|
|
149
|
+
outPath: "screenshots/welcome.png",
|
|
150
|
+
});
|
|
151
|
+
} finally {
|
|
152
|
+
await closeSharedBrowser();
|
|
153
|
+
}
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
Batch CLI runs reuse one browser process. Programmatic callers should close
|
|
157
|
+
the shared browser during shutdown.
|
|
158
|
+
|
|
159
|
+
## Security
|
|
160
|
+
|
|
161
|
+
Fixtures and config files are executable code. Vite loads application modules
|
|
162
|
+
and `react-shot.config.*`; they run with the permissions of the current user.
|
|
163
|
+
Only capture trusted repositories and fixtures. Do not run the CLI on an
|
|
164
|
+
untrusted pull request, package, or downloaded manifest without reviewing it.
|
|
165
|
+
|
|
166
|
+
The Vite server binds only to `127.0.0.1` and restricts file serving to the
|
|
167
|
+
package, fixture, configured alias/style paths, and this tool's runtime files.
|
|
168
|
+
It does not provide a sandbox for fixture code.
|
|
169
|
+
|
|
170
|
+
## Troubleshooting
|
|
171
|
+
|
|
172
|
+
- `Executable doesn't exist`: run
|
|
173
|
+
`npx --@archastro:registry=https://registry.npmjs.org @archastro/astroshot install-browser`.
|
|
174
|
+
- Import failures: pass `--root` or define `root` and `alias` in the config.
|
|
175
|
+
- Missing styles: add their entry files to `styles`; CSS is not inferred.
|
|
176
|
+
- A modal includes a dimmer: target `[role=dialog]` or set
|
|
177
|
+
`stripOverlay: true`.
|
|
178
|
+
- A fixture depends on application providers or network state: wrap it with
|
|
179
|
+
deterministic providers, or capture the running application instead.
|
|
180
|
+
|
|
181
|
+
Run
|
|
182
|
+
`npx --@archastro:registry=https://registry.npmjs.org @archastro/astroshot react --help`
|
|
183
|
+
for all CLI options.
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { BatchEntry } from "./types.js";
|
|
2
|
+
/** Resolve every destination before capture and reject accidental overwrites. */
|
|
3
|
+
export declare function resolveBatchOutputPaths(entries: BatchEntry[], manifestDirectory: string): string[];
|
|
4
|
+
//# sourceMappingURL=batch-paths.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"batch-paths.d.ts","sourceRoot":"","sources":["../src/batch-paths.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAmB7C,iFAAiF;AACjF,wBAAgB,uBAAuB,CACrC,OAAO,EAAE,UAAU,EAAE,EACrB,iBAAiB,EAAE,MAAM,GACxB,MAAM,EAAE,CAgBV"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import fs from "node:fs";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
function collisionKey(filePath) {
|
|
4
|
+
// Keep manifests portable across case-sensitive and case-insensitive hosts.
|
|
5
|
+
let existingAncestor = path.resolve(filePath);
|
|
6
|
+
const missingSegments = [];
|
|
7
|
+
while (!fs.existsSync(existingAncestor)) {
|
|
8
|
+
const parent = path.dirname(existingAncestor);
|
|
9
|
+
if (parent === existingAncestor)
|
|
10
|
+
break;
|
|
11
|
+
missingSegments.unshift(path.basename(existingAncestor));
|
|
12
|
+
existingAncestor = parent;
|
|
13
|
+
}
|
|
14
|
+
const canonicalAncestor = fs.realpathSync.native(existingAncestor);
|
|
15
|
+
return path
|
|
16
|
+
.join(canonicalAncestor, ...missingSegments)
|
|
17
|
+
.normalize("NFC")
|
|
18
|
+
.toLowerCase();
|
|
19
|
+
}
|
|
20
|
+
/** Resolve every destination before capture and reject accidental overwrites. */
|
|
21
|
+
export function resolveBatchOutputPaths(entries, manifestDirectory) {
|
|
22
|
+
const destinations = entries.map((entry) => path.resolve(manifestDirectory, entry.out));
|
|
23
|
+
const seen = new Map();
|
|
24
|
+
for (const destination of destinations) {
|
|
25
|
+
const key = collisionKey(destination);
|
|
26
|
+
const previous = seen.get(key);
|
|
27
|
+
if (previous) {
|
|
28
|
+
throw new Error(`Batch outputs resolve to the same destination: ${previous} and ${destination}`);
|
|
29
|
+
}
|
|
30
|
+
seen.set(key, destination);
|
|
31
|
+
}
|
|
32
|
+
return destinations;
|
|
33
|
+
}
|
|
34
|
+
//# sourceMappingURL=batch-paths.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"batch-paths.js","sourceRoot":"","sources":["../src/batch-paths.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;AAI7B,SAAS,YAAY,CAAC,QAAgB;IACpC,4EAA4E;IAC5E,IAAI,gBAAgB,GAAG,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;IAC9C,MAAM,eAAe,GAAa,EAAE,CAAC;IACrC,OAAO,CAAC,EAAE,CAAC,UAAU,CAAC,gBAAgB,CAAC,EAAE,CAAC;QACxC,MAAM,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,gBAAgB,CAAC,CAAC;QAC9C,IAAI,MAAM,KAAK,gBAAgB;YAAE,MAAM;QACvC,eAAe,CAAC,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,gBAAgB,CAAC,CAAC,CAAC;QACzD,gBAAgB,GAAG,MAAM,CAAC;IAC5B,CAAC;IACD,MAAM,iBAAiB,GAAG,EAAE,CAAC,YAAY,CAAC,MAAM,CAAC,gBAAgB,CAAC,CAAC;IACnE,OAAO,IAAI;SACR,IAAI,CAAC,iBAAiB,EAAE,GAAG,eAAe,CAAC;SAC3C,SAAS,CAAC,KAAK,CAAC;SAChB,WAAW,EAAE,CAAC;AACnB,CAAC;AAED,iFAAiF;AACjF,MAAM,UAAU,uBAAuB,CACrC,OAAqB,EACrB,iBAAyB;IAEzB,MAAM,YAAY,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CACzC,IAAI,CAAC,OAAO,CAAC,iBAAiB,EAAE,KAAK,CAAC,GAAG,CAAC,CAC3C,CAAC;IACF,MAAM,IAAI,GAAG,IAAI,GAAG,EAAkB,CAAC;IACvC,KAAK,MAAM,WAAW,IAAI,YAAY,EAAE,CAAC;QACvC,MAAM,GAAG,GAAG,YAAY,CAAC,WAAW,CAAC,CAAC;QACtC,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QAC/B,IAAI,QAAQ,EAAE,CAAC;YACb,MAAM,IAAI,KAAK,CACb,kDAAkD,QAAQ,QAAQ,WAAW,EAAE,CAChF,CAAC;QACJ,CAAC;QACD,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,WAAW,CAAC,CAAC;IAC7B,CAAC;IACD,OAAO,YAAY,CAAC;AACtB,CAAC"}
|
package/dist/cli.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":""}
|
package/dist/cli.js
ADDED
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { spawnSync } from "node:child_process";
|
|
3
|
+
import fs from "node:fs";
|
|
4
|
+
import { createRequire } from "node:module";
|
|
5
|
+
import path from "node:path";
|
|
6
|
+
import { fileURLToPath } from "node:url";
|
|
7
|
+
import YAML from "yaml";
|
|
8
|
+
import { resolveBatchOutputPaths } from "./batch-paths.js";
|
|
9
|
+
import { closeSharedBrowser, takeShot } from "./shot.js";
|
|
10
|
+
function packageVersion() {
|
|
11
|
+
const here = path.dirname(fileURLToPath(import.meta.url));
|
|
12
|
+
const packagePath = path.resolve(here, "../package.json");
|
|
13
|
+
const parsed = JSON.parse(fs.readFileSync(packagePath, "utf8"));
|
|
14
|
+
return parsed.version ?? "unknown";
|
|
15
|
+
}
|
|
16
|
+
function printHelp() {
|
|
17
|
+
console.log(`react-shot - deterministic React component screenshots
|
|
18
|
+
|
|
19
|
+
Usage:
|
|
20
|
+
react-shot shot <fixture.tsx> -o <out.png> [options]
|
|
21
|
+
react-shot batch <manifest.yaml|json> [options]
|
|
22
|
+
react-shot <fixture.tsx> -o <out.png> [options]
|
|
23
|
+
react-shot install-browser [--with-deps]
|
|
24
|
+
|
|
25
|
+
Options:
|
|
26
|
+
-o, --out <path> Output PNG path
|
|
27
|
+
--root <dir> Package root for imports and aliases
|
|
28
|
+
--config <path> Config path; otherwise discovered from the fixture
|
|
29
|
+
--width <px> Override viewport width
|
|
30
|
+
--height <px> Override viewport height
|
|
31
|
+
--headed Show Chromium for debugging
|
|
32
|
+
--with-deps Install Chromium OS dependencies too
|
|
33
|
+
-v, --version Print the installed version
|
|
34
|
+
-h, --help Show this help
|
|
35
|
+
|
|
36
|
+
Run "react-shot install-browser" once before the first capture.
|
|
37
|
+
`);
|
|
38
|
+
}
|
|
39
|
+
function requiredValue(args, flag) {
|
|
40
|
+
const value = args.shift();
|
|
41
|
+
if (!value || value.startsWith("-")) {
|
|
42
|
+
throw new Error(`${flag} requires a value`);
|
|
43
|
+
}
|
|
44
|
+
return value;
|
|
45
|
+
}
|
|
46
|
+
function parseArgs(argv) {
|
|
47
|
+
const args = [...argv];
|
|
48
|
+
const flags = {};
|
|
49
|
+
const positionals = [];
|
|
50
|
+
while (args.length > 0) {
|
|
51
|
+
const argument = args.shift();
|
|
52
|
+
if (argument === "-h" || argument === "--help")
|
|
53
|
+
flags.help = true;
|
|
54
|
+
else if (argument === "-v" || argument === "--version")
|
|
55
|
+
flags.version = true;
|
|
56
|
+
else if (argument === "--headed")
|
|
57
|
+
flags.headed = true;
|
|
58
|
+
else if (argument === "--with-deps")
|
|
59
|
+
flags.withDeps = true;
|
|
60
|
+
else if (argument === "-o" || argument === "--out") {
|
|
61
|
+
flags.out = requiredValue(args, argument);
|
|
62
|
+
}
|
|
63
|
+
else if (argument === "--root") {
|
|
64
|
+
flags.root = requiredValue(args, argument);
|
|
65
|
+
}
|
|
66
|
+
else if (argument === "--config") {
|
|
67
|
+
flags.config = requiredValue(args, argument);
|
|
68
|
+
}
|
|
69
|
+
else if (argument === "--width") {
|
|
70
|
+
flags.width = requiredValue(args, argument);
|
|
71
|
+
}
|
|
72
|
+
else if (argument === "--height") {
|
|
73
|
+
flags.height = requiredValue(args, argument);
|
|
74
|
+
}
|
|
75
|
+
else if (argument.startsWith("-")) {
|
|
76
|
+
throw new Error(`Unknown option: ${argument}`);
|
|
77
|
+
}
|
|
78
|
+
else {
|
|
79
|
+
positionals.push(argument);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
return { flags, positionals };
|
|
83
|
+
}
|
|
84
|
+
function dimension(flags, name) {
|
|
85
|
+
const raw = flags[name];
|
|
86
|
+
if (raw === undefined)
|
|
87
|
+
return undefined;
|
|
88
|
+
const value = Number(raw);
|
|
89
|
+
if (!Number.isInteger(value) || value < 1 || value > 10_000) {
|
|
90
|
+
throw new Error(`--${name} must be an integer between 1 and 10000`);
|
|
91
|
+
}
|
|
92
|
+
return value;
|
|
93
|
+
}
|
|
94
|
+
async function captureFixture(fixture, flags) {
|
|
95
|
+
const output = flags.out;
|
|
96
|
+
if (typeof output !== "string") {
|
|
97
|
+
throw new Error("A screenshot requires -o <out.png>");
|
|
98
|
+
}
|
|
99
|
+
const outPath = await takeShot({
|
|
100
|
+
fixturePath: fixture,
|
|
101
|
+
outPath: output,
|
|
102
|
+
root: typeof flags.root === "string" ? flags.root : undefined,
|
|
103
|
+
configPath: typeof flags.config === "string" ? flags.config : undefined,
|
|
104
|
+
headed: Boolean(flags.headed),
|
|
105
|
+
width: dimension(flags, "width"),
|
|
106
|
+
height: dimension(flags, "height"),
|
|
107
|
+
});
|
|
108
|
+
console.log(`wrote ${outPath}`);
|
|
109
|
+
}
|
|
110
|
+
function manifestRelative(baseDirectory, value) {
|
|
111
|
+
return value ? path.resolve(baseDirectory, value) : undefined;
|
|
112
|
+
}
|
|
113
|
+
async function captureBatch(manifestPath, flags) {
|
|
114
|
+
const absoluteManifest = path.resolve(manifestPath);
|
|
115
|
+
const raw = fs.readFileSync(absoluteManifest, "utf8");
|
|
116
|
+
const manifest = (absoluteManifest.endsWith(".json") ? JSON.parse(raw) : YAML.parse(raw));
|
|
117
|
+
if (!Array.isArray(manifest?.shots) || manifest.shots.length === 0) {
|
|
118
|
+
throw new Error(`No shots listed in ${absoluteManifest}`);
|
|
119
|
+
}
|
|
120
|
+
const baseDirectory = path.dirname(absoluteManifest);
|
|
121
|
+
for (const entry of manifest.shots) {
|
|
122
|
+
if (!entry.fixture || !entry.out) {
|
|
123
|
+
throw new Error("Each batch entry requires fixture and out");
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
const outPaths = resolveBatchOutputPaths(manifest.shots, baseDirectory);
|
|
127
|
+
const cliWidth = dimension(flags, "width");
|
|
128
|
+
const cliHeight = dimension(flags, "height");
|
|
129
|
+
let completed = 0;
|
|
130
|
+
for (const [index, entry] of manifest.shots.entries()) {
|
|
131
|
+
const fixturePath = path.resolve(baseDirectory, entry.fixture);
|
|
132
|
+
const outPath = outPaths[index];
|
|
133
|
+
const root = typeof flags.root === "string"
|
|
134
|
+
? path.resolve(flags.root)
|
|
135
|
+
: manifestRelative(baseDirectory, entry.root ?? manifest.root);
|
|
136
|
+
const configPath = typeof flags.config === "string"
|
|
137
|
+
? path.resolve(flags.config)
|
|
138
|
+
: manifestRelative(baseDirectory, entry.config ?? manifest.config);
|
|
139
|
+
process.stdout.write(`shot ${path.relative(process.cwd(), fixturePath)} ... `);
|
|
140
|
+
await takeShot({
|
|
141
|
+
fixturePath,
|
|
142
|
+
outPath,
|
|
143
|
+
root,
|
|
144
|
+
configPath,
|
|
145
|
+
headed: Boolean(flags.headed),
|
|
146
|
+
width: cliWidth ?? entry.width,
|
|
147
|
+
height: cliHeight ?? entry.height,
|
|
148
|
+
});
|
|
149
|
+
completed += 1;
|
|
150
|
+
console.log(`wrote ${path.relative(process.cwd(), outPath)}`);
|
|
151
|
+
}
|
|
152
|
+
console.log(`done: ${completed}/${manifest.shots.length} shots`);
|
|
153
|
+
}
|
|
154
|
+
function installBrowser(flags) {
|
|
155
|
+
const require = createRequire(import.meta.url);
|
|
156
|
+
const packagePath = require.resolve("playwright/package.json");
|
|
157
|
+
const cliPath = path.join(path.dirname(packagePath), "cli.js");
|
|
158
|
+
const arguments_ = ["install"];
|
|
159
|
+
if (flags.withDeps)
|
|
160
|
+
arguments_.push("--with-deps");
|
|
161
|
+
arguments_.push("chromium");
|
|
162
|
+
const result = spawnSync(process.execPath, [cliPath, ...arguments_], {
|
|
163
|
+
stdio: "inherit",
|
|
164
|
+
});
|
|
165
|
+
if (result.error) {
|
|
166
|
+
throw new Error(`Could not start Playwright installer: ${result.error.message}`);
|
|
167
|
+
}
|
|
168
|
+
if (result.status !== 0) {
|
|
169
|
+
throw new Error(`Playwright browser installation failed with exit code ${result.status ?? "unknown"}`);
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
async function main() {
|
|
173
|
+
const argv = process.argv.slice(2);
|
|
174
|
+
if (argv.length === 0) {
|
|
175
|
+
printHelp();
|
|
176
|
+
process.exitCode = 1;
|
|
177
|
+
return;
|
|
178
|
+
}
|
|
179
|
+
const { flags, positionals } = parseArgs(argv);
|
|
180
|
+
if (flags.version) {
|
|
181
|
+
console.log(packageVersion());
|
|
182
|
+
return;
|
|
183
|
+
}
|
|
184
|
+
if (flags.help || positionals[0] === "help") {
|
|
185
|
+
printHelp();
|
|
186
|
+
return;
|
|
187
|
+
}
|
|
188
|
+
try {
|
|
189
|
+
if (positionals[0] === "install-browser") {
|
|
190
|
+
installBrowser(flags);
|
|
191
|
+
}
|
|
192
|
+
else if (positionals[0] === "shot") {
|
|
193
|
+
if (!positionals[1])
|
|
194
|
+
throw new Error("shot requires a fixture path");
|
|
195
|
+
await captureFixture(positionals[1], flags);
|
|
196
|
+
}
|
|
197
|
+
else if (positionals[0] === "batch") {
|
|
198
|
+
if (!positionals[1])
|
|
199
|
+
throw new Error("batch requires a manifest path");
|
|
200
|
+
await captureBatch(positionals[1], flags);
|
|
201
|
+
}
|
|
202
|
+
else if (/\.[cm]?tsx?$/.test(positionals[0] ?? "")) {
|
|
203
|
+
await captureFixture(positionals[0], flags);
|
|
204
|
+
}
|
|
205
|
+
else {
|
|
206
|
+
throw new Error(`Unknown command: ${positionals[0]}`);
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
finally {
|
|
210
|
+
await closeSharedBrowser();
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
main().catch((error) => {
|
|
214
|
+
console.error(error instanceof Error ? error.message : error);
|
|
215
|
+
process.exitCode = 1;
|
|
216
|
+
});
|
|
217
|
+
//# sourceMappingURL=cli.js.map
|
package/dist/cli.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
|
package/dist/config.d.ts
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { ReactShotConfig } from "./types.js";
|
|
2
|
+
export declare function findConfigPath(startDir: string): string | null;
|
|
3
|
+
export declare function loadConfig(configPath: string | null | undefined): Promise<ReactShotConfig>;
|
|
4
|
+
export declare function resolvePackageRoot(fixturePath: string, explicitRoot?: string, config?: ReactShotConfig): string;
|
|
5
|
+
//# sourceMappingURL=config.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AASlD,wBAAgB,cAAc,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAW9D;AAED,wBAAsB,UAAU,CAC9B,UAAU,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GACpC,OAAO,CAAC,eAAe,CAAC,CA2C1B;AAED,wBAAgB,kBAAkB,CAChC,WAAW,EAAE,MAAM,EACnB,YAAY,CAAC,EAAE,MAAM,EACrB,MAAM,CAAC,EAAE,eAAe,GACvB,MAAM,CAWR"}
|
package/dist/config.js
ADDED
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import fs from "node:fs";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { pathToFileURL } from "node:url";
|
|
4
|
+
import { tsImport } from "tsx/esm/api";
|
|
5
|
+
const CONFIG_NAMES = [
|
|
6
|
+
"react-shot.config.ts",
|
|
7
|
+
"react-shot.config.mts",
|
|
8
|
+
"react-shot.config.js",
|
|
9
|
+
"react-shot.config.mjs",
|
|
10
|
+
];
|
|
11
|
+
export function findConfigPath(startDir) {
|
|
12
|
+
let dir = path.resolve(startDir);
|
|
13
|
+
while (true) {
|
|
14
|
+
for (const name of CONFIG_NAMES) {
|
|
15
|
+
const candidate = path.join(dir, name);
|
|
16
|
+
if (fs.existsSync(candidate))
|
|
17
|
+
return candidate;
|
|
18
|
+
}
|
|
19
|
+
const parent = path.dirname(dir);
|
|
20
|
+
if (parent === dir)
|
|
21
|
+
return null;
|
|
22
|
+
dir = parent;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
export async function loadConfig(configPath) {
|
|
26
|
+
if (!configPath)
|
|
27
|
+
return {};
|
|
28
|
+
const absolutePath = path.resolve(configPath);
|
|
29
|
+
if (!fs.existsSync(absolutePath)) {
|
|
30
|
+
throw new Error(`react-shot config not found: ${absolutePath}`);
|
|
31
|
+
}
|
|
32
|
+
const module = absolutePath.endsWith(".ts") || absolutePath.endsWith(".mts")
|
|
33
|
+
? await tsImport(absolutePath, import.meta.url)
|
|
34
|
+
: await import(`${pathToFileURL(absolutePath).href}?t=${Date.now()}`);
|
|
35
|
+
const imported = (module.default ?? module);
|
|
36
|
+
// tsx exposes a TypeScript default export through one additional interop
|
|
37
|
+
// layer when the importing package is ESM.
|
|
38
|
+
const config = "default" in imported &&
|
|
39
|
+
Object.keys(imported).every((key) => key === "default")
|
|
40
|
+
? imported.default
|
|
41
|
+
: imported;
|
|
42
|
+
const configDirectory = path.dirname(absolutePath);
|
|
43
|
+
return {
|
|
44
|
+
...config,
|
|
45
|
+
root: config.root
|
|
46
|
+
? path.resolve(configDirectory, config.root)
|
|
47
|
+
: configDirectory,
|
|
48
|
+
alias: config.alias
|
|
49
|
+
? Object.fromEntries(Object.entries(config.alias).map(([key, value]) => [
|
|
50
|
+
key,
|
|
51
|
+
path.resolve(configDirectory, value),
|
|
52
|
+
]))
|
|
53
|
+
: undefined,
|
|
54
|
+
styles: config.styles?.map((value) => path.resolve(configDirectory, value)),
|
|
55
|
+
postcssConfig: config.postcssConfig
|
|
56
|
+
? path.resolve(configDirectory, config.postcssConfig)
|
|
57
|
+
: undefined,
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
export function resolvePackageRoot(fixturePath, explicitRoot, config) {
|
|
61
|
+
if (explicitRoot)
|
|
62
|
+
return path.resolve(explicitRoot);
|
|
63
|
+
if (config?.root)
|
|
64
|
+
return config.root;
|
|
65
|
+
let directory = path.dirname(path.resolve(fixturePath));
|
|
66
|
+
while (true) {
|
|
67
|
+
if (fs.existsSync(path.join(directory, "package.json")))
|
|
68
|
+
return directory;
|
|
69
|
+
const parent = path.dirname(directory);
|
|
70
|
+
if (parent === directory)
|
|
71
|
+
return path.dirname(path.resolve(fixturePath));
|
|
72
|
+
directory = parent;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { type ViteDevServer } from "vite";
|
|
2
|
+
import type { ReactShotConfig } from "./types.js";
|
|
3
|
+
export declare function resolveInstalledPackage(packageRoot: string, name: string): string | null;
|
|
4
|
+
export declare function resolveInstalledModule(packageRoot: string, moduleName: string): string | null;
|
|
5
|
+
export declare function startShotServer(options: {
|
|
6
|
+
fixturePath: string;
|
|
7
|
+
packageRoot: string;
|
|
8
|
+
config: ReactShotConfig;
|
|
9
|
+
}): Promise<{
|
|
10
|
+
server: ViteDevServer;
|
|
11
|
+
url: string;
|
|
12
|
+
}>;
|
|
13
|
+
//# sourceMappingURL=create-server.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"create-server.d.ts","sourceRoot":"","sources":["../src/create-server.ts"],"names":[],"mappings":"AAKA,OAAO,EAIL,KAAK,aAAa,EACnB,MAAM,MAAM,CAAC;AACd,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAgBlD,wBAAgB,uBAAuB,CACrC,WAAW,EAAE,MAAM,EACnB,IAAI,EAAE,MAAM,GACX,MAAM,GAAG,IAAI,CAiBf;AAED,wBAAgB,sBAAsB,CACpC,WAAW,EAAE,MAAM,EACnB,UAAU,EAAE,MAAM,GACjB,MAAM,GAAG,IAAI,CAYf;AAoID,wBAAsB,eAAe,CAAC,OAAO,EAAE;IAC7C,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,eAAe,CAAC;CACzB,GAAG,OAAO,CAAC;IAAE,MAAM,EAAE,aAAa,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,CAAC,CA2FlD"}
|