@onlook/storybook-plugin 0.3.5 → 0.3.7-beta.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 +0 -21
- package/dist/cli/index.js +83 -33
- package/dist/index.d.ts +4 -0
- package/dist/index.js +97421 -636
- package/dist/screenshot-service/index.d.ts +0 -6
- package/dist/screenshot-service/index.js +83 -34
- package/dist/screenshot-service/utils/browser/index.js +2 -1
- package/package.json +8 -9
package/README.md
CHANGED
|
@@ -76,27 +76,6 @@ Screenshots are saved to `.storybook-cache/screenshots/`.
|
|
|
76
76
|
|
|
77
77
|
The plugin auto-disables when `CHROMATIC` or `CI` environment variables are set.
|
|
78
78
|
|
|
79
|
-
## Publishing
|
|
80
|
-
|
|
81
|
-
Three release paths:
|
|
82
|
-
|
|
83
|
-
```bash
|
|
84
|
-
# 1. Ship the current version to npm as `latest` (default dist-tag).
|
|
85
|
-
bun run publish-pkg
|
|
86
|
-
|
|
87
|
-
# 2. Ship under the `next` dist-tag — for testing against preview deploys
|
|
88
|
-
# without affecting consumers pinned to ^x.y.z ranges. Consumers opt in
|
|
89
|
-
# via `@onlook/storybook-plugin@next`.
|
|
90
|
-
bun run publish-pkg:next
|
|
91
|
-
|
|
92
|
-
# 3. Promote a previously-published version to `latest`. Reads the version
|
|
93
|
-
# from package.json, so bump first if you want to promote something else.
|
|
94
|
-
bun run promote-latest
|
|
95
|
-
```
|
|
96
|
-
|
|
97
|
-
The typical flow for risky changes: `publish-pkg:next` → test against a
|
|
98
|
-
Vercel preview deploy → `promote-latest` once confident.
|
|
99
|
-
|
|
100
79
|
## License
|
|
101
80
|
|
|
102
81
|
MIT
|
package/dist/cli/index.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
import { createRequire } from 'node:module';
|
|
2
3
|
import { command, string, boolean, run } from '@drizzle-team/brocli';
|
|
3
4
|
import { spawn } from 'child_process';
|
|
4
5
|
import fs, { readFileSync, existsSync } from 'fs';
|
|
@@ -6,6 +7,7 @@ import path, { resolve, join, dirname } from 'path';
|
|
|
6
7
|
import crypto from 'crypto';
|
|
7
8
|
import { chromium } from 'playwright';
|
|
8
9
|
|
|
10
|
+
globalThis.require = createRequire(import.meta.url);
|
|
9
11
|
var CACHE_DIR = path.join(process.cwd(), ".storybook-cache");
|
|
10
12
|
var SCREENSHOTS_DIR = path.join(CACHE_DIR, "screenshots");
|
|
11
13
|
var MANIFEST_PATH = path.join(CACHE_DIR, "manifest.json");
|
|
@@ -190,6 +192,33 @@ async function generateScreenshot(storyId, theme, storybookUrl = "http://localho
|
|
|
190
192
|
}
|
|
191
193
|
|
|
192
194
|
// src/screenshot-service/screenshot-service.ts
|
|
195
|
+
var StoryTimeoutError = class extends Error {
|
|
196
|
+
constructor(storyId, timeoutMs) {
|
|
197
|
+
super(`Story ${storyId} timed out after ${timeoutMs / 1e3}s`);
|
|
198
|
+
this.storyId = storyId;
|
|
199
|
+
this.timeoutMs = timeoutMs;
|
|
200
|
+
this.name = "StoryTimeoutError";
|
|
201
|
+
}
|
|
202
|
+
};
|
|
203
|
+
async function captureBothThemes(storyId, storybookUrl, timeoutMs, storyTimeoutMs) {
|
|
204
|
+
let timer;
|
|
205
|
+
try {
|
|
206
|
+
return await Promise.race([
|
|
207
|
+
Promise.all([
|
|
208
|
+
generateScreenshot(storyId, "light", storybookUrl, timeoutMs),
|
|
209
|
+
generateScreenshot(storyId, "dark", storybookUrl, timeoutMs)
|
|
210
|
+
]),
|
|
211
|
+
new Promise((_, reject) => {
|
|
212
|
+
timer = setTimeout(
|
|
213
|
+
() => reject(new StoryTimeoutError(storyId, storyTimeoutMs)),
|
|
214
|
+
storyTimeoutMs
|
|
215
|
+
);
|
|
216
|
+
})
|
|
217
|
+
]);
|
|
218
|
+
} finally {
|
|
219
|
+
if (timer) clearTimeout(timer);
|
|
220
|
+
}
|
|
221
|
+
}
|
|
193
222
|
async function generateAllScreenshots(stories, storybookUrl = "http://localhost:6006", concurrency = 10, offset = 0, total, skipExisting = false, timeoutMs = 3e4) {
|
|
194
223
|
const displayTotal = total ?? offset + stories.length;
|
|
195
224
|
console.log(
|
|
@@ -200,53 +229,74 @@ async function generateAllScreenshots(stories, storybookUrl = "http://localhost:
|
|
|
200
229
|
for (let i = 0; i < stories.length; i += BATCH_SIZE) {
|
|
201
230
|
batches.push(stories.slice(i, i + BATCH_SIZE));
|
|
202
231
|
}
|
|
232
|
+
const storyTimeout = timeoutMs * 2 + 1e4;
|
|
203
233
|
let completed = 0;
|
|
204
234
|
for (const batch of batches) {
|
|
205
235
|
await Promise.all(
|
|
206
236
|
batch.map(async (story) => {
|
|
207
237
|
if (skipExisting && screenshotExists(story.id, "light") && screenshotExists(story.id, "dark")) {
|
|
208
238
|
completed++;
|
|
209
|
-
const
|
|
210
|
-
console.log(`[${
|
|
239
|
+
const absoluteIndex2 = offset + completed;
|
|
240
|
+
console.log(`[${absoluteIndex2}/${displayTotal}] Skipped (exists) ${story.id}`);
|
|
211
241
|
return;
|
|
212
242
|
}
|
|
213
|
-
|
|
214
|
-
let
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
243
|
+
let lightResult = null;
|
|
244
|
+
let darkResult = null;
|
|
245
|
+
let lastError;
|
|
246
|
+
const startedAt = Date.now();
|
|
247
|
+
let attempts = 0;
|
|
248
|
+
const maxAttempts = 2;
|
|
249
|
+
while (attempts < maxAttempts) {
|
|
250
|
+
attempts++;
|
|
251
|
+
try {
|
|
252
|
+
[lightResult, darkResult] = await captureBothThemes(
|
|
253
|
+
story.id,
|
|
254
|
+
storybookUrl,
|
|
255
|
+
timeoutMs,
|
|
256
|
+
storyTimeout
|
|
257
|
+
);
|
|
258
|
+
lastError = void 0;
|
|
259
|
+
break;
|
|
260
|
+
} catch (error) {
|
|
261
|
+
lastError = error;
|
|
262
|
+
if (!(error instanceof StoryTimeoutError) || attempts >= maxAttempts) {
|
|
263
|
+
break;
|
|
264
|
+
}
|
|
265
|
+
console.warn(
|
|
266
|
+
`[screenshot] Retrying ${story.id} after timeout (attempt ${attempts + 1}/${maxAttempts})`
|
|
267
|
+
);
|
|
237
268
|
}
|
|
238
|
-
|
|
239
|
-
|
|
269
|
+
}
|
|
270
|
+
completed++;
|
|
271
|
+
const absoluteIndex = offset + completed;
|
|
272
|
+
const durationMs = Date.now() - startedAt;
|
|
273
|
+
if (lightResult && darkResult) {
|
|
274
|
+
const fileHash = computeFileHash(story.importPath);
|
|
275
|
+
updateManifest(story.id, story.importPath, fileHash, lightResult.boundingBox);
|
|
240
276
|
console.log(
|
|
241
|
-
`[${absoluteIndex}/${displayTotal}] Generated screenshots for ${story.id}
|
|
277
|
+
`[${absoluteIndex}/${displayTotal}] Generated screenshots for ${story.id}`,
|
|
278
|
+
{ storyId: story.id, attempts, durationMs, outcome: "ok" }
|
|
242
279
|
);
|
|
243
|
-
}
|
|
244
|
-
completed++;
|
|
245
|
-
const absoluteIndex = offset + completed;
|
|
280
|
+
} else if (lastError) {
|
|
246
281
|
console.error(
|
|
247
282
|
`[${absoluteIndex}/${displayTotal}] \u26A0\uFE0F Failed ${story.id}:`,
|
|
248
|
-
|
|
283
|
+
lastError instanceof Error ? lastError.message : lastError,
|
|
284
|
+
{
|
|
285
|
+
storyId: story.id,
|
|
286
|
+
attempts,
|
|
287
|
+
durationMs,
|
|
288
|
+
outcome: lastError instanceof StoryTimeoutError ? "timeout" : "error"
|
|
289
|
+
}
|
|
249
290
|
);
|
|
291
|
+
} else {
|
|
292
|
+
console.warn(`[${absoluteIndex}/${displayTotal}] Partial result ${story.id}`, {
|
|
293
|
+
storyId: story.id,
|
|
294
|
+
attempts,
|
|
295
|
+
durationMs,
|
|
296
|
+
outcome: "partial",
|
|
297
|
+
hasLight: !!lightResult,
|
|
298
|
+
hasDark: !!darkResult
|
|
299
|
+
});
|
|
250
300
|
}
|
|
251
301
|
})
|
|
252
302
|
);
|
package/dist/index.d.ts
CHANGED
|
@@ -6,6 +6,10 @@ type OnlookPluginOptions = {
|
|
|
6
6
|
port?: number;
|
|
7
7
|
/** Additional allowed origins for CORS (merged with defaults) */
|
|
8
8
|
allowedOrigins?: string[];
|
|
9
|
+
hmr?: {
|
|
10
|
+
protocol?: 'ws' | 'wss';
|
|
11
|
+
clientPort?: number;
|
|
12
|
+
};
|
|
9
13
|
};
|
|
10
14
|
declare function storybookOnlookPlugin(options?: OnlookPluginOptions): PluginOption[];
|
|
11
15
|
|