@onlook/storybook-plugin 0.3.2 → 0.3.4
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 +22 -1
- package/dist/cli/index.js +115 -40
- package/dist/index.d.ts +4 -1
- package/dist/index.js +44 -31
- package/dist/screenshot-service/index.js +59 -27
- package/package.json +6 -3
package/README.md
CHANGED
|
@@ -44,7 +44,7 @@ Configures Vite HMR for E2B sandboxes (WSS protocol, port 443 routing).
|
|
|
44
44
|
|
|
45
45
|
### CORS
|
|
46
46
|
|
|
47
|
-
Pre-configured for `https://app.onlook.
|
|
47
|
+
Pre-configured for `https://app.onlook.com`, `localhost:3000`, and `localhost:6006`.
|
|
48
48
|
|
|
49
49
|
## Options
|
|
50
50
|
|
|
@@ -76,6 +76,27 @@ 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
|
+
|
|
79
100
|
## License
|
|
80
101
|
|
|
81
102
|
MIT
|
package/dist/cli/index.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { command, string, boolean, run } from '@drizzle-team/brocli';
|
|
3
3
|
import { spawn } from 'child_process';
|
|
4
|
+
import fs, { readFileSync, existsSync } from 'fs';
|
|
4
5
|
import path, { resolve, join, dirname } from 'path';
|
|
5
6
|
import crypto from 'crypto';
|
|
6
|
-
import fs, { existsSync } from 'fs';
|
|
7
7
|
import { chromium } from 'playwright';
|
|
8
8
|
|
|
9
9
|
var CACHE_DIR = path.join(process.cwd(), ".storybook-cache");
|
|
@@ -95,20 +95,27 @@ async function captureScreenshotBuffer(storyId, theme, width = VIEWPORT_WIDTH, h
|
|
|
95
95
|
await page.goto(url, { timeout: timeoutMs });
|
|
96
96
|
await page.waitForLoadState("domcontentloaded", { timeout: timeoutMs });
|
|
97
97
|
await page.waitForLoadState("load", { timeout: timeoutMs });
|
|
98
|
-
|
|
98
|
+
try {
|
|
99
|
+
await page.waitForLoadState("networkidle", { timeout: 5e3 });
|
|
100
|
+
} catch {
|
|
101
|
+
}
|
|
99
102
|
await page.evaluate(() => document.fonts.ready);
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
103
|
+
try {
|
|
104
|
+
await page.evaluate(async () => {
|
|
105
|
+
const images = document.querySelectorAll("img");
|
|
106
|
+
await Promise.all(
|
|
107
|
+
Array.from(images).map((img) => {
|
|
108
|
+
if (img.complete) return Promise.resolve();
|
|
109
|
+
return new Promise((resolve3) => {
|
|
110
|
+
img.addEventListener("load", resolve3);
|
|
111
|
+
img.addEventListener("error", resolve3);
|
|
112
|
+
setTimeout(resolve3, 3e3);
|
|
113
|
+
});
|
|
114
|
+
})
|
|
115
|
+
);
|
|
116
|
+
});
|
|
117
|
+
} catch {
|
|
118
|
+
}
|
|
112
119
|
const contentBounds = await page.evaluate(() => {
|
|
113
120
|
const root = document.querySelector("#storybook-root");
|
|
114
121
|
if (!root) return null;
|
|
@@ -199,23 +206,48 @@ async function generateAllScreenshots(stories, storybookUrl = "http://localhost:
|
|
|
199
206
|
batch.map(async (story) => {
|
|
200
207
|
if (skipExisting && screenshotExists(story.id, "light") && screenshotExists(story.id, "dark")) {
|
|
201
208
|
completed++;
|
|
202
|
-
const
|
|
203
|
-
console.log(`[${
|
|
209
|
+
const absoluteIndex = offset + completed;
|
|
210
|
+
console.log(`[${absoluteIndex}/${displayTotal}] Skipped (exists) ${story.id}`);
|
|
204
211
|
return;
|
|
205
212
|
}
|
|
206
|
-
const
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
+
const storyTimeout = timeoutMs * 2 + 1e4;
|
|
214
|
+
let timer;
|
|
215
|
+
try {
|
|
216
|
+
const result = await Promise.race([
|
|
217
|
+
Promise.all([
|
|
218
|
+
generateScreenshot(story.id, "light", storybookUrl, timeoutMs),
|
|
219
|
+
generateScreenshot(story.id, "dark", storybookUrl, timeoutMs)
|
|
220
|
+
]),
|
|
221
|
+
new Promise((_, reject) => {
|
|
222
|
+
timer = setTimeout(
|
|
223
|
+
() => reject(
|
|
224
|
+
new Error(
|
|
225
|
+
`Story ${story.id} timed out after ${storyTimeout / 1e3}s`
|
|
226
|
+
)
|
|
227
|
+
),
|
|
228
|
+
storyTimeout
|
|
229
|
+
);
|
|
230
|
+
})
|
|
231
|
+
]);
|
|
232
|
+
clearTimeout(timer);
|
|
233
|
+
const [lightResult, darkResult] = result;
|
|
234
|
+
if (lightResult && darkResult) {
|
|
235
|
+
const fileHash = computeFileHash(story.importPath);
|
|
236
|
+
updateManifest(story.id, story.importPath, fileHash, lightResult.boundingBox);
|
|
237
|
+
}
|
|
238
|
+
completed++;
|
|
239
|
+
const absoluteIndex = offset + completed;
|
|
240
|
+
console.log(
|
|
241
|
+
`[${absoluteIndex}/${displayTotal}] Generated screenshots for ${story.id}`
|
|
242
|
+
);
|
|
243
|
+
} catch (error) {
|
|
244
|
+
completed++;
|
|
245
|
+
const absoluteIndex = offset + completed;
|
|
246
|
+
console.error(
|
|
247
|
+
`[${absoluteIndex}/${displayTotal}] \u26A0\uFE0F Failed ${story.id}:`,
|
|
248
|
+
error instanceof Error ? error.message : error
|
|
249
|
+
);
|
|
213
250
|
}
|
|
214
|
-
completed++;
|
|
215
|
-
const absoluteIndex = offset + completed;
|
|
216
|
-
console.log(
|
|
217
|
-
`[${absoluteIndex}/${displayTotal}] Generated screenshots for ${story.id}`
|
|
218
|
-
);
|
|
219
251
|
})
|
|
220
252
|
);
|
|
221
253
|
}
|
|
@@ -260,10 +292,27 @@ function getStorybookCommand(storybookDir) {
|
|
|
260
292
|
console.log(
|
|
261
293
|
`\u{1F4E6} Detected package manager: ${pm}${repoRoot ? ` (from ${repoRoot})` : ""}`
|
|
262
294
|
);
|
|
263
|
-
|
|
295
|
+
let extraArgs = [];
|
|
296
|
+
try {
|
|
297
|
+
const pkgPath = resolve(storybookDir, "package.json");
|
|
298
|
+
const pkg = JSON.parse(readFileSync(pkgPath, "utf-8"));
|
|
299
|
+
const script = pkg.scripts?.storybook ?? "";
|
|
300
|
+
const hasPort = script.includes("-p ") || script.includes("--port");
|
|
301
|
+
const hasNoOpen = script.includes("--no-open");
|
|
302
|
+
if (!hasPort || !hasNoOpen) {
|
|
303
|
+
const needsSeparator = pm === "npm" || pm === "pnpm";
|
|
304
|
+
const flags = [];
|
|
305
|
+
if (!hasPort) flags.push("-p", "6006");
|
|
306
|
+
if (!hasNoOpen) flags.push("--no-open");
|
|
307
|
+
extraArgs = needsSeparator && flags.length > 0 ? ["--", ...flags] : flags;
|
|
308
|
+
}
|
|
309
|
+
} catch {
|
|
310
|
+
const separator = pm === "npm" || pm === "pnpm" ? ["--"] : [];
|
|
311
|
+
extraArgs = [...separator, "-p", "6006", "--no-open"];
|
|
312
|
+
}
|
|
264
313
|
return {
|
|
265
314
|
command: pm,
|
|
266
|
-
args: ["run", "storybook", ...
|
|
315
|
+
args: ["run", "storybook", ...extraArgs]
|
|
267
316
|
};
|
|
268
317
|
}
|
|
269
318
|
async function isStorybookRunning(url) {
|
|
@@ -276,14 +325,38 @@ async function isStorybookRunning(url) {
|
|
|
276
325
|
return false;
|
|
277
326
|
}
|
|
278
327
|
}
|
|
279
|
-
async function
|
|
328
|
+
async function waitForStorybookReady(url, timeoutMs = 12e4) {
|
|
329
|
+
const start = Date.now();
|
|
330
|
+
const pollInterval = 2e3;
|
|
331
|
+
while (Date.now() - start < timeoutMs) {
|
|
332
|
+
if (await isStorybookRunning(url)) return;
|
|
333
|
+
await new Promise((r) => setTimeout(r, pollInterval));
|
|
334
|
+
}
|
|
335
|
+
throw new Error(`Storybook did not become ready within ${timeoutMs / 1e3}s`);
|
|
336
|
+
}
|
|
337
|
+
async function fetchStoryIndex(url, retries = 3) {
|
|
280
338
|
const indexUrl = `${url}/index.json`;
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
339
|
+
for (let attempt = 1; attempt <= retries; attempt++) {
|
|
340
|
+
try {
|
|
341
|
+
const response = await fetch(indexUrl, {
|
|
342
|
+
signal: AbortSignal.timeout(1e4)
|
|
343
|
+
});
|
|
344
|
+
if (!response.ok) {
|
|
345
|
+
throw new Error(
|
|
346
|
+
`Failed to fetch story index: ${response.status} ${response.statusText}`
|
|
347
|
+
);
|
|
348
|
+
}
|
|
349
|
+
const data = await response.json();
|
|
350
|
+
return Object.values(data.entries);
|
|
351
|
+
} catch (error) {
|
|
352
|
+
if (attempt === retries) throw error;
|
|
353
|
+
console.log(
|
|
354
|
+
`\u26A0\uFE0F Fetch story index failed (attempt ${attempt}/${retries}), retrying in 3s...`
|
|
355
|
+
);
|
|
356
|
+
await new Promise((r) => setTimeout(r, 3e3));
|
|
357
|
+
}
|
|
284
358
|
}
|
|
285
|
-
|
|
286
|
-
return Object.values(data.entries);
|
|
359
|
+
throw new Error("Unreachable");
|
|
287
360
|
}
|
|
288
361
|
async function startStorybook(command2, args, storybookDir) {
|
|
289
362
|
console.log(
|
|
@@ -301,12 +374,12 @@ async function startStorybook(command2, args, storybookDir) {
|
|
|
301
374
|
const timeout = setTimeout(() => {
|
|
302
375
|
if (!started) {
|
|
303
376
|
storybookProcess.kill();
|
|
304
|
-
reject(new Error("Storybook failed to start within
|
|
377
|
+
reject(new Error("Storybook failed to start within 180 seconds"));
|
|
305
378
|
}
|
|
306
|
-
},
|
|
379
|
+
}, 18e4);
|
|
307
380
|
storybookProcess.stdout?.on("data", (data) => {
|
|
308
381
|
const output = data.toString();
|
|
309
|
-
if (output.includes("Local:") || output.includes("localhost:")) {
|
|
382
|
+
if (output.includes("Local:") || output.includes("localhost:") || output.includes("local:")) {
|
|
310
383
|
if (!started) {
|
|
311
384
|
started = true;
|
|
312
385
|
clearTimeout(timeout);
|
|
@@ -335,7 +408,7 @@ async function warmupStorybook(url, firstStoryId) {
|
|
|
335
408
|
try {
|
|
336
409
|
const warmupUrl = `${url}/iframe.html?id=${firstStoryId}&viewMode=story`;
|
|
337
410
|
await page.goto(warmupUrl, { timeout: 15e3 });
|
|
338
|
-
await page.waitForLoadState("
|
|
411
|
+
await page.waitForLoadState("domcontentloaded", { timeout: 15e3 });
|
|
339
412
|
console.log("\u2705 Storybook warmed up");
|
|
340
413
|
} catch {
|
|
341
414
|
console.log("\u26A0\uFE0F Warmup had issues, proceeding anyway");
|
|
@@ -358,6 +431,8 @@ async function generateScreenshots(options = {}) {
|
|
|
358
431
|
const { command: command2, args } = getStorybookCommand(storybookDir);
|
|
359
432
|
storybookProcess = await startStorybook(command2, args, storybookDir);
|
|
360
433
|
weStartedStorybook = true;
|
|
434
|
+
console.log("\u23F3 Waiting for Storybook to finish compiling...");
|
|
435
|
+
await waitForStorybookReady(url);
|
|
361
436
|
}
|
|
362
437
|
const allStories = await fetchStoryIndex(url);
|
|
363
438
|
const total = allStories.length;
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { PluginOption } from 'vite';
|
|
2
|
+
import { Indexer } from 'storybook/internal/types';
|
|
2
3
|
|
|
3
4
|
type OnlookPluginOptions = {
|
|
4
5
|
/** Storybook port (default: 6006) */
|
|
@@ -8,4 +9,6 @@ type OnlookPluginOptions = {
|
|
|
8
9
|
};
|
|
9
10
|
declare function storybookOnlookPlugin(options?: OnlookPluginOptions): PluginOption[];
|
|
10
11
|
|
|
11
|
-
|
|
12
|
+
declare const tolerantCsfIndexer: Indexer;
|
|
13
|
+
|
|
14
|
+
export { type OnlookPluginOptions, storybookOnlookPlugin, tolerantCsfIndexer };
|
package/dist/index.js
CHANGED
|
@@ -7,6 +7,7 @@ import traverseModule from '@babel/traverse';
|
|
|
7
7
|
import * as t from '@babel/types';
|
|
8
8
|
import crypto from 'crypto';
|
|
9
9
|
import { chromium } from 'playwright';
|
|
10
|
+
import { readCsf } from 'storybook/internal/csf-tools';
|
|
10
11
|
|
|
11
12
|
// src/storybook-onlook-plugin.ts
|
|
12
13
|
function componentLocPlugin(options = {}) {
|
|
@@ -142,20 +143,27 @@ async function captureScreenshotBuffer(storyId, theme, width = VIEWPORT_WIDTH, h
|
|
|
142
143
|
await page.goto(url, { timeout: timeoutMs });
|
|
143
144
|
await page.waitForLoadState("domcontentloaded", { timeout: timeoutMs });
|
|
144
145
|
await page.waitForLoadState("load", { timeout: timeoutMs });
|
|
145
|
-
|
|
146
|
+
try {
|
|
147
|
+
await page.waitForLoadState("networkidle", { timeout: 5e3 });
|
|
148
|
+
} catch {
|
|
149
|
+
}
|
|
146
150
|
await page.evaluate(() => document.fonts.ready);
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
151
|
+
try {
|
|
152
|
+
await page.evaluate(async () => {
|
|
153
|
+
const images = document.querySelectorAll("img");
|
|
154
|
+
await Promise.all(
|
|
155
|
+
Array.from(images).map((img) => {
|
|
156
|
+
if (img.complete) return Promise.resolve();
|
|
157
|
+
return new Promise((resolve) => {
|
|
158
|
+
img.addEventListener("load", resolve);
|
|
159
|
+
img.addEventListener("error", resolve);
|
|
160
|
+
setTimeout(resolve, 3e3);
|
|
161
|
+
});
|
|
162
|
+
})
|
|
163
|
+
);
|
|
164
|
+
});
|
|
165
|
+
} catch {
|
|
166
|
+
}
|
|
159
167
|
const contentBounds = await page.evaluate(() => {
|
|
160
168
|
const root = document.querySelector("#storybook-root");
|
|
161
169
|
if (!root) return null;
|
|
@@ -331,7 +339,7 @@ var gitRoot = findGitRoot(storybookDir);
|
|
|
331
339
|
var storybookLocation = gitRoot ? relative(gitRoot, storybookDir) : "";
|
|
332
340
|
var repoRoot = gitRoot || process.cwd();
|
|
333
341
|
var DEFAULT_ALLOWED_ORIGINS = [
|
|
334
|
-
"https://app.onlook.
|
|
342
|
+
"https://app.onlook.com",
|
|
335
343
|
"http://localhost:3000",
|
|
336
344
|
"http://localhost:6006"
|
|
337
345
|
];
|
|
@@ -496,17 +504,16 @@ function storybookOnlookPlugin(options = {}) {
|
|
|
496
504
|
const mainPlugin = {
|
|
497
505
|
name: "storybook-onlook-plugin",
|
|
498
506
|
config() {
|
|
499
|
-
const isE2B = !!process.env.E2B_SANDBOX;
|
|
500
507
|
return {
|
|
501
508
|
server: {
|
|
502
|
-
//
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
509
|
+
// E2B sandbox HMR configuration
|
|
510
|
+
hmr: {
|
|
511
|
+
// E2B sandboxes use HTTPS, so we need secure WebSocket
|
|
512
|
+
protocol: "wss",
|
|
513
|
+
// E2B routes through standard HTTPS port 443
|
|
514
|
+
clientPort: 443,
|
|
515
|
+
// The actual Storybook server port inside the sandbox
|
|
516
|
+
port
|
|
510
517
|
},
|
|
511
518
|
cors: {
|
|
512
519
|
origin: allowedOrigins
|
|
@@ -528,15 +535,21 @@ function storybookOnlookPlugin(options = {}) {
|
|
|
528
535
|
console.log("[STORYBOOK_PLUGIN] Configuring preview server middleware");
|
|
529
536
|
server.middlewares.use(serveMetadataAndScreenshots);
|
|
530
537
|
},
|
|
531
|
-
|
|
532
|
-
// consumes them. In local dev this blocks HMR with 36 Playwright
|
|
533
|
-
// page loads per save. Screenshots are still available on-demand
|
|
534
|
-
// via /api/capture-screenshot and the CLI.
|
|
535
|
-
...process.env.E2B_SANDBOX && {
|
|
536
|
-
handleHotUpdate: handleStoryFileChange
|
|
537
|
-
}
|
|
538
|
+
handleHotUpdate: handleStoryFileChange
|
|
538
539
|
};
|
|
539
540
|
return [componentLocPlugin(), mainPlugin];
|
|
540
541
|
}
|
|
542
|
+
var tolerantCsfIndexer = {
|
|
543
|
+
test: /(stories|story)\.(m?js|ts)x?$/,
|
|
544
|
+
createIndex: async (fileName, options) => {
|
|
545
|
+
try {
|
|
546
|
+
return (await readCsf(fileName, options)).parse().indexInputs;
|
|
547
|
+
} catch (err) {
|
|
548
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
549
|
+
console.warn("[onbook] Skipping broken story file:", fileName, msg);
|
|
550
|
+
return [];
|
|
551
|
+
}
|
|
552
|
+
}
|
|
553
|
+
};
|
|
541
554
|
|
|
542
|
-
export { storybookOnlookPlugin };
|
|
555
|
+
export { storybookOnlookPlugin, tolerantCsfIndexer };
|
|
@@ -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;
|
|
@@ -197,23 +204,48 @@ async function generateAllScreenshots(stories, storybookUrl = "http://localhost:
|
|
|
197
204
|
batch.map(async (story) => {
|
|
198
205
|
if (skipExisting && screenshotExists(story.id, "light") && screenshotExists(story.id, "dark")) {
|
|
199
206
|
completed++;
|
|
200
|
-
const
|
|
201
|
-
console.log(`[${
|
|
207
|
+
const absoluteIndex = offset + completed;
|
|
208
|
+
console.log(`[${absoluteIndex}/${displayTotal}] Skipped (exists) ${story.id}`);
|
|
202
209
|
return;
|
|
203
210
|
}
|
|
204
|
-
const
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
+
const storyTimeout = timeoutMs * 2 + 1e4;
|
|
212
|
+
let timer;
|
|
213
|
+
try {
|
|
214
|
+
const result = await Promise.race([
|
|
215
|
+
Promise.all([
|
|
216
|
+
generateScreenshot(story.id, "light", storybookUrl, timeoutMs),
|
|
217
|
+
generateScreenshot(story.id, "dark", storybookUrl, timeoutMs)
|
|
218
|
+
]),
|
|
219
|
+
new Promise((_, reject) => {
|
|
220
|
+
timer = setTimeout(
|
|
221
|
+
() => reject(
|
|
222
|
+
new Error(
|
|
223
|
+
`Story ${story.id} timed out after ${storyTimeout / 1e3}s`
|
|
224
|
+
)
|
|
225
|
+
),
|
|
226
|
+
storyTimeout
|
|
227
|
+
);
|
|
228
|
+
})
|
|
229
|
+
]);
|
|
230
|
+
clearTimeout(timer);
|
|
231
|
+
const [lightResult, darkResult] = result;
|
|
232
|
+
if (lightResult && darkResult) {
|
|
233
|
+
const fileHash = computeFileHash(story.importPath);
|
|
234
|
+
updateManifest(story.id, story.importPath, fileHash, lightResult.boundingBox);
|
|
235
|
+
}
|
|
236
|
+
completed++;
|
|
237
|
+
const absoluteIndex = offset + completed;
|
|
238
|
+
console.log(
|
|
239
|
+
`[${absoluteIndex}/${displayTotal}] Generated screenshots for ${story.id}`
|
|
240
|
+
);
|
|
241
|
+
} catch (error) {
|
|
242
|
+
completed++;
|
|
243
|
+
const absoluteIndex = offset + completed;
|
|
244
|
+
console.error(
|
|
245
|
+
`[${absoluteIndex}/${displayTotal}] \u26A0\uFE0F Failed ${story.id}:`,
|
|
246
|
+
error instanceof Error ? error.message : error
|
|
247
|
+
);
|
|
211
248
|
}
|
|
212
|
-
completed++;
|
|
213
|
-
const absoluteIndex = offset + completed;
|
|
214
|
-
console.log(
|
|
215
|
-
`[${absoluteIndex}/${displayTotal}] Generated screenshots for ${story.id}`
|
|
216
|
-
);
|
|
217
249
|
})
|
|
218
250
|
);
|
|
219
251
|
}
|
package/package.json
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@onlook/storybook-plugin",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.4",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"bin": {
|
|
6
|
-
"onlook-storybook": "
|
|
6
|
+
"onlook-storybook": "dist/cli/index.js"
|
|
7
7
|
},
|
|
8
8
|
"exports": {
|
|
9
9
|
".": {
|
|
@@ -29,7 +29,9 @@
|
|
|
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": "npm publish"
|
|
32
|
+
"publish-pkg": "npm publish",
|
|
33
|
+
"publish-pkg:next": "npm publish --tag next",
|
|
34
|
+
"promote-latest": "npm dist-tag add @onlook/storybook-plugin@$(node -p \"require('./package.json').version\") latest"
|
|
33
35
|
},
|
|
34
36
|
"dependencies": {
|
|
35
37
|
"@babel/generator": "^7.26.9",
|
|
@@ -53,6 +55,7 @@
|
|
|
53
55
|
"access": "public"
|
|
54
56
|
},
|
|
55
57
|
"peerDependencies": {
|
|
58
|
+
"storybook": "^10.0.0",
|
|
56
59
|
"vite": "^5.0.0 || ^6.0.0"
|
|
57
60
|
}
|
|
58
61
|
}
|