@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
|
@@ -1,12 +1,6 @@
|
|
|
1
1
|
export { closeBrowser } from './utils/browser/index.js';
|
|
2
2
|
import 'playwright';
|
|
3
3
|
|
|
4
|
-
/**
|
|
5
|
-
* Generate screenshots for all stories (parallelized for speed)
|
|
6
|
-
*
|
|
7
|
-
* @param offset - Absolute index offset for logging (e.g. skip=200 → offset=200)
|
|
8
|
-
* @param total - Total number of stories across all runs (for [n/total] logging)
|
|
9
|
-
*/
|
|
10
4
|
declare function generateAllScreenshots(stories: Array<{
|
|
11
5
|
id: string;
|
|
12
6
|
importPath: string;
|
|
@@ -1,9 +1,10 @@
|
|
|
1
|
+
import { createRequire } from 'node:module';
|
|
1
2
|
import crypto from 'crypto';
|
|
2
3
|
import fs from 'fs';
|
|
3
4
|
import path from 'path';
|
|
4
5
|
import { chromium } from 'playwright';
|
|
5
6
|
|
|
6
|
-
|
|
7
|
+
globalThis.require = createRequire(import.meta.url);
|
|
7
8
|
var CACHE_DIR = path.join(process.cwd(), ".storybook-cache");
|
|
8
9
|
var SCREENSHOTS_DIR = path.join(CACHE_DIR, "screenshots");
|
|
9
10
|
var MANIFEST_PATH = path.join(CACHE_DIR, "manifest.json");
|
|
@@ -188,6 +189,33 @@ async function generateScreenshot(storyId, theme, storybookUrl = "http://localho
|
|
|
188
189
|
}
|
|
189
190
|
|
|
190
191
|
// src/screenshot-service/screenshot-service.ts
|
|
192
|
+
var StoryTimeoutError = class extends Error {
|
|
193
|
+
constructor(storyId, timeoutMs) {
|
|
194
|
+
super(`Story ${storyId} timed out after ${timeoutMs / 1e3}s`);
|
|
195
|
+
this.storyId = storyId;
|
|
196
|
+
this.timeoutMs = timeoutMs;
|
|
197
|
+
this.name = "StoryTimeoutError";
|
|
198
|
+
}
|
|
199
|
+
};
|
|
200
|
+
async function captureBothThemes(storyId, storybookUrl, timeoutMs, storyTimeoutMs) {
|
|
201
|
+
let timer;
|
|
202
|
+
try {
|
|
203
|
+
return await Promise.race([
|
|
204
|
+
Promise.all([
|
|
205
|
+
generateScreenshot(storyId, "light", storybookUrl, timeoutMs),
|
|
206
|
+
generateScreenshot(storyId, "dark", storybookUrl, timeoutMs)
|
|
207
|
+
]),
|
|
208
|
+
new Promise((_, reject) => {
|
|
209
|
+
timer = setTimeout(
|
|
210
|
+
() => reject(new StoryTimeoutError(storyId, storyTimeoutMs)),
|
|
211
|
+
storyTimeoutMs
|
|
212
|
+
);
|
|
213
|
+
})
|
|
214
|
+
]);
|
|
215
|
+
} finally {
|
|
216
|
+
if (timer) clearTimeout(timer);
|
|
217
|
+
}
|
|
218
|
+
}
|
|
191
219
|
async function generateAllScreenshots(stories, storybookUrl = "http://localhost:6006", concurrency = 10, offset = 0, total, skipExisting = false, timeoutMs = 3e4) {
|
|
192
220
|
const displayTotal = total ?? offset + stories.length;
|
|
193
221
|
console.log(
|
|
@@ -198,53 +226,74 @@ async function generateAllScreenshots(stories, storybookUrl = "http://localhost:
|
|
|
198
226
|
for (let i = 0; i < stories.length; i += BATCH_SIZE) {
|
|
199
227
|
batches.push(stories.slice(i, i + BATCH_SIZE));
|
|
200
228
|
}
|
|
229
|
+
const storyTimeout = timeoutMs * 2 + 1e4;
|
|
201
230
|
let completed = 0;
|
|
202
231
|
for (const batch of batches) {
|
|
203
232
|
await Promise.all(
|
|
204
233
|
batch.map(async (story) => {
|
|
205
234
|
if (skipExisting && screenshotExists(story.id, "light") && screenshotExists(story.id, "dark")) {
|
|
206
235
|
completed++;
|
|
207
|
-
const
|
|
208
|
-
console.log(`[${
|
|
236
|
+
const absoluteIndex2 = offset + completed;
|
|
237
|
+
console.log(`[${absoluteIndex2}/${displayTotal}] Skipped (exists) ${story.id}`);
|
|
209
238
|
return;
|
|
210
239
|
}
|
|
211
|
-
|
|
212
|
-
let
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
240
|
+
let lightResult = null;
|
|
241
|
+
let darkResult = null;
|
|
242
|
+
let lastError;
|
|
243
|
+
const startedAt = Date.now();
|
|
244
|
+
let attempts = 0;
|
|
245
|
+
const maxAttempts = 2;
|
|
246
|
+
while (attempts < maxAttempts) {
|
|
247
|
+
attempts++;
|
|
248
|
+
try {
|
|
249
|
+
[lightResult, darkResult] = await captureBothThemes(
|
|
250
|
+
story.id,
|
|
251
|
+
storybookUrl,
|
|
252
|
+
timeoutMs,
|
|
253
|
+
storyTimeout
|
|
254
|
+
);
|
|
255
|
+
lastError = void 0;
|
|
256
|
+
break;
|
|
257
|
+
} catch (error) {
|
|
258
|
+
lastError = error;
|
|
259
|
+
if (!(error instanceof StoryTimeoutError) || attempts >= maxAttempts) {
|
|
260
|
+
break;
|
|
261
|
+
}
|
|
262
|
+
console.warn(
|
|
263
|
+
`[screenshot] Retrying ${story.id} after timeout (attempt ${attempts + 1}/${maxAttempts})`
|
|
264
|
+
);
|
|
235
265
|
}
|
|
236
|
-
|
|
237
|
-
|
|
266
|
+
}
|
|
267
|
+
completed++;
|
|
268
|
+
const absoluteIndex = offset + completed;
|
|
269
|
+
const durationMs = Date.now() - startedAt;
|
|
270
|
+
if (lightResult && darkResult) {
|
|
271
|
+
const fileHash = computeFileHash(story.importPath);
|
|
272
|
+
updateManifest(story.id, story.importPath, fileHash, lightResult.boundingBox);
|
|
238
273
|
console.log(
|
|
239
|
-
`[${absoluteIndex}/${displayTotal}] Generated screenshots for ${story.id}
|
|
274
|
+
`[${absoluteIndex}/${displayTotal}] Generated screenshots for ${story.id}`,
|
|
275
|
+
{ storyId: story.id, attempts, durationMs, outcome: "ok" }
|
|
240
276
|
);
|
|
241
|
-
}
|
|
242
|
-
completed++;
|
|
243
|
-
const absoluteIndex = offset + completed;
|
|
277
|
+
} else if (lastError) {
|
|
244
278
|
console.error(
|
|
245
279
|
`[${absoluteIndex}/${displayTotal}] \u26A0\uFE0F Failed ${story.id}:`,
|
|
246
|
-
|
|
280
|
+
lastError instanceof Error ? lastError.message : lastError,
|
|
281
|
+
{
|
|
282
|
+
storyId: story.id,
|
|
283
|
+
attempts,
|
|
284
|
+
durationMs,
|
|
285
|
+
outcome: lastError instanceof StoryTimeoutError ? "timeout" : "error"
|
|
286
|
+
}
|
|
247
287
|
);
|
|
288
|
+
} else {
|
|
289
|
+
console.warn(`[${absoluteIndex}/${displayTotal}] Partial result ${story.id}`, {
|
|
290
|
+
storyId: story.id,
|
|
291
|
+
attempts,
|
|
292
|
+
durationMs,
|
|
293
|
+
outcome: "partial",
|
|
294
|
+
hasLight: !!lightResult,
|
|
295
|
+
hasDark: !!darkResult
|
|
296
|
+
});
|
|
248
297
|
}
|
|
249
298
|
})
|
|
250
299
|
);
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
+
import { createRequire } from 'node:module';
|
|
1
2
|
import { chromium } from 'playwright';
|
|
2
3
|
|
|
3
|
-
|
|
4
|
+
globalThis.require = createRequire(import.meta.url);
|
|
4
5
|
var browser = null;
|
|
5
6
|
async function getBrowser() {
|
|
6
7
|
if (!browser) {
|
package/package.json
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@onlook/storybook-plugin",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.7-beta.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"bin": {
|
|
6
|
-
"onlook-storybook": "dist/cli/index.js"
|
|
6
|
+
"onlook-storybook": "./dist/cli/index.js"
|
|
7
7
|
},
|
|
8
8
|
"exports": {
|
|
9
9
|
".": {
|
|
@@ -29,9 +29,8 @@
|
|
|
29
29
|
"typecheck": "tsc --noEmit",
|
|
30
30
|
"prepublishOnly": "bun run build && bun scripts/prepublish.ts",
|
|
31
31
|
"postpublish": "bun scripts/postpublish.ts",
|
|
32
|
-
"publish-pkg": "
|
|
33
|
-
"publish-
|
|
34
|
-
"promote-latest": "npm dist-tag add @onlook/storybook-plugin@$(node -p \"require('./package.json').version\") latest"
|
|
32
|
+
"publish-pkg": "bun publish",
|
|
33
|
+
"publish-beta": "bun publish --tag beta"
|
|
35
34
|
},
|
|
36
35
|
"dependencies": {
|
|
37
36
|
"@babel/generator": "^7.26.9",
|
|
@@ -39,15 +38,16 @@
|
|
|
39
38
|
"@babel/traverse": "^7.26.9",
|
|
40
39
|
"@babel/types": "^7.26.9",
|
|
41
40
|
"@drizzle-team/brocli": "^0.11.0",
|
|
42
|
-
"
|
|
41
|
+
"@liveblocks/client": "3.11.0",
|
|
42
|
+
"playwright": "^1.52.0",
|
|
43
|
+
"ws": "^8.18.0"
|
|
43
44
|
},
|
|
44
45
|
"devDependencies": {
|
|
45
|
-
"@onbook/tsconfig": "
|
|
46
|
+
"@onbook/tsconfig": "0.1.0",
|
|
46
47
|
"@types/babel__generator": "^7.6.8",
|
|
47
48
|
"@types/babel__traverse": "^7.20.6",
|
|
48
49
|
"@types/node": "^22.15.32",
|
|
49
50
|
"bun-types": "^1.3.5",
|
|
50
|
-
"storybook": "^10.1.11",
|
|
51
51
|
"tsup": "^8.5.1",
|
|
52
52
|
"typescript": "5.8.3",
|
|
53
53
|
"vite": "^6.3.5"
|
|
@@ -56,7 +56,6 @@
|
|
|
56
56
|
"access": "public"
|
|
57
57
|
},
|
|
58
58
|
"peerDependencies": {
|
|
59
|
-
"storybook": "^10.0.0",
|
|
60
59
|
"vite": "^5.0.0 || ^6.0.0"
|
|
61
60
|
}
|
|
62
61
|
}
|