@juangadm/pre-post 0.2.0 → 1.0.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 +102 -222
- package/dist/bin/cli.js +199 -347
- package/dist/bin/cli.js.map +1 -1
- package/dist/browser.d.ts +42 -11
- package/dist/browser.d.ts.map +1 -1
- package/dist/browser.js +371 -94
- package/dist/browser.js.map +1 -1
- package/dist/capture.d.ts +1 -6
- package/dist/capture.d.ts.map +1 -1
- package/dist/capture.js +12 -35
- package/dist/capture.js.map +1 -1
- package/dist/commands/compare.d.ts +18 -0
- package/dist/commands/compare.d.ts.map +1 -0
- package/dist/commands/compare.js +64 -0
- package/dist/commands/compare.js.map +1 -0
- package/dist/commands/detect.d.ts +20 -0
- package/dist/commands/detect.d.ts.map +1 -0
- package/dist/commands/detect.js +19 -0
- package/dist/commands/detect.js.map +1 -0
- package/dist/commands/doctor.d.ts +10 -0
- package/dist/commands/doctor.d.ts.map +1 -0
- package/dist/commands/doctor.js +38 -0
- package/dist/commands/doctor.js.map +1 -0
- package/dist/commands/login.d.ts +6 -0
- package/dist/commands/login.d.ts.map +1 -0
- package/dist/commands/login.js +34 -0
- package/dist/commands/login.js.map +1 -0
- package/dist/commands/pr.d.ts +28 -0
- package/dist/commands/pr.d.ts.map +1 -0
- package/dist/commands/pr.js +159 -0
- package/dist/commands/pr.js.map +1 -0
- package/dist/commands/prune.d.ts +10 -0
- package/dist/commands/prune.d.ts.map +1 -0
- package/dist/commands/prune.js +13 -0
- package/dist/commands/prune.js.map +1 -0
- package/dist/config.d.ts +36 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +60 -0
- package/dist/config.js.map +1 -0
- package/dist/diff-pool.d.ts +17 -0
- package/dist/diff-pool.d.ts.map +1 -0
- package/dist/diff-pool.js +89 -0
- package/dist/diff-pool.js.map +1 -0
- package/dist/diff-worker.d.ts +29 -0
- package/dist/diff-worker.d.ts.map +1 -0
- package/dist/diff-worker.js +38 -0
- package/dist/diff-worker.js.map +1 -0
- package/dist/diff.d.ts +37 -0
- package/dist/diff.d.ts.map +1 -0
- package/dist/diff.js +171 -0
- package/dist/diff.js.map +1 -0
- package/dist/doctor.d.ts +38 -0
- package/dist/doctor.d.ts.map +1 -0
- package/dist/doctor.js +72 -0
- package/dist/doctor.js.map +1 -0
- package/dist/errors.d.ts +38 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +59 -0
- package/dist/errors.js.map +1 -0
- package/dist/filename.d.ts +2 -0
- package/dist/filename.d.ts.map +1 -1
- package/dist/filename.js +2 -1
- package/dist/filename.js.map +1 -1
- package/dist/git.d.ts +23 -0
- package/dist/git.d.ts.map +1 -0
- package/dist/git.js +86 -0
- package/dist/git.js.map +1 -0
- package/dist/github.d.ts +73 -0
- package/dist/github.d.ts.map +1 -0
- package/dist/github.js +240 -0
- package/dist/github.js.map +1 -0
- package/dist/index.d.ts +22 -22
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +17 -66
- package/dist/index.js.map +1 -1
- package/dist/pkg.d.ts +8 -0
- package/dist/pkg.d.ts.map +1 -0
- package/dist/pkg.js +35 -0
- package/dist/pkg.js.map +1 -0
- package/dist/report.d.ts +20 -0
- package/dist/report.d.ts.map +1 -0
- package/dist/report.js +107 -0
- package/dist/report.js.map +1 -0
- package/dist/routes/imports.d.ts +46 -0
- package/dist/routes/imports.d.ts.map +1 -0
- package/dist/routes/imports.js +208 -0
- package/dist/routes/imports.js.map +1 -0
- package/dist/routes/vite.d.ts +15 -0
- package/dist/routes/vite.d.ts.map +1 -0
- package/dist/routes/vite.js +130 -0
- package/dist/routes/vite.js.map +1 -0
- package/dist/routes.d.ts +41 -14
- package/dist/routes.d.ts.map +1 -1
- package/dist/routes.js +271 -141
- package/dist/routes.js.map +1 -1
- package/dist/run.d.ts +36 -0
- package/dist/run.d.ts.map +1 -0
- package/dist/run.js +128 -0
- package/dist/run.js.map +1 -0
- package/dist/sessions.d.ts +50 -0
- package/dist/sessions.d.ts.map +1 -0
- package/dist/sessions.js +74 -0
- package/dist/sessions.js.map +1 -0
- package/dist/types.d.ts +118 -41
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +1 -0
- package/dist/types.js.map +1 -1
- package/dist/viewport.d.ts +6 -1
- package/dist/viewport.d.ts.map +1 -1
- package/dist/viewport.js +13 -7
- package/dist/viewport.js.map +1 -1
- package/package.json +21 -13
- package/skill/SKILL.md +31 -229
- package/dist/clipboard.d.ts +0 -9
- package/dist/clipboard.d.ts.map +0 -1
- package/dist/clipboard.js +0 -26
- package/dist/clipboard.js.map +0 -1
- package/dist/upload.d.ts +0 -39
- package/dist/upload.d.ts.map +0 -1
- package/dist/upload.js +0 -149
- package/dist/upload.js.map +0 -1
- package/skill/scripts/adapters/0x0st.sh +0 -36
- package/skill/scripts/adapters/blob.sh +0 -55
- package/skill/scripts/adapters/git-native.sh +0 -51
- package/skill/scripts/upload-and-copy.sh +0 -230
package/README.md
CHANGED
|
@@ -1,255 +1,135 @@
|
|
|
1
1
|
# pre-post
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
P --> Q[Disable animations]
|
|
51
|
-
Q --> R[Wait for fonts]
|
|
52
|
-
R --> S[Take 2x retina screenshot]
|
|
53
|
-
|
|
54
|
-
S --> T{Output}
|
|
55
|
-
T -->|Default| U["Save to ~/Downloads"]
|
|
56
|
-
T -->|--markdown| V{Upload}
|
|
57
|
-
V -->|Default| W["Commit to .pre-post/ (blob+SHA URL)"]
|
|
58
|
-
V -->|--upload-url| Y["Custom storage"]
|
|
59
|
-
W --> Z[Markdown table for PR]
|
|
60
|
-
Y --> Z
|
|
61
|
-
|
|
62
|
-
style A fill:#4f46e5,color:#fff
|
|
63
|
-
style L fill:#2563eb,color:#fff
|
|
64
|
-
style S fill:#059669,color:#fff
|
|
65
|
-
```
|
|
66
|
-
|
|
67
|
-
## Prerequisites
|
|
68
|
-
|
|
69
|
-
- **Node.js** 18+
|
|
70
|
-
- **Chromium** — install once via Playwright:
|
|
71
|
-
|
|
72
|
-
```bash
|
|
73
|
-
npx playwright install chromium
|
|
74
|
-
```
|
|
75
|
-
|
|
76
|
-
## CI / Sandboxed Environments
|
|
77
|
-
|
|
78
|
-
pre-post needs a Chromium binary. In restricted environments where `npx playwright install chromium` fails (CDN blocked):
|
|
79
|
-
|
|
80
|
-
```bash
|
|
81
|
-
# Point to a pre-installed Chrome/Chromium binary
|
|
82
|
-
export PLAYWRIGHT_CHROMIUM_EXECUTABLE_PATH=/path/to/chrome
|
|
83
|
-
|
|
84
|
-
# This is treated as an explicit override — pre-post will fail with a
|
|
85
|
-
# clear error if the path is wrong, rather than silently falling back.
|
|
86
|
-
```
|
|
87
|
-
|
|
88
|
-
When no custom path is set, pre-post auto-detects in order: system Chrome, bundled Playwright Chromium, then any builds in `~/.cache/ms-playwright/`.
|
|
89
|
-
|
|
90
|
-
If no browser is available at all, use image-only mode:
|
|
91
|
-
|
|
92
|
-
```bash
|
|
93
|
-
pre-post before.png after.png --markdown
|
|
94
|
-
```
|
|
95
|
-
|
|
96
|
-
**Proxy URLs**: If your git remote uses a proxy (e.g., `http://proxy@host/git/owner/repo`), set the repo explicitly:
|
|
97
|
-
|
|
98
|
-
```bash
|
|
99
|
-
export GH_REPO=owner/repo
|
|
100
|
-
```
|
|
101
|
-
|
|
102
|
-
**Google Fonts**: Container egress proxies typically block `fonts.googleapis.com`.
|
|
103
|
-
Screenshots will render with system font fallbacks. This is cosmetic only —
|
|
104
|
-
`document.fonts.ready` still resolves and layout is preserved.
|
|
3
|
+
Before/after screenshots for pull requests. One command detects the routes your branch
|
|
4
|
+
changed, captures them on production ("Pre") and on your dev server ("Post"), pixel-diffs
|
|
5
|
+
them, uploads the images to GitHub, and posts a single comment on the PR that a reviewer
|
|
6
|
+
can judge at a glance.
|
|
7
|
+
|
|
8
|
+
> Originally forked from [before-and-after](https://github.com/vercel-labs/before-and-after) by James Clements / Vercel Labs.
|
|
9
|
+
|
|
10
|
+
```
|
|
11
|
+
$ npx -y @juangadm/pre-post@latest pr
|
|
12
|
+
|
|
13
|
+
Routes (nextjs-app, 41ms): /, /pricing
|
|
14
|
+
/ medium src/app/page.tsx imports src/components/ui/button.tsx (2 hops)
|
|
15
|
+
/pricing medium src/app/pricing/page.tsx imports src/components/ui/button.tsx (2 hops)
|
|
16
|
+
Capturing 8 screenshots (2 route(s) × 2 viewport(s)) ...
|
|
17
|
+
changed /pricing @ mobile (1.42%, 1811ms)
|
|
18
|
+
changed /pricing @ desktop (0.64%, 2036ms)
|
|
19
|
+
same / @ mobile (0.00%, 1990ms)
|
|
20
|
+
same / @ desktop (0.00%, 2211ms)
|
|
21
|
+
Publishing 10 image(s) to acme/web@pre-post-assets ...
|
|
22
|
+
Updated PR comment: https://github.com/acme/web/pull/42#issuecomment-1
|
|
23
|
+
pre-post · PR #42 · 2 route(s) · 2 viewport(s) · 6.8s
|
|
24
|
+
/ desktop no change
|
|
25
|
+
/ mobile no change
|
|
26
|
+
/pricing desktop 0.64% changed
|
|
27
|
+
/pricing mobile 1.4% changed
|
|
28
|
+
Comment: https://github.com/acme/web/pull/42#issuecomment-1
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
## How it works
|
|
32
|
+
|
|
33
|
+
1. **Routes.** Diffs the branch against the merge base with `main`, then follows the import
|
|
34
|
+
graph: a change to `components/ui/button.tsx` marks every page that imports it. Next.js
|
|
35
|
+
App Router and Pages Router, Vite apps (React Router, file-based `src/pages`), and a
|
|
36
|
+
generic fallback. Monorepos are handled by picking the app that owns the changed files.
|
|
37
|
+
2. **Capture.** Playwright + Chromium headless shell. Fixed clock, reduced motion,
|
|
38
|
+
animations finished, caret hidden, fonts and images settled, layout stable across frames,
|
|
39
|
+
lazy content primed. 2x device scale, full page (capped at 2400 CSS px), desktop + mobile.
|
|
40
|
+
All routes and viewports run concurrently.
|
|
41
|
+
3. **Diff.** Pure-JS pixel comparison in worker threads. Reports the percentage changed,
|
|
42
|
+
the bounding box, a red-highlight image, and a tight crop of the changed region.
|
|
43
|
+
4. **Publish.** Images go to a `pre-post-assets` branch in the same repository via the GitHub
|
|
44
|
+
API, as one commit per run. Nothing is committed to the PR branch, no CI is triggered,
|
|
45
|
+
and the blob URLs render on private repos. `pre-post prune` removes images for PRs
|
|
46
|
+
closed more than 90 days ago.
|
|
47
|
+
5. **Comment.** One sticky comment per PR, updated in place on every run. Changed routes show
|
|
48
|
+
a Pre/Post crop with the full page and diff collapsed underneath; unchanged routes fold
|
|
49
|
+
into a single line.
|
|
105
50
|
|
|
106
51
|
## Install
|
|
107
52
|
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
## Basic Use
|
|
113
|
-
|
|
114
|
-
### As a Claude Code Skill (recommended)
|
|
115
|
-
|
|
116
|
-
After making visual UI changes, say `/pre-post` or "take pre and post screenshots". Claude will:
|
|
117
|
-
|
|
118
|
-
1. Detect affected routes from your git diff
|
|
119
|
-
2. Propose routes for your approval
|
|
120
|
-
3. Capture desktop + mobile screenshots (production vs localhost)
|
|
121
|
-
4. Show you the screenshots for approval
|
|
122
|
-
5. Upload and append markdown to your PR
|
|
123
|
-
|
|
124
|
-
### From the CLI
|
|
125
|
-
|
|
126
|
-
Capture any two URLs:
|
|
127
|
-
|
|
128
|
-
```bash
|
|
129
|
-
pre-post site.com localhost:3000
|
|
130
|
-
```
|
|
131
|
-
|
|
132
|
-
Use existing images:
|
|
133
|
-
|
|
134
|
-
```bash
|
|
135
|
-
pre-post before.png after.png
|
|
136
|
-
```
|
|
137
|
-
|
|
138
|
-
## CLI Subcommands
|
|
139
|
-
|
|
140
|
-
### `detect` -- Route Detection
|
|
141
|
-
|
|
142
|
-
Detect affected routes from git changes:
|
|
143
|
-
|
|
144
|
-
```bash
|
|
145
|
-
pre-post detect # Auto-detect framework
|
|
146
|
-
pre-post detect --framework nextjs-app # Force framework
|
|
147
|
-
```
|
|
148
|
-
|
|
149
|
-
Outputs JSON with route paths, confidence levels, and source files.
|
|
150
|
-
|
|
151
|
-
### `compare` -- URL Comparison
|
|
53
|
+
Nothing to install. `npx -y @juangadm/pre-post@latest pr` downloads the CLI and, on first
|
|
54
|
+
use, the Chromium headless shell (~80 MB). You need Node 20+ and a GitHub token: either
|
|
55
|
+
`gh auth login` or `GH_TOKEN`.
|
|
152
56
|
|
|
153
|
-
|
|
57
|
+
As a Claude Code skill:
|
|
154
58
|
|
|
155
59
|
```bash
|
|
156
|
-
pre-post
|
|
157
|
-
pre-post compare --before-base URL --after-base URL --routes /dashboard,/settings
|
|
158
|
-
pre-post compare --before-base URL --after-base URL --responsive # Desktop + mobile
|
|
60
|
+
npx skills add juangadm/pre-post -y
|
|
159
61
|
```
|
|
160
62
|
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
Combines `detect` + `compare`:
|
|
164
|
-
|
|
165
|
-
```bash
|
|
166
|
-
pre-post run --before-base https://prod.com --after-base http://localhost:3000
|
|
167
|
-
```
|
|
168
|
-
|
|
169
|
-
## Options
|
|
170
|
-
|
|
171
|
-
Capture a specific element using a CSS selector:
|
|
172
|
-
|
|
173
|
-
```bash
|
|
174
|
-
pre-post url1 url2 ".hero"
|
|
175
|
-
```
|
|
63
|
+
Then say `/pre-post` after making UI changes.
|
|
176
64
|
|
|
177
|
-
|
|
65
|
+
## Usage
|
|
178
66
|
|
|
179
67
|
```bash
|
|
180
|
-
pre-post
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
68
|
+
pre-post pr # everything, on the current branch's PR
|
|
69
|
+
pre-post pr --before https://acme.com # first run in a repo (saved to .pre-post.json)
|
|
70
|
+
pre-post pr --routes /pricing,/docs # explicit routes
|
|
71
|
+
pre-post pr --viewports desktop,1440x900 # custom viewports
|
|
72
|
+
pre-post pr --dry-run # capture + diff locally, post nothing
|
|
73
|
+
pre-post pr --json # machine-readable output
|
|
184
74
|
|
|
185
|
-
|
|
186
|
-
pre-post
|
|
187
|
-
pre-post
|
|
75
|
+
pre-post https://acme.com http://localhost:3000 --routes /pricing # ad-hoc comparison
|
|
76
|
+
pre-post before.png after.png # diff two images
|
|
77
|
+
pre-post detect # which routes does this branch touch?
|
|
78
|
+
pre-post login https://staging.acme.com # sign in once; the session is reused
|
|
79
|
+
pre-post prune --days 90 # clean up the assets branch
|
|
80
|
+
pre-post doctor # browser, token, dev server, config
|
|
188
81
|
```
|
|
189
82
|
|
|
190
|
-
|
|
83
|
+
When something needs a human, the CLI exits with code 3 and one sentence saying what to do
|
|
84
|
+
(log in, start the dev server, pass `--before`). Re-running picks up where it left off.
|
|
191
85
|
|
|
192
|
-
|
|
193
|
-
pre-post url1 url2 --full
|
|
194
|
-
```
|
|
86
|
+
## Configuration
|
|
195
87
|
|
|
196
|
-
|
|
88
|
+
Optional `.pre-post.json` in the repo root:
|
|
197
89
|
|
|
198
|
-
```
|
|
199
|
-
|
|
90
|
+
```json
|
|
91
|
+
{
|
|
92
|
+
"before": "https://acme.com",
|
|
93
|
+
"routes": ["/"],
|
|
94
|
+
"samples": { "/blog/[slug]": "/blog/hello-world" },
|
|
95
|
+
"viewports": ["desktop", "mobile"],
|
|
96
|
+
"fullPage": true,
|
|
97
|
+
"maxHeight": 2400,
|
|
98
|
+
"scale": 2,
|
|
99
|
+
"threshold": 0.001,
|
|
100
|
+
"minChangedPixels": 40,
|
|
101
|
+
"maxRoutes": 6,
|
|
102
|
+
"ignore": ["apps/docs"],
|
|
103
|
+
"headers": {},
|
|
104
|
+
"assetsBranch": "pre-post-assets"
|
|
105
|
+
}
|
|
200
106
|
```
|
|
201
107
|
|
|
202
|
-
|
|
108
|
+
Environment:
|
|
203
109
|
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
110
|
+
| Variable | Purpose |
|
|
111
|
+
|---|---|
|
|
112
|
+
| `GH_TOKEN` / `GITHUB_TOKEN` | GitHub token (default: `gh auth token`) |
|
|
113
|
+
| `VERCEL_AUTOMATION_BYPASS_SECRET` | Bypass Vercel Deployment Protection on the production URL |
|
|
114
|
+
| `PRE_POST_CONCURRENCY` | Parallel pages (default 6) |
|
|
115
|
+
| `PLAYWRIGHT_CHROMIUM_EXECUTABLE_PATH` | Use a specific Chromium binary |
|
|
116
|
+
| `GH_REPO` | `owner/repo` when the remote URL cannot be parsed |
|
|
207
117
|
|
|
208
|
-
|
|
118
|
+
## Library
|
|
209
119
|
|
|
210
|
-
```
|
|
211
|
-
|
|
120
|
+
```ts
|
|
121
|
+
import { runPr, captureScreenshot, diffImages, detectRoutesForRepo } from '@juangadm/pre-post';
|
|
212
122
|
```
|
|
213
123
|
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
## Route Detection
|
|
217
|
-
|
|
218
|
-
Pre-post automatically maps `git diff --name-only` to affected UI routes:
|
|
219
|
-
|
|
220
|
-
| Changed File | Detected Route | Confidence |
|
|
221
|
-
|---|---|---|
|
|
222
|
-
| `app/page.tsx` | `/` | high |
|
|
223
|
-
| `app/dashboard/page.tsx` | `/dashboard` | high |
|
|
224
|
-
| `app/(marketing)/about/page.tsx` | `/about` (strips route groups) | high |
|
|
225
|
-
| `app/blog/[slug]/page.tsx` | `/blog/[slug]` | high |
|
|
226
|
-
| `app/dashboard/layout.tsx` | `/dashboard` | medium |
|
|
227
|
-
| `app/dashboard/components/Chart.tsx` | `/dashboard` | medium |
|
|
228
|
-
| `globals.css`, `tailwind.config.ts` | `/` | low |
|
|
229
|
-
| `app/api/*`, `middleware.ts` | Skipped (no visual) | -- |
|
|
230
|
-
|
|
231
|
-
Supports:
|
|
232
|
-
- **Next.js App Router** (route groups, dynamic segments, parallel routes, catch-all)
|
|
233
|
-
- **Next.js Pages Router** (`pages/`, `_app.tsx`, `_document.tsx`)
|
|
234
|
-
- **Remix** (`routes/` directory)
|
|
235
|
-
- **SvelteKit** (`src/routes/+page.svelte`)
|
|
236
|
-
- **Generic fallback** (defaults to `/`)
|
|
237
|
-
|
|
238
|
-
## Add Skill
|
|
239
|
-
|
|
240
|
-
Install as a Claude Code skill:
|
|
124
|
+
## Development
|
|
241
125
|
|
|
242
126
|
```bash
|
|
243
|
-
|
|
127
|
+
pnpm install
|
|
128
|
+
pnpm build
|
|
129
|
+
pnpm test:unit
|
|
130
|
+
TEST_BROWSER=true pnpm test # needs a Chromium; npx playwright-core install chromium-headless-shell
|
|
244
131
|
```
|
|
245
132
|
|
|
246
|
-
The skill uses `gh` to detect the associated PR and Playwright for screenshots.
|
|
247
|
-
|
|
248
|
-
## Credits
|
|
249
|
-
|
|
250
|
-
- Original [before-and-after](https://github.com/vercel-labs/before-and-after) by [James Clements](https://github.com/jamesclement) at [Vercel Labs](https://github.com/vercel-labs)
|
|
251
|
-
- Browser automation powered by [Playwright](https://playwright.dev/)
|
|
252
|
-
|
|
253
133
|
## License
|
|
254
134
|
|
|
255
135
|
MIT
|