@onlook/storybook-plugin 0.3.1 → 0.3.2-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 +1 -1
- package/dist/cli/index.js +158 -35
- package/dist/index.d.ts +11 -1
- package/dist/index.js +97308 -464
- package/dist/screenshot-service/index.js +102 -22
- package/package.json +4 -3
|
@@ -93,20 +93,27 @@ async function captureScreenshotBuffer(storyId, theme, width = VIEWPORT_WIDTH, h
|
|
|
93
93
|
await page.goto(url, { timeout: timeoutMs });
|
|
94
94
|
await page.waitForLoadState("domcontentloaded", { timeout: timeoutMs });
|
|
95
95
|
await page.waitForLoadState("load", { timeout: timeoutMs });
|
|
96
|
-
|
|
96
|
+
try {
|
|
97
|
+
await page.waitForLoadState("networkidle", { timeout: 5e3 });
|
|
98
|
+
} catch {
|
|
99
|
+
}
|
|
97
100
|
await page.evaluate(() => document.fonts.ready);
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
101
|
+
try {
|
|
102
|
+
await page.evaluate(async () => {
|
|
103
|
+
const images = document.querySelectorAll("img");
|
|
104
|
+
await Promise.all(
|
|
105
|
+
Array.from(images).map((img) => {
|
|
106
|
+
if (img.complete) return Promise.resolve();
|
|
107
|
+
return new Promise((resolve) => {
|
|
108
|
+
img.addEventListener("load", resolve);
|
|
109
|
+
img.addEventListener("error", resolve);
|
|
110
|
+
setTimeout(resolve, 3e3);
|
|
111
|
+
});
|
|
112
|
+
})
|
|
113
|
+
);
|
|
114
|
+
});
|
|
115
|
+
} catch {
|
|
116
|
+
}
|
|
110
117
|
const contentBounds = await page.evaluate(() => {
|
|
111
118
|
const root = document.querySelector("#storybook-root");
|
|
112
119
|
if (!root) return null;
|
|
@@ -181,6 +188,33 @@ async function generateScreenshot(storyId, theme, storybookUrl = "http://localho
|
|
|
181
188
|
}
|
|
182
189
|
|
|
183
190
|
// src/screenshot-service/screenshot-service.ts
|
|
191
|
+
var StoryTimeoutError = class extends Error {
|
|
192
|
+
constructor(storyId, timeoutMs) {
|
|
193
|
+
super(`Story ${storyId} timed out after ${timeoutMs / 1e3}s`);
|
|
194
|
+
this.storyId = storyId;
|
|
195
|
+
this.timeoutMs = timeoutMs;
|
|
196
|
+
this.name = "StoryTimeoutError";
|
|
197
|
+
}
|
|
198
|
+
};
|
|
199
|
+
async function captureBothThemes(storyId, storybookUrl, timeoutMs, storyTimeoutMs) {
|
|
200
|
+
let timer;
|
|
201
|
+
try {
|
|
202
|
+
return await Promise.race([
|
|
203
|
+
Promise.all([
|
|
204
|
+
generateScreenshot(storyId, "light", storybookUrl, timeoutMs),
|
|
205
|
+
generateScreenshot(storyId, "dark", storybookUrl, timeoutMs)
|
|
206
|
+
]),
|
|
207
|
+
new Promise((_, reject) => {
|
|
208
|
+
timer = setTimeout(
|
|
209
|
+
() => reject(new StoryTimeoutError(storyId, storyTimeoutMs)),
|
|
210
|
+
storyTimeoutMs
|
|
211
|
+
);
|
|
212
|
+
})
|
|
213
|
+
]);
|
|
214
|
+
} finally {
|
|
215
|
+
if (timer) clearTimeout(timer);
|
|
216
|
+
}
|
|
217
|
+
}
|
|
184
218
|
async function generateAllScreenshots(stories, storybookUrl = "http://localhost:6006", concurrency = 10, offset = 0, total, skipExisting = false, timeoutMs = 3e4) {
|
|
185
219
|
const displayTotal = total ?? offset + stories.length;
|
|
186
220
|
console.log(
|
|
@@ -191,6 +225,7 @@ async function generateAllScreenshots(stories, storybookUrl = "http://localhost:
|
|
|
191
225
|
for (let i = 0; i < stories.length; i += BATCH_SIZE) {
|
|
192
226
|
batches.push(stories.slice(i, i + BATCH_SIZE));
|
|
193
227
|
}
|
|
228
|
+
const storyTimeout = timeoutMs * 2 + 1e4;
|
|
194
229
|
let completed = 0;
|
|
195
230
|
for (const batch of batches) {
|
|
196
231
|
await Promise.all(
|
|
@@ -201,19 +236,64 @@ async function generateAllScreenshots(stories, storybookUrl = "http://localhost:
|
|
|
201
236
|
console.log(`[${absoluteIndex2}/${displayTotal}] Skipped (exists) ${story.id}`);
|
|
202
237
|
return;
|
|
203
238
|
}
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
239
|
+
let lightResult = null;
|
|
240
|
+
let darkResult = null;
|
|
241
|
+
let lastError;
|
|
242
|
+
const startedAt = Date.now();
|
|
243
|
+
let attempts = 0;
|
|
244
|
+
const maxAttempts = 2;
|
|
245
|
+
while (attempts < maxAttempts) {
|
|
246
|
+
attempts++;
|
|
247
|
+
try {
|
|
248
|
+
[lightResult, darkResult] = await captureBothThemes(
|
|
249
|
+
story.id,
|
|
250
|
+
storybookUrl,
|
|
251
|
+
timeoutMs,
|
|
252
|
+
storyTimeout
|
|
253
|
+
);
|
|
254
|
+
lastError = void 0;
|
|
255
|
+
break;
|
|
256
|
+
} catch (error) {
|
|
257
|
+
lastError = error;
|
|
258
|
+
if (!(error instanceof StoryTimeoutError) || attempts >= maxAttempts) {
|
|
259
|
+
break;
|
|
260
|
+
}
|
|
261
|
+
console.warn(
|
|
262
|
+
`[screenshot] Retrying ${story.id} after timeout (attempt ${attempts + 1}/${maxAttempts})`
|
|
263
|
+
);
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
completed++;
|
|
267
|
+
const absoluteIndex = offset + completed;
|
|
268
|
+
const durationMs = Date.now() - startedAt;
|
|
208
269
|
if (lightResult && darkResult) {
|
|
209
270
|
const fileHash = computeFileHash(story.importPath);
|
|
210
271
|
updateManifest(story.id, story.importPath, fileHash, lightResult.boundingBox);
|
|
272
|
+
console.log(
|
|
273
|
+
`[${absoluteIndex}/${displayTotal}] Generated screenshots for ${story.id}`,
|
|
274
|
+
{ storyId: story.id, attempts, durationMs, outcome: "ok" }
|
|
275
|
+
);
|
|
276
|
+
} else if (lastError) {
|
|
277
|
+
console.error(
|
|
278
|
+
`[${absoluteIndex}/${displayTotal}] \u26A0\uFE0F Failed ${story.id}:`,
|
|
279
|
+
lastError instanceof Error ? lastError.message : lastError,
|
|
280
|
+
{
|
|
281
|
+
storyId: story.id,
|
|
282
|
+
attempts,
|
|
283
|
+
durationMs,
|
|
284
|
+
outcome: lastError instanceof StoryTimeoutError ? "timeout" : "error"
|
|
285
|
+
}
|
|
286
|
+
);
|
|
287
|
+
} else {
|
|
288
|
+
console.warn(`[${absoluteIndex}/${displayTotal}] Partial result ${story.id}`, {
|
|
289
|
+
storyId: story.id,
|
|
290
|
+
attempts,
|
|
291
|
+
durationMs,
|
|
292
|
+
outcome: "partial",
|
|
293
|
+
hasLight: !!lightResult,
|
|
294
|
+
hasDark: !!darkResult
|
|
295
|
+
});
|
|
211
296
|
}
|
|
212
|
-
completed++;
|
|
213
|
-
const absoluteIndex = offset + completed;
|
|
214
|
-
console.log(
|
|
215
|
-
`[${absoluteIndex}/${displayTotal}] Generated screenshots for ${story.id}`
|
|
216
|
-
);
|
|
217
297
|
})
|
|
218
298
|
);
|
|
219
299
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@onlook/storybook-plugin",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.2-beta.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"bin": {
|
|
6
6
|
"onlook-storybook": "./dist/cli/index.js"
|
|
@@ -29,7 +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": "
|
|
32
|
+
"publish-pkg": "bun publish",
|
|
33
|
+
"publish-beta": "bun publish --tag beta"
|
|
33
34
|
},
|
|
34
35
|
"dependencies": {
|
|
35
36
|
"@babel/generator": "^7.26.9",
|
|
@@ -40,7 +41,7 @@
|
|
|
40
41
|
"playwright": "^1.52.0"
|
|
41
42
|
},
|
|
42
43
|
"devDependencies": {
|
|
43
|
-
"@onbook/tsconfig": "
|
|
44
|
+
"@onbook/tsconfig": "0.1.0",
|
|
44
45
|
"@types/babel__generator": "^7.6.8",
|
|
45
46
|
"@types/babel__traverse": "^7.20.6",
|
|
46
47
|
"@types/node": "^22.15.32",
|