@slidev/cli 52.17.1 → 52.18.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.
@@ -1,5 +1,5 @@
1
- import { n as resolveViteConfigs } from "./serve-bAegrEOc.mjs";
2
- import { join, resolve } from "node:path";
1
+ import { n as resolveViteConfigs } from "./serve-1daxO8VB.mjs";
2
+ import { join, resolve } from "pathe";
3
3
  import { build as build$1 } from "vite";
4
4
  import { existsSync } from "node:fs";
5
5
  import fs$1 from "node:fs/promises";
@@ -51,7 +51,7 @@ async function build(options, viteConfig = {}, args) {
51
51
  dev: true
52
52
  }));
53
53
  server.listen(port);
54
- const { exportSlides } = await import("./export-_6QaMWg2.mjs");
54
+ const { exportSlides } = await import("./export-B_maVZXE.mjs");
55
55
  const tempDir = resolve(outDir, "temp");
56
56
  await fs$1.mkdir(tempDir, { recursive: true });
57
57
  await exportSlides({
@@ -92,7 +92,7 @@ async function build(options, viteConfig = {}, args) {
92
92
  "true",
93
93
  "auto"
94
94
  ].includes(options.data.config.download)) {
95
- const { exportSlides, getExportOptions } = await import("./export-_6QaMWg2.mjs");
95
+ const { exportSlides, getExportOptions } = await import("./export-B_maVZXE.mjs");
96
96
  const port = 12445;
97
97
  const app = connect();
98
98
  const server = http.createServer(app);
package/dist/cli.mjs CHANGED
@@ -1,7 +1,7 @@
1
- import { i as resolveEntry, r as isInstalledGlobally } from "./resolver-BBT539iz.mjs";
2
- import { c as getThemeMeta, d as loadSetups, f as updateFrontmatterPatch, l as resolveTheme, o as resolveOptions, s as parser, t as createServer, u as version } from "./serve-bAegrEOc.mjs";
3
- import path from "node:path";
1
+ import { i as isInstalledGlobally, o as resolveEntry } from "./resolver-BIhhHpe7.mjs";
2
+ import { c as getThemeMeta, d as loadSetups, f as updateFrontmatterPatch, l as resolveTheme, o as resolveOptions, s as parser, t as createServer, u as version } from "./serve-1daxO8VB.mjs";
4
3
  import process from "node:process";
4
+ import path from "pathe";
5
5
  import fs from "node:fs/promises";
6
6
  import { blue, bold, cyan, cyanBright, dim, gray, green, underline, yellow } from "ansis";
7
7
  import { injectPreparserExtensionLoader } from "@slidev/parser/fs";
@@ -300,7 +300,7 @@ cli.command("build [entry..]", "Build hostable SPA", (args) => exportOptions(com
300
300
  describe: "enable the inspect plugin for debugging"
301
301
  }).strict().help(), async (args) => {
302
302
  const { entry, theme, base, download, out, inspect, "without-notes": withoutNotes, "router-mode": routerMode } = args;
303
- const { build } = await import("./build-CsQUCdtJ.mjs");
303
+ const { build } = await import("./build-DJdJOe3Q.mjs");
304
304
  for (const entryFile of entry) {
305
305
  const options = await resolveOptions({
306
306
  entry: entryFile,
@@ -329,7 +329,7 @@ cli.command("format [entry..]", "Format the markdown file", (args) => commonOpti
329
329
  }
330
330
  });
331
331
  cli.command("mcp [entry]", "Start an MCP (Model Context Protocol) server over stdio for AI agents to inspect and edit the slides", (args) => commonOptions(args).strict().help(), async ({ entry }) => {
332
- const { startMcpStdioServer } = await import("./stdio-CjXw2-ks.mjs");
332
+ const { startMcpStdioServer } = await import("./stdio-BPU_DuqN.mjs");
333
333
  await startMcpStdioServer(await resolveEntry(entry));
334
334
  });
335
335
  cli.command("theme [subcommand]", "Theme related operations", (command) => {
@@ -369,7 +369,7 @@ cli.command("theme [subcommand]", "Theme related operations", (command) => {
369
369
  });
370
370
  cli.command("export [entry..]", "Export slides to PDF", (args) => exportOptions(commonOptions(args)).strict().help(), async (args) => {
371
371
  const { entry, theme } = args;
372
- const { exportSlides, getExportOptions } = await import("./export-_6QaMWg2.mjs");
372
+ const { exportSlides, getExportOptions } = await import("./export-B_maVZXE.mjs");
373
373
  const candidatePort = await getPort(12445);
374
374
  let warned = false;
375
375
  for (const entryFile of entry) {
@@ -421,7 +421,7 @@ cli.command("export-notes [entry..]", "Export slide notes to PDF", (args) => arg
421
421
  type: "number",
422
422
  describe: "wait for the specified ms before exporting"
423
423
  }).strict().help(), async ({ entry, output, timeout, wait }) => {
424
- const { exportNotes } = await import("./export-_6QaMWg2.mjs");
424
+ const { exportNotes } = await import("./export-B_maVZXE.mjs");
425
425
  const candidatePort = await getPort(12445);
426
426
  for (const entryFile of entry) {
427
427
  const options = await resolveOptions({ entry: entryFile }, "export");
@@ -547,7 +547,7 @@ function printInfo(options, port, base, remote, tunnelUrl, publicIp) {
547
547
  if (options.utils.define.__SLIDEV_FEATURE_PRESENTER__) console.log(`${dim(" presenter mode ")} > ${blue(`${baseUrl}${presenterPath}`)}`);
548
548
  console.log(`${dim(" slides overview ")} > ${blue(`${baseUrl}${overviewPath}`)}`);
549
549
  if (options.utils.define.__SLIDEV_FEATURE_BROWSER_EXPORTER__) console.log(`${dim(" export slides")} > ${blue(`${baseUrl}/export/`)}`);
550
- if (options.mode === "dev" && options.data.config.mcp !== false) console.log(`${dim(" mcp server (ai)")} > ${blue(`http://localhost:${bold(port)}/__mcp`)}`);
550
+ if (options.mode === "dev" && options.data.config.mcp !== false) console.log(`${dim(" mcp server ")} > ${blue(`http://localhost:${bold(port)}/__mcp`)}`);
551
551
  if (options.inspect) console.log(`${dim(" vite inspector")} > ${yellow(`${baseUrl}/__inspect/`)}`);
552
552
  let lastRemoteUrl = "";
553
553
  if (remote !== void 0) {
@@ -1,6 +1,6 @@
1
- import { n as getRoots } from "./resolver-BBT539iz.mjs";
2
- import path, { dirname, relative } from "node:path";
1
+ import { n as getRoots } from "./resolver-BIhhHpe7.mjs";
3
2
  import process from "node:process";
3
+ import path, { dirname, relative } from "pathe";
4
4
  import fs from "node:fs/promises";
5
5
  import { clearUndefined, ensureSuffix, slash } from "@antfu/utils";
6
6
  import { blue, cyan, dim, green, yellow } from "ansis";
package/dist/index.mjs CHANGED
@@ -1,2 +1,2 @@
1
- import { a as createDataUtils, o as resolveOptions, r as ViteSlidevPlugin, s as parser, t as createServer } from "./serve-bAegrEOc.mjs";
1
+ import { a as createDataUtils, o as resolveOptions, r as ViteSlidevPlugin, s as parser, t as createServer } from "./serve-1daxO8VB.mjs";
2
2
  export { ViteSlidevPlugin, createDataUtils, createServer, parser, resolveOptions };
@@ -1,5 +1,5 @@
1
- import { dirname, join, relative, resolve, sep } from "node:path";
2
1
  import process from "node:process";
2
+ import { dirname, join, relative, resolve, sep } from "pathe";
3
3
  import { existsSync, lstatSync, readdirSync, readlinkSync } from "node:fs";
4
4
  import { copyFile, readFile } from "node:fs/promises";
5
5
  import { fileURLToPath, pathToFileURL } from "node:url";
@@ -7,7 +7,7 @@ import { parseNi, run } from "@antfu/ni";
7
7
  import { ensurePrefix, slash } from "@antfu/utils";
8
8
  import { underline, yellow } from "ansis";
9
9
  import globalDirs from "global-directory";
10
- import { resolvePath } from "mlly";
10
+ import { resolve as resolve$1, resolvePath } from "mlly";
11
11
  import prompts from "prompts";
12
12
  import { resolveGlobal } from "resolve-global";
13
13
  import { findClosestPkgJsonPath, findDepPkgJsonPath } from "vitefu";
@@ -119,6 +119,52 @@ async function resolveImportPath(importName, ensure = false) {
119
119
  }
120
120
  if (ensure) throw new Error(`Failed to resolve package "${importName}"`);
121
121
  }
122
+ /**
123
+ * Import an optional dependency (typically an optional peer dependency such as
124
+ * `vite-plugin-pwa`) that the user may or may not have installed. Resolution is
125
+ * attempted, in order, from the user's project root, the workspace root, the
126
+ * global registry (when Slidev runs globally), and finally the cli's own
127
+ * dependencies. Returns `undefined` when the package can't be resolved anywhere.
128
+ */
129
+ async function importOptionalDependency(name) {
130
+ const roots = [];
131
+ try {
132
+ const { userRoot, userWorkspaceRoot } = await getRoots();
133
+ roots.push(userRoot);
134
+ if (userWorkspaceRoot !== userRoot) roots.push(userWorkspaceRoot);
135
+ } catch {}
136
+ for (const root of roots) try {
137
+ return await import(await resolve$1(name, { url: pathToFileURL(`${root}${sep}`).href }));
138
+ } catch {}
139
+ if (isInstalledGlobally.value) try {
140
+ return await import(resolveGlobal(name));
141
+ } catch {}
142
+ try {
143
+ return await import(name);
144
+ } catch {}
145
+ }
146
+ /**
147
+ * Prompt the user to install a missing optional dependency, then install it
148
+ * with the detected package manager. Exits the process when the user declines
149
+ * or when stdin isn't interactive (so it can't prompt).
150
+ *
151
+ * `purpose` describes why the package is needed, e.g. `The "pwa" option`.
152
+ */
153
+ async function promptForOptionalInstallation(pkgName, purpose) {
154
+ if (!process.stdin.isTTY) {
155
+ console.error(`${purpose} requires the "${pkgName}" package, which is not installed, and cannot prompt for installation. Install it with \`npm i -D ${pkgName}\` (or your package manager's equivalent) and try again.`);
156
+ process.exit(1);
157
+ }
158
+ const { confirm } = await prompts({
159
+ name: "confirm",
160
+ initial: "Y",
161
+ type: "confirm",
162
+ message: `${purpose} requires the "${yellow(pkgName)}" package, which is not installed ${underline(isInstalledGlobally.value ? "globally" : "in your project")}. Install it now?`
163
+ });
164
+ if (!confirm) process.exit(1);
165
+ if (isInstalledGlobally.value) await run(parseNi, ["-g", pkgName]);
166
+ else await run(parseNi, [pkgName]);
167
+ }
122
168
  async function findPkgRoot(dep, parent, ensure = false) {
123
169
  const pkgJsonPath = await findDepPkgJsonPath(dep, parent);
124
170
  const path = pkgJsonPath ? dirname(pkgJsonPath) : isInstalledGlobally.value ? await findGlobalPkgRoot(dep, false) : void 0;
@@ -257,4 +303,4 @@ function resolveSourceFiles(roots, subpath, extensions = [
257
303
  return results;
258
304
  }
259
305
  //#endregion
260
- export { resolveImportPath as a, toAtFS as c, resolveEntry as i, getRoots as n, resolveImportUrl as o, isInstalledGlobally as r, resolveSourceFiles as s, createResolver as t };
306
+ export { promptForOptionalInstallation as a, resolveImportUrl as c, isInstalledGlobally as i, resolveSourceFiles as l, getRoots as n, resolveEntry as o, importOptionalDependency as r, resolveImportPath as s, createResolver as t, toAtFS as u };
@@ -1,7 +1,7 @@
1
- import { a as resolveImportPath, c as toAtFS, i as resolveEntry, n as getRoots, o as resolveImportUrl, r as isInstalledGlobally, s as resolveSourceFiles, t as createResolver } from "./resolver-BBT539iz.mjs";
1
+ import { a as promptForOptionalInstallation, c as resolveImportUrl, i as isInstalledGlobally, l as resolveSourceFiles, n as getRoots, o as resolveEntry, r as importOptionalDependency, s as resolveImportPath, t as createResolver, u as toAtFS } from "./resolver-BIhhHpe7.mjs";
2
2
  import { builtinModules } from "node:module";
3
- import path, { basename, dirname, isAbsolute, join, relative, resolve, win32 } from "node:path";
4
3
  import process from "node:process";
4
+ import path, { basename, dirname, isAbsolute, join, relative, resolve, win32 } from "pathe";
5
5
  import { createServer, loadConfigFromFile, mergeConfig, parseSync } from "vite";
6
6
  import MarkdownExit from "markdown-exit";
7
7
  import fs, { existsSync, mkdirSync, realpathSync, writeFileSync } from "node:fs";
@@ -44,7 +44,6 @@ import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/
44
44
  import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
45
45
  import { z } from "zod";
46
46
  import ServerRef from "vite-plugin-vue-server-ref";
47
- import { VitePWA } from "vite-plugin-pwa";
48
47
  import UnoCSS from "unocss/vite";
49
48
  import { mergeConfigs, presetIcons } from "unocss";
50
49
  import Vue from "@vitejs/plugin-vue";
@@ -141,6 +140,7 @@ function createSlideImportGuardPlugin() {
141
140
  if (!isSlideMarkdownId(id) || !config?.server.fs.strict) return null;
142
141
  const importer = filePathFromId(id) ?? id;
143
142
  await Promise.all(extractImportSources(code, id).map(async ({ value, start }) => {
143
+ if (isPublicAsset(value, config)) return;
144
144
  const resolved = await this.resolve(value, importer, { skipSelf: true });
145
145
  if (!resolved || resolved.external) return;
146
146
  const filePath = filePathFromId(resolved.id);
@@ -169,6 +169,20 @@ function filePathFromId(id) {
169
169
  function isAllowedFile(filePath, allowRoots) {
170
170
  return allowRoots.some((root) => isFileInRoot(root, filePath));
171
171
  }
172
+ /**
173
+ * Whether a static import `value` is a public-directory asset, i.e. a
174
+ * root-absolute Vite URL (`/foo.png`) that maps to an existing file under
175
+ * `config.publicDir`. The Vue SFC compiler turns `<img src="/foo.png">` into a
176
+ * static `import`, but public assets are served by URL rather than
177
+ * module-resolved, so `/foo.png` is a Vite URL — not a filesystem-absolute path
178
+ * — and must be exempted from the `server.fs.allow` check.
179
+ */
180
+ function isPublicAsset(value, config) {
181
+ if (!config.publicDir || !value.startsWith("/") || value.startsWith("/@")) return false;
182
+ const publicDir = normalizeFsPath(config.publicDir);
183
+ const publicPath = normalizeFsPath(path.join(publicDir, cleanUrl$1(value).slice(1)));
184
+ return isFileInRoot(publicDir, publicPath) && existsSync(publicPath);
185
+ }
172
186
  function extractImportSources(code, id) {
173
187
  const result = parseSync(id, code);
174
188
  const sources = [];
@@ -698,7 +712,7 @@ function createLayoutWrapperPlugin({ data, utils }) {
698
712
  }
699
713
  //#endregion
700
714
  //#region package.json
701
- var version = "52.17.1";
715
+ var version = "52.18.0";
702
716
  //#endregion
703
717
  //#region node/integrations/addons.ts
704
718
  async function resolveAddons(addonsInConfig) {
@@ -3184,13 +3198,13 @@ function createPatchMonacoSourceMapPlugin() {
3184
3198
  }
3185
3199
  //#endregion
3186
3200
  //#region node/vite/pwa.ts
3187
- function createPWAPlugin(options) {
3201
+ const PWA_PACKAGE = "vite-plugin-pwa";
3202
+ async function createPWAPlugin(options) {
3188
3203
  const matchMode = (mode) => mode === true || mode === options.mode;
3189
- const enabled = matchMode(options.data.config.pwa);
3204
+ if (!matchMode(options.data.config.pwa)) return createPWARegisterStubPlugin();
3205
+ const VitePWA = await resolveVitePWA();
3190
3206
  const base = options.base ?? "/";
3191
- const title = options.data.config.title || "Slidev";
3192
3207
  return VitePWA({
3193
- disable: !enabled,
3194
3208
  registerType: "autoUpdate",
3195
3209
  injectRegister: null,
3196
3210
  base,
@@ -3201,7 +3215,7 @@ function createPWAPlugin(options) {
3201
3215
  navigateFallbackDenylist: [/^\/(presenter|notes|overview|print|export)/]
3202
3216
  },
3203
3217
  manifest: {
3204
- name: title,
3218
+ name: options.data.config.title || "Slidev",
3205
3219
  short_name: "Slidev",
3206
3220
  start_url: base,
3207
3221
  display: "fullscreen",
@@ -3210,6 +3224,40 @@ function createPWAPlugin(options) {
3210
3224
  }
3211
3225
  });
3212
3226
  }
3227
+ /**
3228
+ * Resolve `vite-plugin-pwa`'s `VitePWA` factory, prompting the user to install
3229
+ * the optional peer dependency when the `pwa` option is enabled but the package
3230
+ * is missing.
3231
+ */
3232
+ async function resolveVitePWA() {
3233
+ let mod = await importOptionalDependency(PWA_PACKAGE);
3234
+ if (!mod?.VitePWA && !mod?.default?.VitePWA) {
3235
+ await promptForOptionalInstallation(PWA_PACKAGE, "The \"pwa\" option");
3236
+ mod = await importOptionalDependency(PWA_PACKAGE);
3237
+ }
3238
+ const VitePWA = mod?.VitePWA ?? mod?.default?.VitePWA;
3239
+ if (!VitePWA) throw new Error(`[slidev] Failed to load "${PWA_PACKAGE}", which is required by the "pwa" option.`);
3240
+ return VitePWA;
3241
+ }
3242
+ /**
3243
+ * When PWA is disabled, resolve `virtual:pwa-register` to a no-op module. The
3244
+ * client only imports it behind the `__SLIDEV_FEATURE_PWA__` guard (stripped
3245
+ * from the build when off), but the guarded dynamic import must still resolve
3246
+ * during dev — without pulling in the optional `vite-plugin-pwa` dependency.
3247
+ */
3248
+ function createPWARegisterStubPlugin() {
3249
+ const VIRTUAL_ID = "virtual:pwa-register";
3250
+ const RESOLVED_ID = `\0${VIRTUAL_ID}`;
3251
+ return {
3252
+ name: "slidev:pwa-register-stub",
3253
+ resolveId(id) {
3254
+ return id === VIRTUAL_ID ? RESOLVED_ID : void 0;
3255
+ },
3256
+ load(id) {
3257
+ if (id === RESOLVED_ID) return "export function registerSW() { return () => Promise.resolve() }";
3258
+ }
3259
+ };
3260
+ }
3213
3261
  //#endregion
3214
3262
  //#region node/vite/remoteAssets.ts
3215
3263
  async function createRemoteAssetsPlugin({ data: { config }, mode }, pluginOptions) {
@@ -1,5 +1,5 @@
1
- import { n as getRoots } from "./resolver-BBT539iz.mjs";
2
- import { i as createSlidevMcpServer, s as parser, u as version } from "./serve-bAegrEOc.mjs";
1
+ import { n as getRoots } from "./resolver-BIhhHpe7.mjs";
2
+ import { i as createSlidevMcpServer, s as parser, u as version } from "./serve-1daxO8VB.mjs";
3
3
  import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
4
4
  //#region node/mcp/stdio.ts
5
5
  /**
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@slidev/cli",
3
3
  "type": "module",
4
- "version": "52.17.1",
4
+ "version": "52.18.0",
5
5
  "description": "Presentation slides for developers",
6
6
  "author": "Anthony Fu <anthonyfu117@hotmail.com>",
7
7
  "license": "MIT",
@@ -35,11 +35,15 @@
35
35
  "node": ">=20.12.0"
36
36
  },
37
37
  "peerDependencies": {
38
- "playwright-chromium": "^1.10.0"
38
+ "playwright-chromium": "^1.10.0",
39
+ "vite-plugin-pwa": "^1.0.0"
39
40
  },
40
41
  "peerDependenciesMeta": {
41
42
  "playwright-chromium": {
42
43
  "optional": true
44
+ },
45
+ "vite-plugin-pwa": {
46
+ "optional": true
43
47
  }
44
48
  },
45
49
  "dependencies": {
@@ -82,6 +86,7 @@
82
86
  "monaco-editor": "^0.55.1",
83
87
  "obug": "^2.1.3",
84
88
  "open": "^11.0.0",
89
+ "pathe": "^2.0.3",
85
90
  "pdf-lib": "^1.17.1",
86
91
  "picomatch": "^4.0.5",
87
92
  "plantuml-encoder": "^1.4.0",
@@ -105,7 +110,6 @@
105
110
  "uqr": "^0.1.3",
106
111
  "vite": "^8.1.3",
107
112
  "vite-plugin-inspect": "^11.4.1",
108
- "vite-plugin-pwa": "^1.3.0",
109
113
  "vite-plugin-remote-assets": "^2.1.0",
110
114
  "vite-plugin-static-copy": "^4.1.1",
111
115
  "vite-plugin-vue-server-ref": "^1.0.0",
@@ -114,9 +118,9 @@
114
118
  "yaml": "^2.9.0",
115
119
  "yargs": "^18.0.0",
116
120
  "zod": "^3.25.76",
117
- "@slidev/types": "52.17.1",
118
- "@slidev/client": "52.17.1",
119
- "@slidev/parser": "52.17.1"
121
+ "@slidev/client": "52.18.0",
122
+ "@slidev/types": "52.18.0",
123
+ "@slidev/parser": "52.18.0"
120
124
  },
121
125
  "devDependencies": {
122
126
  "@hedgedoc/markdown-it-plugins": "^2.1.4",