@slidev/cli 51.6.0 → 51.6.2
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/dist/build-oRYT3yXD.js +62 -0
- package/dist/cli.d.ts +1 -2
- package/dist/cli.js +518 -594
- package/dist/export-D1Zqc-n1.js +433 -0
- package/dist/index.d.ts +12 -7
- package/dist/index.js +5 -17
- package/dist/resolver-BShaA6qw.js +155 -0
- package/dist/serve-D6FyjIir.js +14 -0
- package/dist/shared-D3tuRsUE.js +2475 -0
- package/package.json +23 -23
- package/dist/build-Z7GTSSXD.js +0 -77
- package/dist/chunk-BCA62OS7.js +0 -29
- package/dist/chunk-TJFRPB4N.js +0 -190
- package/dist/chunk-Y2DHOFI5.js +0 -2761
- package/dist/export-5TR5BGLG.js +0 -520
package/dist/cli.js
CHANGED
|
@@ -1,23 +1,6 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
} from "./
|
|
4
|
-
import {
|
|
5
|
-
getThemeMeta,
|
|
6
|
-
loadSetups,
|
|
7
|
-
parser,
|
|
8
|
-
resolveAddons,
|
|
9
|
-
resolveOptions,
|
|
10
|
-
resolveTheme,
|
|
11
|
-
updateFrontmatterPatch,
|
|
12
|
-
version
|
|
13
|
-
} from "./chunk-Y2DHOFI5.js";
|
|
14
|
-
import {
|
|
15
|
-
getRoots,
|
|
16
|
-
isInstalledGlobally,
|
|
17
|
-
resolveEntry
|
|
18
|
-
} from "./chunk-TJFRPB4N.js";
|
|
19
|
-
|
|
20
|
-
// node/cli.ts
|
|
1
|
+
import { getThemeMeta, loadSetups, parser, resolveAddons, resolveOptions, resolveTheme, updateFrontmatterPatch, version } from "./shared-D3tuRsUE.js";
|
|
2
|
+
import { getRoots, isInstalledGlobally, resolveEntry } from "./resolver-BShaA6qw.js";
|
|
3
|
+
import { createServer } from "./serve-D6FyjIir.js";
|
|
21
4
|
import { exec } from "node:child_process";
|
|
22
5
|
import fs from "node:fs/promises";
|
|
23
6
|
import os from "node:os";
|
|
@@ -30,593 +13,534 @@ import equal from "fast-deep-equal";
|
|
|
30
13
|
import { getPort } from "get-port-please";
|
|
31
14
|
import openBrowser from "open";
|
|
32
15
|
import yargs from "yargs";
|
|
33
|
-
|
|
34
|
-
// node/setups/preparser.ts
|
|
35
16
|
import { uniq } from "@antfu/utils";
|
|
36
17
|
import { injectPreparserExtensionLoader } from "@slidev/parser/fs";
|
|
18
|
+
|
|
19
|
+
//#region node/setups/preparser.ts
|
|
37
20
|
function setupPreparser() {
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
21
|
+
injectPreparserExtensionLoader(async (headmatter, filepath, mode) => {
|
|
22
|
+
const addons = Array.isArray(headmatter?.addons) ? headmatter.addons : [];
|
|
23
|
+
const { userRoot } = await getRoots();
|
|
24
|
+
const roots = uniq([...await resolveAddons(addons), userRoot]);
|
|
25
|
+
const returns = await loadSetups(roots, "preparser.ts", [{
|
|
26
|
+
filepath,
|
|
27
|
+
headmatter,
|
|
28
|
+
mode
|
|
29
|
+
}]);
|
|
30
|
+
return returns.flat();
|
|
31
|
+
});
|
|
48
32
|
}
|
|
49
33
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
34
|
+
//#endregion
|
|
35
|
+
//#region node/cli.ts
|
|
36
|
+
const CONFIG_RESTART_FIELDS = [
|
|
37
|
+
"monaco",
|
|
38
|
+
"routerMode",
|
|
39
|
+
"fonts",
|
|
40
|
+
"css",
|
|
41
|
+
"mdc",
|
|
42
|
+
"editor",
|
|
43
|
+
"theme",
|
|
44
|
+
"seoMeta"
|
|
60
45
|
];
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
46
|
+
/**
|
|
47
|
+
* Files that triggers a restart when added or removed
|
|
48
|
+
*/
|
|
49
|
+
const FILES_CREATE_RESTART = [
|
|
50
|
+
"global-bottom.vue",
|
|
51
|
+
"global-top.vue",
|
|
52
|
+
"uno.config.js",
|
|
53
|
+
"uno.config.ts",
|
|
54
|
+
"unocss.config.js",
|
|
55
|
+
"unocss.config.ts"
|
|
68
56
|
];
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
57
|
+
const FILES_CHANGE_RESTART = [
|
|
58
|
+
"setup/shiki.ts",
|
|
59
|
+
"setup/katex.ts",
|
|
60
|
+
"setup/preparser.ts"
|
|
73
61
|
];
|
|
74
62
|
setupPreparser();
|
|
75
|
-
|
|
76
|
-
cli.command(
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
);
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
)
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
);
|
|
371
|
-
cli.command(
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
)
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
options,
|
|
442
|
-
{
|
|
443
|
-
server: { port },
|
|
444
|
-
clearScreen: false
|
|
445
|
-
}
|
|
446
|
-
);
|
|
447
|
-
await server.listen(port);
|
|
448
|
-
printInfo(options);
|
|
449
|
-
const result = await exportSlides({
|
|
450
|
-
port,
|
|
451
|
-
...getExportOptions({ ...args, entry: entryFile }, options)
|
|
452
|
-
});
|
|
453
|
-
console.log(`${green(" \u2713 ")}${dim("exported to ")}${result}
|
|
454
|
-
`);
|
|
455
|
-
server.close();
|
|
456
|
-
}
|
|
457
|
-
process.exit(0);
|
|
458
|
-
}
|
|
459
|
-
);
|
|
460
|
-
cli.command(
|
|
461
|
-
"export-notes [entry..]",
|
|
462
|
-
"Export slide notes to PDF",
|
|
463
|
-
(args) => args.positional("entry", {
|
|
464
|
-
default: "slides.md",
|
|
465
|
-
type: "string",
|
|
466
|
-
describe: "path to the slides markdown entry"
|
|
467
|
-
}).option("output", {
|
|
468
|
-
type: "string",
|
|
469
|
-
describe: "path to the output"
|
|
470
|
-
}).option("timeout", {
|
|
471
|
-
default: 3e4,
|
|
472
|
-
type: "number",
|
|
473
|
-
describe: "timeout for rendering the print page"
|
|
474
|
-
}).option("wait", {
|
|
475
|
-
default: 0,
|
|
476
|
-
type: "number",
|
|
477
|
-
describe: "wait for the specified ms before exporting"
|
|
478
|
-
}).strict().help(),
|
|
479
|
-
async ({
|
|
480
|
-
entry,
|
|
481
|
-
output,
|
|
482
|
-
timeout,
|
|
483
|
-
wait
|
|
484
|
-
}) => {
|
|
485
|
-
const { exportNotes } = await import("./export-5TR5BGLG.js");
|
|
486
|
-
const port = await getPort(12445);
|
|
487
|
-
for (const entryFile of entry) {
|
|
488
|
-
const options = await resolveOptions({ entry: entryFile }, "export");
|
|
489
|
-
const server = await createServer(
|
|
490
|
-
options,
|
|
491
|
-
{
|
|
492
|
-
server: { port },
|
|
493
|
-
clearScreen: false
|
|
494
|
-
}
|
|
495
|
-
);
|
|
496
|
-
await server.listen(port);
|
|
497
|
-
printInfo(options);
|
|
498
|
-
const result = await exportNotes({
|
|
499
|
-
port,
|
|
500
|
-
output: output || (options.data.config.exportFilename ? `${options.data.config.exportFilename}-notes` : `${path.basename(entryFile, ".md")}-export-notes`),
|
|
501
|
-
timeout,
|
|
502
|
-
wait
|
|
503
|
-
});
|
|
504
|
-
console.log(`${green(" \u2713 ")}${dim("exported to ")}${result}
|
|
505
|
-
`);
|
|
506
|
-
server.close();
|
|
507
|
-
}
|
|
508
|
-
process.exit(0);
|
|
509
|
-
}
|
|
510
|
-
);
|
|
63
|
+
const cli = yargs(process.argv.slice(2)).scriptName("slidev").usage("$0 [args]").version(version).strict().showHelpOnFail(false).alias("h", "help").alias("v", "version");
|
|
64
|
+
cli.command("* [entry]", "Start a local server for Slidev", (args) => commonOptions(args).option("port", {
|
|
65
|
+
alias: "p",
|
|
66
|
+
type: "number",
|
|
67
|
+
describe: "port"
|
|
68
|
+
}).option("open", {
|
|
69
|
+
alias: "o",
|
|
70
|
+
default: false,
|
|
71
|
+
type: "boolean",
|
|
72
|
+
describe: "open in browser"
|
|
73
|
+
}).option("remote", {
|
|
74
|
+
type: "string",
|
|
75
|
+
describe: "listen public host and enable remote control"
|
|
76
|
+
}).option("tunnel", {
|
|
77
|
+
default: false,
|
|
78
|
+
type: "boolean",
|
|
79
|
+
describe: "open a Cloudflare Quick Tunnel to make Slidev available on the internet"
|
|
80
|
+
}).option("log", {
|
|
81
|
+
default: "warn",
|
|
82
|
+
type: "string",
|
|
83
|
+
choices: [
|
|
84
|
+
"error",
|
|
85
|
+
"warn",
|
|
86
|
+
"info",
|
|
87
|
+
"silent"
|
|
88
|
+
],
|
|
89
|
+
describe: "log level"
|
|
90
|
+
}).option("inspect", {
|
|
91
|
+
default: false,
|
|
92
|
+
type: "boolean",
|
|
93
|
+
describe: "enable the inspect plugin for debugging"
|
|
94
|
+
}).option("force", {
|
|
95
|
+
alias: "f",
|
|
96
|
+
default: false,
|
|
97
|
+
type: "boolean",
|
|
98
|
+
describe: "force the optimizer to ignore the cache and re-bundle"
|
|
99
|
+
}).option("bind", {
|
|
100
|
+
type: "string",
|
|
101
|
+
default: "0.0.0.0",
|
|
102
|
+
describe: "specify which IP addresses the server should listen on in remote mode"
|
|
103
|
+
}).option("base", {
|
|
104
|
+
type: "string",
|
|
105
|
+
describe: "base URL. Example: /demo/",
|
|
106
|
+
default: "/"
|
|
107
|
+
}).strict().help(), async ({ entry, theme, port: userPort, open, log, remote, tunnel, force, inspect, bind, base }) => {
|
|
108
|
+
let server;
|
|
109
|
+
let port = 3030;
|
|
110
|
+
let lastRemoteUrl;
|
|
111
|
+
let restartTimer;
|
|
112
|
+
function restartServer() {
|
|
113
|
+
clearTimeout(restartTimer);
|
|
114
|
+
restartTimer = setTimeout(() => {
|
|
115
|
+
console.log(yellow("\n restarting...\n"));
|
|
116
|
+
initServer();
|
|
117
|
+
}, 500);
|
|
118
|
+
}
|
|
119
|
+
async function initServer() {
|
|
120
|
+
if (server) await server.close();
|
|
121
|
+
const options = await resolveOptions({
|
|
122
|
+
entry,
|
|
123
|
+
remote,
|
|
124
|
+
theme,
|
|
125
|
+
inspect,
|
|
126
|
+
base
|
|
127
|
+
}, "dev");
|
|
128
|
+
const host = remote !== void 0 ? bind : "localhost";
|
|
129
|
+
port = userPort || await getPort({
|
|
130
|
+
port: 3030,
|
|
131
|
+
random: false,
|
|
132
|
+
portRange: [3030, 4e3],
|
|
133
|
+
host
|
|
134
|
+
});
|
|
135
|
+
server = await createServer(options, {
|
|
136
|
+
server: {
|
|
137
|
+
port,
|
|
138
|
+
strictPort: true,
|
|
139
|
+
open,
|
|
140
|
+
host,
|
|
141
|
+
force
|
|
142
|
+
},
|
|
143
|
+
optimizeDeps: { force },
|
|
144
|
+
logLevel: log,
|
|
145
|
+
base
|
|
146
|
+
}, { async loadData(loadedSource) {
|
|
147
|
+
const { data: oldData, entry: entry$1 } = options;
|
|
148
|
+
const loaded = await parser.load(options.userRoot, entry$1, loadedSource, "dev");
|
|
149
|
+
const themeRaw = theme || loaded.headmatter.theme || "default";
|
|
150
|
+
if (options.themeRaw !== themeRaw) {
|
|
151
|
+
console.log(yellow("\n restarting on theme change\n"));
|
|
152
|
+
restartServer();
|
|
153
|
+
return false;
|
|
154
|
+
}
|
|
155
|
+
const themeMeta = options.themeRoots[0] ? await getThemeMeta(themeRaw, options.themeRoots[0]) : void 0;
|
|
156
|
+
const newData = {
|
|
157
|
+
...loaded,
|
|
158
|
+
themeMeta,
|
|
159
|
+
config: parser.resolveConfig(loaded.headmatter, themeMeta, entry$1)
|
|
160
|
+
};
|
|
161
|
+
if (CONFIG_RESTART_FIELDS.some((i) => !equal(newData.config[i], oldData.config[i]))) {
|
|
162
|
+
console.log(yellow("\n restarting on config change\n"));
|
|
163
|
+
restartServer();
|
|
164
|
+
return false;
|
|
165
|
+
}
|
|
166
|
+
if (newData.features.katex && !oldData.features.katex || newData.features.monaco && !oldData.features.monaco) {
|
|
167
|
+
console.log(yellow("\n restarting on feature change\n"));
|
|
168
|
+
restartServer();
|
|
169
|
+
return false;
|
|
170
|
+
}
|
|
171
|
+
return newData;
|
|
172
|
+
} });
|
|
173
|
+
await server.listen();
|
|
174
|
+
let tunnelUrl = "";
|
|
175
|
+
if (tunnel) if (remote != null) tunnelUrl = await openTunnel(port);
|
|
176
|
+
else console.log(yellow("\n --remote is required for tunneling, Cloudflare Quick Tunnel is not enabled.\n"));
|
|
177
|
+
let publicIp;
|
|
178
|
+
if (remote) publicIp = await import("public-ip").then((r) => r.publicIpv4());
|
|
179
|
+
lastRemoteUrl = printInfo(options, port, base, remote, tunnelUrl, publicIp);
|
|
180
|
+
}
|
|
181
|
+
async function openTunnel(port$1) {
|
|
182
|
+
const { startTunnel } = await import("untun");
|
|
183
|
+
const tunnel$1 = await startTunnel({
|
|
184
|
+
port: port$1,
|
|
185
|
+
acceptCloudflareNotice: true
|
|
186
|
+
});
|
|
187
|
+
return await tunnel$1?.getURL() ?? "";
|
|
188
|
+
}
|
|
189
|
+
const SHORTCUTS = [
|
|
190
|
+
{
|
|
191
|
+
name: "r",
|
|
192
|
+
fullname: "restart",
|
|
193
|
+
action() {
|
|
194
|
+
restartServer();
|
|
195
|
+
}
|
|
196
|
+
},
|
|
197
|
+
{
|
|
198
|
+
name: "o",
|
|
199
|
+
fullname: "open",
|
|
200
|
+
action() {
|
|
201
|
+
openBrowser(`http://localhost:${port}${base}`);
|
|
202
|
+
}
|
|
203
|
+
},
|
|
204
|
+
{
|
|
205
|
+
name: "e",
|
|
206
|
+
fullname: "edit",
|
|
207
|
+
action() {
|
|
208
|
+
exec(`code "${entry}"`);
|
|
209
|
+
}
|
|
210
|
+
},
|
|
211
|
+
{
|
|
212
|
+
name: "q",
|
|
213
|
+
fullname: "quit",
|
|
214
|
+
action() {
|
|
215
|
+
try {
|
|
216
|
+
server?.close();
|
|
217
|
+
} finally {
|
|
218
|
+
process.exit();
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
},
|
|
222
|
+
{
|
|
223
|
+
name: "c",
|
|
224
|
+
fullname: "qrcode",
|
|
225
|
+
async action() {
|
|
226
|
+
if (!lastRemoteUrl) return;
|
|
227
|
+
await import("uqr").then(async (r) => {
|
|
228
|
+
const code = r.renderUnicodeCompact(lastRemoteUrl);
|
|
229
|
+
console.log(`\n${dim(" QR Code for remote control: ")}\n ${blue(lastRemoteUrl)}\n`);
|
|
230
|
+
console.log(code.split("\n").map((i) => ` ${i}`).join("\n"));
|
|
231
|
+
const publicIp = await import("public-ip").then((r$1) => r$1.publicIpv4());
|
|
232
|
+
if (publicIp) console.log(`\n${dim(" Public IP: ")} ${blue(publicIp)}\n`);
|
|
233
|
+
});
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
];
|
|
237
|
+
function bindShortcut() {
|
|
238
|
+
process.stdin.resume();
|
|
239
|
+
process.stdin.setEncoding("utf8");
|
|
240
|
+
readline.emitKeypressEvents(process.stdin);
|
|
241
|
+
if (process.stdin.isTTY) process.stdin.setRawMode(true);
|
|
242
|
+
const onKeyPress = (str, key) => {
|
|
243
|
+
if (key.ctrl && key.name === "c") process.exit();
|
|
244
|
+
else {
|
|
245
|
+
const [sh] = SHORTCUTS.filter((item) => item.name === str);
|
|
246
|
+
if (sh) try {
|
|
247
|
+
sh.action();
|
|
248
|
+
} catch (err) {
|
|
249
|
+
console.error(`Failed to execute shortcut ${sh.fullname}`, err);
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
};
|
|
253
|
+
process.stdin.on("keypress", onKeyPress);
|
|
254
|
+
server?.httpServer?.on("close", () => {
|
|
255
|
+
process.stdin.off("keypress", onKeyPress);
|
|
256
|
+
});
|
|
257
|
+
}
|
|
258
|
+
initServer();
|
|
259
|
+
bindShortcut();
|
|
260
|
+
const { watch } = await import("chokidar");
|
|
261
|
+
const watcher = watch([...FILES_CREATE_RESTART, ...FILES_CHANGE_RESTART], {
|
|
262
|
+
ignored: ["node_modules", ".git"],
|
|
263
|
+
ignoreInitial: true
|
|
264
|
+
});
|
|
265
|
+
watcher.on("unlink", (file) => {
|
|
266
|
+
console.log(yellow(`\n file ${file} removed, restarting...\n`));
|
|
267
|
+
restartServer();
|
|
268
|
+
});
|
|
269
|
+
watcher.on("add", (file) => {
|
|
270
|
+
console.log(yellow(`\n file ${file} added, restarting...\n`));
|
|
271
|
+
restartServer();
|
|
272
|
+
});
|
|
273
|
+
watcher.on("change", (file) => {
|
|
274
|
+
if (typeof file !== "string") return;
|
|
275
|
+
if (FILES_CREATE_RESTART.includes(file)) return;
|
|
276
|
+
console.log(yellow(`\n file ${file} changed, restarting...\n`));
|
|
277
|
+
restartServer();
|
|
278
|
+
});
|
|
279
|
+
});
|
|
280
|
+
cli.command("build [entry..]", "Build hostable SPA", (args) => exportOptions(commonOptions(args)).option("out", {
|
|
281
|
+
alias: "o",
|
|
282
|
+
type: "string",
|
|
283
|
+
default: "dist",
|
|
284
|
+
describe: "output dir"
|
|
285
|
+
}).option("base", {
|
|
286
|
+
type: "string",
|
|
287
|
+
describe: "output base. Example: /demo/"
|
|
288
|
+
}).option("download", {
|
|
289
|
+
alias: "d",
|
|
290
|
+
type: "boolean",
|
|
291
|
+
describe: "allow download as PDF"
|
|
292
|
+
}).option("inspect", {
|
|
293
|
+
default: false,
|
|
294
|
+
type: "boolean",
|
|
295
|
+
describe: "enable the inspect plugin for debugging"
|
|
296
|
+
}).strict().help(), async (args) => {
|
|
297
|
+
const { entry, theme, base, download, out, inspect } = args;
|
|
298
|
+
const { build } = await import("./build-oRYT3yXD.js");
|
|
299
|
+
for (const entryFile of entry) {
|
|
300
|
+
const options = await resolveOptions({
|
|
301
|
+
entry: entryFile,
|
|
302
|
+
theme,
|
|
303
|
+
inspect,
|
|
304
|
+
download,
|
|
305
|
+
base
|
|
306
|
+
}, "build");
|
|
307
|
+
printInfo(options);
|
|
308
|
+
await build(options, {
|
|
309
|
+
base,
|
|
310
|
+
build: { outDir: entry.length === 1 ? out : path.join(out, path.basename(entryFile, ".md")) }
|
|
311
|
+
}, {
|
|
312
|
+
...args,
|
|
313
|
+
entry: entryFile
|
|
314
|
+
});
|
|
315
|
+
}
|
|
316
|
+
});
|
|
317
|
+
cli.command("format [entry..]", "Format the markdown file", (args) => commonOptions(args).strict().help(), async ({ entry }) => {
|
|
318
|
+
for (const entryFile of entry) {
|
|
319
|
+
const md = await parser.parse(await fs.readFile(entryFile, "utf-8"), entryFile);
|
|
320
|
+
parser.prettify(md);
|
|
321
|
+
await parser.save(md);
|
|
322
|
+
}
|
|
323
|
+
});
|
|
324
|
+
cli.command("theme [subcommand]", "Theme related operations", (command) => {
|
|
325
|
+
return command.command("eject", "Eject current theme into local file system", (args) => commonOptions(args).option("dir", {
|
|
326
|
+
type: "string",
|
|
327
|
+
default: "theme"
|
|
328
|
+
}), async ({ entry: entryRaw, dir, theme: themeInput }) => {
|
|
329
|
+
const entry = await resolveEntry(entryRaw);
|
|
330
|
+
const roots = await getRoots(entry);
|
|
331
|
+
const data = await parser.load(roots.userRoot, entry);
|
|
332
|
+
let themeRaw = themeInput || data.headmatter.theme;
|
|
333
|
+
themeRaw = themeRaw === null ? "none" : themeRaw || "default";
|
|
334
|
+
if (themeRaw === "none") {
|
|
335
|
+
console.error("Cannot eject theme \"none\"");
|
|
336
|
+
process.exit(1);
|
|
337
|
+
}
|
|
338
|
+
if ("/.".includes(themeRaw[0]) || themeRaw[0] !== "@" && themeRaw.includes("/")) {
|
|
339
|
+
console.error("Theme is already ejected");
|
|
340
|
+
process.exit(1);
|
|
341
|
+
}
|
|
342
|
+
const [name, root] = await resolveTheme(themeRaw, entry);
|
|
343
|
+
await fs.mkdir(path.resolve(dir), { recursive: true });
|
|
344
|
+
await fs.cp(root, path.resolve(dir), {
|
|
345
|
+
recursive: true,
|
|
346
|
+
filter: (i) => !/node_modules|\.git/.test(path.relative(root, i))
|
|
347
|
+
});
|
|
348
|
+
const dirPath = `./${dir}`;
|
|
349
|
+
const firstSlide = data.entry.slides[0];
|
|
350
|
+
updateFrontmatterPatch(firstSlide, { theme: dirPath });
|
|
351
|
+
parser.prettifySlide(firstSlide);
|
|
352
|
+
await parser.save(data.entry);
|
|
353
|
+
console.log(`Theme "${name}" ejected successfully to "${dirPath}"`);
|
|
354
|
+
});
|
|
355
|
+
}, () => {
|
|
356
|
+
cli.showHelp();
|
|
357
|
+
process.exit(1);
|
|
358
|
+
});
|
|
359
|
+
cli.command("export [entry..]", "Export slides to PDF", (args) => exportOptions(commonOptions(args)).strict().help(), async (args) => {
|
|
360
|
+
const { entry, theme } = args;
|
|
361
|
+
const { exportSlides, getExportOptions } = await import("./export-D1Zqc-n1.js");
|
|
362
|
+
const port = await getPort(12445);
|
|
363
|
+
let warned = false;
|
|
364
|
+
for (const entryFile of entry) {
|
|
365
|
+
const options = await resolveOptions({
|
|
366
|
+
entry: entryFile,
|
|
367
|
+
theme
|
|
368
|
+
}, "export");
|
|
369
|
+
if (options.data.config.browserExporter !== false && !warned) {
|
|
370
|
+
warned = true;
|
|
371
|
+
console.log(cyanBright("[Slidev] Try the new browser exporter!"));
|
|
372
|
+
console.log(cyanBright("You can use the browser exporter instead by starting the dev server as normal and visit"), `${blue("localhost:")}${dim("<port>")}${blue("/export")}\n`);
|
|
373
|
+
}
|
|
374
|
+
const server = await createServer(options, {
|
|
375
|
+
server: { port },
|
|
376
|
+
clearScreen: false
|
|
377
|
+
});
|
|
378
|
+
await server.listen(port);
|
|
379
|
+
printInfo(options);
|
|
380
|
+
const result = await exportSlides({
|
|
381
|
+
port,
|
|
382
|
+
...getExportOptions({
|
|
383
|
+
...args,
|
|
384
|
+
entry: entryFile
|
|
385
|
+
}, options)
|
|
386
|
+
});
|
|
387
|
+
console.log(`${green(" ✓ ")}${dim("exported to ")}${result}\n`);
|
|
388
|
+
server.close();
|
|
389
|
+
}
|
|
390
|
+
process.exit(0);
|
|
391
|
+
});
|
|
392
|
+
cli.command("export-notes [entry..]", "Export slide notes to PDF", (args) => args.positional("entry", {
|
|
393
|
+
default: "slides.md",
|
|
394
|
+
type: "string",
|
|
395
|
+
describe: "path to the slides markdown entry"
|
|
396
|
+
}).option("output", {
|
|
397
|
+
type: "string",
|
|
398
|
+
describe: "path to the output"
|
|
399
|
+
}).option("timeout", {
|
|
400
|
+
default: 3e4,
|
|
401
|
+
type: "number",
|
|
402
|
+
describe: "timeout for rendering the print page"
|
|
403
|
+
}).option("wait", {
|
|
404
|
+
default: 0,
|
|
405
|
+
type: "number",
|
|
406
|
+
describe: "wait for the specified ms before exporting"
|
|
407
|
+
}).strict().help(), async ({ entry, output, timeout, wait }) => {
|
|
408
|
+
const { exportNotes } = await import("./export-D1Zqc-n1.js");
|
|
409
|
+
const port = await getPort(12445);
|
|
410
|
+
for (const entryFile of entry) {
|
|
411
|
+
const options = await resolveOptions({ entry: entryFile }, "export");
|
|
412
|
+
const server = await createServer(options, {
|
|
413
|
+
server: { port },
|
|
414
|
+
clearScreen: false
|
|
415
|
+
});
|
|
416
|
+
await server.listen(port);
|
|
417
|
+
printInfo(options);
|
|
418
|
+
const result = await exportNotes({
|
|
419
|
+
port,
|
|
420
|
+
output: output || (options.data.config.exportFilename ? `${options.data.config.exportFilename}-notes` : `${path.basename(entryFile, ".md")}-export-notes`),
|
|
421
|
+
timeout,
|
|
422
|
+
wait
|
|
423
|
+
});
|
|
424
|
+
console.log(`${green(" ✓ ")}${dim("exported to ")}${result}\n`);
|
|
425
|
+
server.close();
|
|
426
|
+
}
|
|
427
|
+
process.exit(0);
|
|
428
|
+
});
|
|
511
429
|
cli.help().parse();
|
|
512
430
|
function commonOptions(args) {
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
431
|
+
return args.positional("entry", {
|
|
432
|
+
default: "slides.md",
|
|
433
|
+
type: "string",
|
|
434
|
+
describe: "path to the slides markdown entry"
|
|
435
|
+
}).option("theme", {
|
|
436
|
+
alias: "t",
|
|
437
|
+
type: "string",
|
|
438
|
+
describe: "override theme"
|
|
439
|
+
});
|
|
522
440
|
}
|
|
523
441
|
function exportOptions(args) {
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
442
|
+
return args.option("output", {
|
|
443
|
+
type: "string",
|
|
444
|
+
describe: "path to the output"
|
|
445
|
+
}).option("format", {
|
|
446
|
+
type: "string",
|
|
447
|
+
choices: [
|
|
448
|
+
"pdf",
|
|
449
|
+
"png",
|
|
450
|
+
"pptx",
|
|
451
|
+
"md"
|
|
452
|
+
],
|
|
453
|
+
describe: "output format"
|
|
454
|
+
}).option("timeout", {
|
|
455
|
+
type: "number",
|
|
456
|
+
describe: "timeout for rendering the print page"
|
|
457
|
+
}).option("wait", {
|
|
458
|
+
type: "number",
|
|
459
|
+
describe: "wait for the specified ms before exporting"
|
|
460
|
+
}).option("wait-until", {
|
|
461
|
+
type: "string",
|
|
462
|
+
choices: [
|
|
463
|
+
"networkidle",
|
|
464
|
+
"load",
|
|
465
|
+
"domcontentloaded",
|
|
466
|
+
"none"
|
|
467
|
+
],
|
|
468
|
+
describe: "wait until the specified event before exporting each slide"
|
|
469
|
+
}).option("range", {
|
|
470
|
+
type: "string",
|
|
471
|
+
describe: "page ranges to export, for example \"1,4-5,6\""
|
|
472
|
+
}).option("dark", {
|
|
473
|
+
type: "boolean",
|
|
474
|
+
describe: "export as dark theme"
|
|
475
|
+
}).option("with-clicks", {
|
|
476
|
+
alias: "c",
|
|
477
|
+
type: "boolean",
|
|
478
|
+
describe: "export pages for every clicks"
|
|
479
|
+
}).option("executable-path", {
|
|
480
|
+
type: "string",
|
|
481
|
+
describe: "executable to override playwright bundled browser"
|
|
482
|
+
}).option("with-toc", {
|
|
483
|
+
type: "boolean",
|
|
484
|
+
describe: "export pages with outline"
|
|
485
|
+
}).option("per-slide", {
|
|
486
|
+
type: "boolean",
|
|
487
|
+
describe: "slide slides slide by slide. Works better with global components, but will break cross slide links and TOC in PDF"
|
|
488
|
+
}).option("scale", {
|
|
489
|
+
type: "number",
|
|
490
|
+
describe: "scale factor for image export"
|
|
491
|
+
}).option("omit-background", {
|
|
492
|
+
type: "boolean",
|
|
493
|
+
describe: "export png pages without the default browser background"
|
|
494
|
+
});
|
|
567
495
|
}
|
|
568
496
|
function printInfo(options, port, base, remote, tunnelUrl, publicIp) {
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
console.log(`${dim(" remote control ")} > ${dim("pass --remote to enable")}`);
|
|
617
|
-
}
|
|
618
|
-
console.log();
|
|
619
|
-
console.log(`${dim(" shortcuts ")} > ${underline("r")}${dim("estart | ")}${underline("o")}${dim("pen | ")}${underline("e")}${dim("dit | ")}${underline("q")}${dim("uit")}${lastRemoteUrl ? ` | ${dim("qr")}${underline("c")}${dim("ode")}` : ""}`);
|
|
620
|
-
return lastRemoteUrl;
|
|
621
|
-
}
|
|
497
|
+
if (base && (!base.startsWith("/") || !base.endsWith("/"))) {
|
|
498
|
+
console.error("Base URL must start and end with a slash \"/\"");
|
|
499
|
+
process.exit(1);
|
|
500
|
+
}
|
|
501
|
+
console.log();
|
|
502
|
+
console.log();
|
|
503
|
+
console.log(` ${cyan("●") + blue("■") + yellow("▲")}`);
|
|
504
|
+
console.log(`${bold(" Slidev")} ${blue(`v${version}`)} ${isInstalledGlobally.value ? yellow("(global)") : ""}`);
|
|
505
|
+
console.log();
|
|
506
|
+
verifyConfig(options.data.config, options.data.themeMeta, (v) => console.warn(yellow(` ! ${v}`)));
|
|
507
|
+
console.log(dim(" theme ") + (options.theme ? green(options.theme) : gray("none")));
|
|
508
|
+
console.log(dim(" css engine ") + blue("unocss"));
|
|
509
|
+
console.log(dim(" entry ") + dim(path.normalize(path.dirname(options.entry)) + path.sep) + path.basename(options.entry));
|
|
510
|
+
if (port) {
|
|
511
|
+
const baseText = base?.slice(0, -1) || "";
|
|
512
|
+
const portAndBase = port + baseText;
|
|
513
|
+
const baseUrl = `http://localhost:${bold(portAndBase)}`;
|
|
514
|
+
const query = remote ? `?password=${remote}` : "";
|
|
515
|
+
const presenterPath = `${options.data.config.routerMode === "hash" ? "/#/" : "/"}presenter/${query}`;
|
|
516
|
+
const entryPath = `${options.data.config.routerMode === "hash" ? "/#/" : "/"}entry${query}/`;
|
|
517
|
+
const overviewPath = `${options.data.config.routerMode === "hash" ? "/#/" : "/"}overview${query}/`;
|
|
518
|
+
console.log();
|
|
519
|
+
console.log(`${dim(" public slide show ")} > ${cyan(`${baseUrl}/`)}`);
|
|
520
|
+
if (query) console.log(`${dim(" private slide show ")} > ${cyan(`${baseUrl}/${query}`)}`);
|
|
521
|
+
if (options.utils.define.__SLIDEV_FEATURE_PRESENTER__) console.log(`${dim(" presenter mode ")} > ${blue(`${baseUrl}${presenterPath}`)}`);
|
|
522
|
+
console.log(`${dim(" slides overview ")} > ${blue(`${baseUrl}${overviewPath}`)}`);
|
|
523
|
+
if (options.utils.define.__SLIDEV_FEATURE_BROWSER_EXPORTER__) console.log(`${dim(" export slides")} > ${blue(`${baseUrl}/export/`)}`);
|
|
524
|
+
if (options.inspect) console.log(`${dim(" vite inspector")} > ${yellow(`${baseUrl}/__inspect/`)}`);
|
|
525
|
+
let lastRemoteUrl = "";
|
|
526
|
+
if (remote !== void 0) {
|
|
527
|
+
Object.values(os.networkInterfaces()).forEach((v) => (v || []).filter((details) => String(details.family).slice(-1) === "4" && !details.address.includes("127.0.0.1")).forEach(({ address }) => {
|
|
528
|
+
lastRemoteUrl = `http://${address}:${portAndBase}${entryPath}`;
|
|
529
|
+
console.log(`${dim(" remote control ")} > ${blue(lastRemoteUrl)}`);
|
|
530
|
+
}));
|
|
531
|
+
if (publicIp) {
|
|
532
|
+
lastRemoteUrl = `http://${publicIp}:${portAndBase}${entryPath}`;
|
|
533
|
+
console.log(`${dim(" remote control ")} > ${blue(lastRemoteUrl)}`);
|
|
534
|
+
}
|
|
535
|
+
if (tunnelUrl) {
|
|
536
|
+
lastRemoteUrl = `${tunnelUrl}${baseText}${entryPath}`;
|
|
537
|
+
console.log(`${dim(" remote via tunnel")} > ${yellow(lastRemoteUrl)}`);
|
|
538
|
+
}
|
|
539
|
+
} else console.log(`${dim(" remote control ")} > ${dim("pass --remote to enable")}`);
|
|
540
|
+
console.log();
|
|
541
|
+
console.log(`${dim(" shortcuts ")} > ${underline("r")}${dim("estart | ")}${underline("o")}${dim("pen | ")}${underline("e")}${dim("dit | ")}${underline("q")}${dim("uit")}${lastRemoteUrl ? ` | ${dim("qr")}${underline("c")}${dim("ode")}` : ""}`);
|
|
542
|
+
return lastRemoteUrl;
|
|
543
|
+
}
|
|
622
544
|
}
|
|
545
|
+
|
|
546
|
+
//#endregion
|