@vivliostyle/cli 9.8.4 → 10.0.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.
Files changed (55) hide show
  1. package/README.md +74 -30
  2. package/dist/{chunk-LI2REENX.js → chunk-2M2KXPDN.js} +16 -17
  3. package/dist/chunk-2M2KXPDN.js.map +1 -0
  4. package/dist/{chunk-PBAUN5CU.js → chunk-5DB6XVJN.js} +2 -2
  5. package/dist/chunk-5DB6XVJN.js.map +1 -0
  6. package/dist/{chunk-HYY2WKJZ.js → chunk-5K3NGLBV.js} +6 -7
  7. package/dist/chunk-5K3NGLBV.js.map +1 -0
  8. package/dist/{chunk-YUYXQJDY.js → chunk-IIKRNYAM.js} +470 -238
  9. package/dist/chunk-IIKRNYAM.js.map +1 -0
  10. package/dist/{chunk-MDTA37GZ.js → chunk-MQYXBSRJ.js} +397 -88
  11. package/dist/chunk-MQYXBSRJ.js.map +1 -0
  12. package/dist/chunk-RPMMYPTR.js +1076 -0
  13. package/dist/chunk-RPMMYPTR.js.map +1 -0
  14. package/dist/{chunk-PPI5DA75.js → chunk-YN3JNBNT.js} +425 -374
  15. package/dist/chunk-YN3JNBNT.js.map +1 -0
  16. package/dist/{chunk-QOPM72CS.js → chunk-YVNDJXMI.js} +32 -33
  17. package/dist/chunk-YVNDJXMI.js.map +1 -0
  18. package/dist/{chunk-FXUEYQRY.js → chunk-ZIK6DINS.js} +3 -3
  19. package/dist/chunk-ZIK6DINS.js.map +1 -0
  20. package/dist/chunk-ZKEIYNLT.js +331 -0
  21. package/dist/chunk-ZKEIYNLT.js.map +1 -0
  22. package/dist/cli.js +7 -8
  23. package/dist/cli.js.map +1 -1
  24. package/dist/commands/build.js +29 -17
  25. package/dist/commands/build.js.map +1 -1
  26. package/dist/commands/create.d.ts +2 -0
  27. package/dist/commands/create.js +64 -0
  28. package/dist/commands/create.js.map +1 -0
  29. package/dist/commands/init.js +23 -14
  30. package/dist/commands/init.js.map +1 -1
  31. package/dist/commands/preview.js +26 -20
  32. package/dist/commands/preview.js.map +1 -1
  33. package/dist/config/schema.d.ts +9034 -4436
  34. package/dist/config/schema.js +20 -4
  35. package/dist/index.d.ts +46 -7
  36. package/dist/index.js +24 -16
  37. package/dist/index.js.map +1 -1
  38. package/dist/node-modules.d.ts +5 -5
  39. package/dist/node-modules.js +1 -1
  40. package/dist/vite-adapter.d.ts +1 -0
  41. package/dist/vite-adapter.js +6 -6
  42. package/package.json +38 -27
  43. package/dist/chunk-3VKIUKTD.js +0 -89
  44. package/dist/chunk-3VKIUKTD.js.map +0 -1
  45. package/dist/chunk-4IIM6RSG.js +0 -71
  46. package/dist/chunk-4IIM6RSG.js.map +0 -1
  47. package/dist/chunk-FXUEYQRY.js.map +0 -1
  48. package/dist/chunk-HYY2WKJZ.js.map +0 -1
  49. package/dist/chunk-LI2REENX.js.map +0 -1
  50. package/dist/chunk-MDTA37GZ.js.map +0 -1
  51. package/dist/chunk-PBAUN5CU.js.map +0 -1
  52. package/dist/chunk-PPI5DA75.js.map +0 -1
  53. package/dist/chunk-QOPM72CS.js.map +0 -1
  54. package/dist/chunk-YUYXQJDY.js.map +0 -1
  55. package/types/playwright.d.ts +0 -49
@@ -1,15 +1,19 @@
1
- import {
2
- importNodeModule
3
- } from "./chunk-FXUEYQRY.js";
4
1
  import {
5
2
  DetailError,
3
+ GlobMatcher,
6
4
  Logger,
7
5
  assertPubManifestSchema,
8
6
  cwd,
9
7
  debounce,
8
+ detectBrowserPlatform,
9
+ getAssetMatcher,
10
+ getCacheDir,
11
+ getDefaultBrowserTag,
10
12
  getDefaultEpubOpfPath,
11
13
  getEpubRootDir,
12
14
  getFormattedError,
15
+ getOsLocale,
16
+ getWebPubResourceMatcher,
13
17
  isInContainer,
14
18
  isRunningOnWSL,
15
19
  isValidUri,
@@ -26,15 +30,16 @@ import {
26
30
  touchTmpFile,
27
31
  useTmpDirectory,
28
32
  writeFileIfChanged
29
- } from "./chunk-MDTA37GZ.js";
33
+ } from "./chunk-MQYXBSRJ.js";
30
34
  import {
31
35
  VivliostyleConfigSchema
32
- } from "./chunk-YUYXQJDY.js";
36
+ } from "./chunk-IIKRNYAM.js";
33
37
  import {
34
38
  CONTAINER_LOCAL_HOSTNAME,
35
39
  CONTAINER_URL,
36
40
  COVER_HTML_FILENAME,
37
41
  COVER_HTML_IMAGE_ALT,
42
+ DEFAULT_BROWSER_VERSIONS,
38
43
  EMPTY_DATA_URI,
39
44
  EPUB_CONTAINER_XML,
40
45
  EPUB_LANDMARKS_COVER_ENTRY,
@@ -49,7 +54,10 @@ import {
49
54
  XML_DECLARATION,
50
55
  cliVersion,
51
56
  viewerRoot
52
- } from "./chunk-4IIM6RSG.js";
57
+ } from "./chunk-ZKEIYNLT.js";
58
+ import {
59
+ importNodeModule
60
+ } from "./chunk-ZIK6DINS.js";
53
61
  import {
54
62
  __callDispose,
55
63
  __using
@@ -180,7 +188,7 @@ function mergeInlineConfig({ tasks, inlineOptions }, inlineConfig) {
180
188
  renderMode,
181
189
  preflight,
182
190
  preflightOption,
183
- vite,
191
+ vite: vite5,
184
192
  viteConfigFile,
185
193
  host,
186
194
  port,
@@ -202,7 +210,7 @@ function mergeInlineConfig({ tasks, inlineOptions }, inlineConfig) {
202
210
  viewer,
203
211
  viewerParam,
204
212
  browser,
205
- vite,
213
+ vite: vite5,
206
214
  viteConfigFile
207
215
  }),
208
216
  output: (output?.length ? output : task.output)?.map((o) => ({
@@ -220,6 +228,11 @@ function mergeInlineConfig({ tasks, inlineOptions }, inlineConfig) {
220
228
  })),
221
229
  inlineOptions: {
222
230
  ...pruneObject(inlineOptions),
231
+ ...pruneObject({
232
+ renderMode,
233
+ preflight,
234
+ preflightOption
235
+ }),
223
236
  ...pruneObject(
224
237
  overrideInlineOptions
225
238
  )
@@ -228,7 +241,10 @@ function mergeInlineConfig({ tasks, inlineOptions }, inlineConfig) {
228
241
  }
229
242
 
230
243
  // src/config/resolve.ts
231
- import { VFM } from "@vivliostyle/vfm";
244
+ import {
245
+ readMetadata,
246
+ VFM
247
+ } from "@vivliostyle/vfm";
232
248
  import { lookup as mime } from "mime-types";
233
249
  import fs3 from "node:fs";
234
250
  import { fileURLToPath, pathToFileURL as pathToFileURL2 } from "node:url";
@@ -236,38 +252,31 @@ import npa from "npm-package-arg";
236
252
  import upath2 from "upath";
237
253
 
238
254
  // src/processor/markdown.ts
239
- import {
240
- readMetadata
241
- } from "@vivliostyle/vfm";
242
255
  import fs2 from "node:fs";
243
256
  import vfile from "vfile";
244
- function safeReadMetadata(content) {
245
- try {
246
- return readMetadata(content);
247
- } catch {
248
- return {};
249
- }
250
- }
251
- async function processMarkdown(documentProcessorFactory, filepath, options = {}) {
257
+ async function processMarkdown(documentProcessorFactory, documentMetadataReader, filepath, options = {}) {
252
258
  const markdownString = fs2.readFileSync(filepath, "utf8");
253
259
  const processor = documentProcessorFactory(
254
260
  options,
255
- safeReadMetadata(markdownString)
261
+ documentMetadataReader(markdownString)
256
262
  );
257
263
  const processed = await processor.process(
258
264
  vfile({ path: filepath, contents: markdownString })
259
265
  );
260
266
  return processed;
261
267
  }
262
- function readMarkdownMetadata(filepath) {
263
- return safeReadMetadata(fs2.readFileSync(filepath, "utf8"));
268
+ function readMarkdownMetadata(filepath, documentMetadataReader) {
269
+ return documentMetadataReader(fs2.readFileSync(filepath, "utf8"));
264
270
  }
265
271
 
266
272
  // src/config/resolve.ts
267
273
  var manuscriptMediaTypes = [
268
274
  "text/markdown",
269
275
  "text/html",
270
- "application/xhtml+xml"
276
+ "text/plain",
277
+ "application/xhtml+xml",
278
+ // a special MIME type indicates that a custom processor is used
279
+ "text/x-vivliostyle-custom"
271
280
  ];
272
281
  var UseTemporaryServerRoot = Symbol("UseTemporaryServerRoot");
273
282
  var DEFAULT_ASSET_EXTENSIONS = [
@@ -288,6 +297,17 @@ var DEFAULT_ASSET_EXTENSIONS = [
288
297
  function isManuscriptMediaType(mediaType) {
289
298
  return !!(mediaType && manuscriptMediaTypes.includes(mediaType));
290
299
  }
300
+ var htmlExtensions = [".html", ".htm", ".xhtml", ".xht"];
301
+ function toHtmlExtension(filename) {
302
+ const ext = upath2.extname(filename).toLowerCase();
303
+ if (htmlExtensions.includes(
304
+ // @ts-expect-error check membership
305
+ ext
306
+ )) {
307
+ return filename;
308
+ }
309
+ return `${filename.slice(0, -ext.length)}.html`;
310
+ }
291
311
  function isWebPubConfig(config) {
292
312
  return config.viewerInput.type === "webpub";
293
313
  }
@@ -377,13 +397,14 @@ function parseFileMetadata({
377
397
  contentType,
378
398
  sourcePath,
379
399
  workspaceDir,
380
- themesDir
400
+ themesDir,
401
+ documentMetadataReader
381
402
  }) {
382
403
  const sourceDir = upath2.dirname(sourcePath);
383
404
  let title;
384
405
  let themes;
385
- if (contentType === "text/markdown") {
386
- const metadata = readMarkdownMetadata(sourcePath);
406
+ if (documentMetadataReader) {
407
+ const metadata = readMarkdownMetadata(sourcePath, documentMetadataReader);
387
408
  title = metadata.title;
388
409
  if (metadata.vfm?.theme && themesDir) {
389
410
  themes = [metadata.vfm.theme].flat().filter(
@@ -397,7 +418,7 @@ function parseFileMetadata({
397
418
  })
398
419
  );
399
420
  }
400
- } else {
421
+ } else if (contentType === "text/html" || contentType === "application/xhtml+xml") {
401
422
  const content = fs3.readFileSync(sourcePath, "utf8");
402
423
  title = content.match(/<title>([^<]*)<\/title>/)?.[1] || void 0;
403
424
  }
@@ -437,7 +458,6 @@ function resolveTaskConfig(config, options) {
437
458
  const singleDoc = options.singleDoc ?? false;
438
459
  const quick = options.quick ?? false;
439
460
  const temporaryFilePrefix = config.temporaryFilePrefix ?? `.vs-${Date.now()}.`;
440
- const documentProcessorFactory = config?.documentProcessor ?? VFM;
441
461
  const vfmOptions = {
442
462
  ...config?.vfm,
443
463
  hardLineBreaks: config?.vfm?.hardLineBreaks ?? false,
@@ -445,10 +465,15 @@ function resolveTaskConfig(config, options) {
445
465
  };
446
466
  const timeout = config.timeout ?? 3e5;
447
467
  const sandbox = options.sandbox ?? false;
448
- const browser = {
449
- type: config.browser ?? "chromium",
450
- executablePath: options.executableBrowser
451
- };
468
+ const browser = (() => {
469
+ const type = config.browser?.type ?? "chrome";
470
+ const platform = detectBrowserPlatform();
471
+ return {
472
+ type,
473
+ tag: config.browser?.tag ?? (platform ? DEFAULT_BROWSER_VERSIONS[type][platform] : "latest"),
474
+ executablePath: options.executableBrowser
475
+ };
476
+ })();
452
477
  const proxyServer = options.proxyServer ?? process.env.HTTP_PROXY ?? void 0;
453
478
  const proxy = proxyServer ? {
454
479
  server: proxyServer,
@@ -611,7 +636,6 @@ function resolveTaskConfig(config, options) {
611
636
  quick,
612
637
  language,
613
638
  readingProgression,
614
- documentProcessorFactory,
615
639
  vfmOptions,
616
640
  cover,
617
641
  timeout,
@@ -691,15 +715,22 @@ function resolveSingleInputConfig({
691
715
  const themesDir = upath2.resolve(workspaceDir, "themes");
692
716
  if (input.format === "markdown") {
693
717
  const contentType = "text/markdown";
718
+ const documentProcessor = {
719
+ processorFactory: config.documentProcessor ?? VFM,
720
+ metadataReader: config.documentMetadataReader ?? readMetadata
721
+ };
694
722
  const metadata = parseFileMetadata({
695
723
  contentType,
696
724
  sourcePath,
697
- workspaceDir
698
- });
699
- const target = upath2.resolve(
700
725
  workspaceDir,
701
- `${temporaryFilePrefix}${upath2.basename(sourcePath)}`
702
- ).replace(/\.md$/, ".html");
726
+ documentMetadataReader: documentProcessor.metadataReader
727
+ });
728
+ const target = toHtmlExtension(
729
+ upath2.resolve(
730
+ workspaceDir,
731
+ `${temporaryFilePrefix}${upath2.basename(sourcePath)}`
732
+ )
733
+ );
703
734
  touchTmpFile(target);
704
735
  const themes = metadata.themes ?? config.theme?.map(
705
736
  (theme) => parseTheme({
@@ -715,7 +746,8 @@ function resolveSingleInputConfig({
715
746
  source: {
716
747
  type: "file",
717
748
  pathname: sourcePath,
718
- contentType
749
+ contentType,
750
+ documentProcessor
719
751
  },
720
752
  target,
721
753
  title: metadata.title,
@@ -725,7 +757,7 @@ function resolveSingleInputConfig({
725
757
  source: target,
726
758
  target: upath2.resolve(
727
759
  upath2.dirname(target),
728
- upath2.basename(sourcePath).replace(/\.md$/, ".html")
760
+ toHtmlExtension(upath2.basename(sourcePath))
729
761
  )
730
762
  });
731
763
  }
@@ -849,6 +881,10 @@ function resolveComposedProjectConfig({
849
881
  };
850
882
  const projectTitle = config?.title ?? pkgJson?.name;
851
883
  const projectAuthor = config?.author ?? pkgJson?.author;
884
+ const rootDocumentProcessor = {
885
+ processorFactory: config.documentProcessor ?? VFM,
886
+ metadataReader: config.documentMetadataReader ?? readMetadata
887
+ };
852
888
  const isContentsEntry = (entry) => entry.rel === "contents";
853
889
  const isCoverEntry = (entry) => entry.rel === "cover";
854
890
  const isArticleEntry = (entry) => !isContentsEntry(entry) && !isCoverEntry(entry);
@@ -869,12 +905,19 @@ function resolveComposedProjectConfig({
869
905
  }
870
906
  const pathname = upath2.resolve(entryContextDir, entryPath);
871
907
  statFileSync(pathname);
872
- const contentType = mime(pathname);
873
- if (!isManuscriptMediaType(contentType)) {
908
+ const rawContentType = mime(pathname);
909
+ const documentProcessor = {
910
+ processorFactory: "documentProcessor" in entry && entry.documentProcessor || rootDocumentProcessor.processorFactory,
911
+ metadataReader: "documentMetadataReader" in entry && entry.documentMetadataReader || rootDocumentProcessor.metadataReader
912
+ };
913
+ const hasCustomProcessor = !!(documentProcessor.processorFactory !== VFM || documentProcessor.metadataReader !== readMetadata);
914
+ const contentType = hasCustomProcessor && rawContentType !== "text/markdown" ? "text/x-vivliostyle-custom" : rawContentType;
915
+ if (!isManuscriptMediaType(contentType) || contentType === "text/plain") {
874
916
  throw new Error(
875
- `Invalid manuscript type ${contentType} detected: ${entry}`
917
+ `Invalid manuscript type ${rawContentType} detected: ${entry}`
876
918
  );
877
919
  }
920
+ const useDocumentProcessor = contentType === "text/markdown" || contentType === "text/x-vivliostyle-custom";
878
921
  return {
879
922
  type: "file",
880
923
  pathname,
@@ -883,8 +926,10 @@ function resolveComposedProjectConfig({
883
926
  contentType,
884
927
  sourcePath: pathname,
885
928
  workspaceDir,
886
- themesDir
887
- })
929
+ themesDir,
930
+ documentMetadataReader: useDocumentProcessor ? documentProcessor.metadataReader : void 0
931
+ }),
932
+ ...useDocumentProcessor && { documentProcessor }
888
933
  };
889
934
  };
890
935
  const getTargetPath = (source) => {
@@ -892,7 +937,7 @@ function resolveComposedProjectConfig({
892
937
  case "file":
893
938
  return upath2.resolve(
894
939
  workspaceDir,
895
- upath2.relative(entryContextDir, source.pathname).replace(/\.md$/, ".html")
940
+ toHtmlExtension(upath2.relative(entryContextDir, source.pathname))
896
941
  );
897
942
  case "uri": {
898
943
  const url = new URL(source.href, "a://dummy");
@@ -1065,77 +1110,211 @@ Maybe you want to set the "output" field instead.`
1065
1110
  };
1066
1111
  }
1067
1112
 
1113
+ // src/vite/vite-plugin-browser.ts
1114
+ import "vite";
1115
+
1068
1116
  // src/browser.ts
1069
1117
  import fs4 from "node:fs";
1118
+ import upath3 from "upath";
1119
+ var browserEnumMap = {
1120
+ chrome: "chrome",
1121
+ chromium: "chromium",
1122
+ firefox: "firefox"
1123
+ };
1070
1124
  async function launchBrowser({
1071
1125
  browserType,
1072
1126
  proxy,
1073
1127
  executablePath,
1074
1128
  headless,
1075
1129
  noSandbox,
1076
- disableDevShmUsage
1130
+ disableDevShmUsage,
1131
+ ignoreHttpsErrors
1077
1132
  }) {
1078
- const playwright = await importNodeModule("playwright-core");
1079
- playwright.firefox.executablePath;
1080
- const options = browserType === "chromium" ? {
1133
+ const puppeteer = await importNodeModule("puppeteer-core");
1134
+ const args = [];
1135
+ if (browserType === "chrome" || browserType === "chromium") {
1136
+ args.push(
1137
+ "--disable-field-trial-config",
1138
+ "--disable-back-forward-cache",
1139
+ "--disable-component-update",
1140
+ "--no-default-browser-check",
1141
+ "--disable-features=AcceptCHFrame,AvoidUnnecessaryBeforeUnloadCheckSync,DestroyProfileOnBrowserClose,DialMediaRouteProvider,GlobalMediaControls,HttpsUpgrades,LensOverlay,MediaRouter,PaintHolding,ThirdPartyStoragePartitioning,Translate,AutoDeElevate,RenderDocument",
1142
+ "--enable-features=CDPScreenshotNewSurface",
1143
+ "--no-service-autorun",
1144
+ "--unsafely-disable-devtools-self-xss-warnings",
1145
+ "--edge-skip-compat-layer-relaunch"
1146
+ );
1147
+ if (process.platform === "darwin") {
1148
+ args.push("--enable-unsafe-swiftshader");
1149
+ }
1150
+ if (noSandbox) {
1151
+ args.push("--no-sandbox");
1152
+ }
1153
+ if (headless) {
1154
+ args.push(
1155
+ "--hide-scrollbars",
1156
+ "--mute-audio",
1157
+ "--blink-settings=primaryHoverType=2,availableHoverTypes=2,primaryPointerType=4,availablePointerTypes=4"
1158
+ );
1159
+ }
1160
+ if (proxy?.server) {
1161
+ const proxyURL = new URL(proxy.server);
1162
+ const isSocks = proxyURL.protocol === "socks5:";
1163
+ if (isSocks) {
1164
+ args.push(
1165
+ `--host-resolver-rules="MAP * ~NOTFOUND , EXCLUDE ${proxyURL.hostname}"`
1166
+ );
1167
+ }
1168
+ args.push(`--proxy-server=${proxy.server}`);
1169
+ const proxyBypassRules = [];
1170
+ if (proxy.bypass) {
1171
+ proxyBypassRules.push(
1172
+ ...proxy.bypass.split(",").map((t) => t.trim()).map((t) => t.startsWith(".") ? "*" + t : t)
1173
+ );
1174
+ }
1175
+ proxyBypassRules.push("<-loopback>");
1176
+ args.push(`--proxy-bypass-list=${proxyBypassRules.join(";")}`);
1177
+ }
1178
+ args.push("--disable-web-security");
1179
+ if (disableDevShmUsage) {
1180
+ args.push("--disable-dev-shm-usage");
1181
+ }
1182
+ if (headless) {
1183
+ args.push("--force-device-scale-factor=1");
1184
+ }
1185
+ if (isRunningOnWSL()) {
1186
+ args.push("--disable-gpu");
1187
+ }
1188
+ args.push("--lang=en");
1189
+ if (!headless && process.platform === "darwin") {
1190
+ args.push("-AppleLanguages", "(en)");
1191
+ }
1192
+ args.push("--no-startup-window");
1193
+ }
1194
+ const launchOptions = {
1081
1195
  executablePath,
1082
- chromiumSandbox: !noSandbox,
1196
+ args,
1197
+ browser: browserType === "chromium" ? "chrome" : browserType,
1083
1198
  headless,
1084
- args: [
1085
- // #579: disable web security to allow cross-origin requests
1086
- "--disable-web-security",
1087
- ...disableDevShmUsage ? ["--disable-dev-shm-usage"] : [],
1088
- // #357: Set devicePixelRatio=1 otherwise it causes layout issues in HiDPI displays
1089
- ...headless ? ["--force-device-scale-factor=1"] : [],
1090
- // #565: Add --disable-gpu option when running on WSL
1091
- ...isRunningOnWSL() ? ["--disable-gpu"] : [],
1092
- // set Chromium language to English to avoid locale-dependent issues
1093
- "--lang=en",
1094
- ...!headless && process.platform === "darwin" ? ["", "-AppleLanguages", "(en)"] : []
1095
- ],
1096
- env: { ...process.env, LANG: "en.UTF-8" },
1097
- proxy
1098
- } : (
1099
- // TODO: Investigate appropriate settings on Firefox & Webkit
1100
- { executablePath, headless }
1101
- );
1102
- const browser = await playwright[browserType].launch(options);
1199
+ acceptInsecureCerts: ignoreHttpsErrors,
1200
+ waitForInitialPage: false
1201
+ };
1202
+ Logger.debug("launchOptions %O", launchOptions);
1203
+ const browser = await puppeteer.launch({
1204
+ ...launchOptions,
1205
+ env: { ...process.env, LANG: "en.UTF-8" }
1206
+ });
1103
1207
  registerExitHandler("Closing browser", () => {
1104
1208
  browser.close();
1105
1209
  });
1106
- return browser;
1210
+ const [browserContext] = browser.browserContexts();
1211
+ return { browser, browserContext };
1107
1212
  }
1108
- async function getExecutableBrowserPath(browserType) {
1109
- const playwright = await importNodeModule("playwright-core");
1110
- return playwright[browserType].executablePath();
1213
+ function getPuppeteerCacheDir() {
1214
+ if (isInContainer()) {
1215
+ return "/opt/puppeteer";
1216
+ }
1217
+ return upath3.join(getCacheDir(), "browsers");
1111
1218
  }
1112
- function getFullBrowserName(browserType) {
1113
- return {
1114
- chromium: "Chromium",
1115
- firefox: "Firefox",
1116
- webkit: "Webkit"
1117
- }[browserType];
1219
+ async function resolveBuildId({
1220
+ type,
1221
+ tag,
1222
+ browsers
1223
+ }) {
1224
+ const cacheDataFilename = upath3.join(
1225
+ getPuppeteerCacheDir(),
1226
+ "build-ids.json"
1227
+ );
1228
+ let cacheData;
1229
+ try {
1230
+ cacheData = JSON.parse(fs4.readFileSync(cacheDataFilename, "utf-8"));
1231
+ if (Date.now() - cacheData.createdAt > 24 * 60 * 60 * 1e3) {
1232
+ cacheData = { createdAt: Date.now(), buildIds: {} };
1233
+ }
1234
+ } catch (_) {
1235
+ cacheData = { createdAt: Date.now(), buildIds: {} };
1236
+ }
1237
+ if (cacheData.buildIds[type]?.[tag]) {
1238
+ return cacheData.buildIds[type][tag];
1239
+ }
1240
+ const platform = detectBrowserPlatform();
1241
+ if (!platform) {
1242
+ throw new Error("The current platform is not supported.");
1243
+ }
1244
+ const buildId = await browsers.resolveBuildId(
1245
+ browserEnumMap[type],
1246
+ platform,
1247
+ tag
1248
+ );
1249
+ (cacheData.buildIds[type] ??= {})[tag] = buildId;
1250
+ fs4.mkdirSync(upath3.dirname(cacheDataFilename), { recursive: true });
1251
+ fs4.writeFileSync(cacheDataFilename, JSON.stringify(cacheData));
1252
+ return buildId;
1253
+ }
1254
+ async function cleanupOutdatedBrowsers() {
1255
+ for (const browser of Object.values(browserEnumMap)) {
1256
+ const browsersDir = upath3.join(getPuppeteerCacheDir(), browser);
1257
+ if (!fs4.existsSync(browsersDir)) {
1258
+ continue;
1259
+ }
1260
+ const entries = fs4.readdirSync(browsersDir);
1261
+ for (const entry of entries) {
1262
+ const entryPath = upath3.join(browsersDir, entry);
1263
+ const stat = fs4.statSync(entryPath);
1264
+ if (!stat.isDirectory() || Date.now() - stat.mtimeMs > 7 * 24 * 60 * 60 * 1e3) {
1265
+ Logger.debug(`Removing outdated browser at ${entryPath}`);
1266
+ await fs4.promises.rm(entryPath, { recursive: true, force: true });
1267
+ }
1268
+ }
1269
+ }
1270
+ }
1271
+ async function getExecutableBrowserPath({
1272
+ type,
1273
+ tag
1274
+ }) {
1275
+ const browsers = await importNodeModule("@puppeteer/browsers");
1276
+ const buildId = await resolveBuildId({ type, tag, browsers });
1277
+ return browsers.computeExecutablePath({
1278
+ cacheDir: getPuppeteerCacheDir(),
1279
+ browser: browserEnumMap[type],
1280
+ buildId
1281
+ });
1118
1282
  }
1119
1283
  function checkBrowserAvailability(path) {
1120
1284
  return fs4.existsSync(path);
1121
1285
  }
1122
- async function downloadBrowser(browserType) {
1123
- const { registry } = await importNodeModule("playwright-core/lib/server");
1124
- const executable = registry.findExecutable(browserType);
1286
+ async function downloadBrowser({
1287
+ type,
1288
+ tag
1289
+ }) {
1290
+ const browsers = await importNodeModule("@puppeteer/browsers");
1291
+ const buildId = await resolveBuildId({ type, tag, browsers });
1292
+ let installedBrowser;
1293
+ if (isInContainer()) {
1294
+ const defaultBrowserVersion = getDefaultBrowserTag("chrome");
1295
+ Logger.logWarn(
1296
+ `The container you are using already includes a browser (chrome@${defaultBrowserVersion}); however, the specified browser ${type}@${tag} was not found. Downloading the browser inside the container may take a long time. Consider using a container image that includes the required browser version.`
1297
+ );
1298
+ }
1125
1299
  {
1126
1300
  var _stack = [];
1127
1301
  try {
1128
1302
  const _2 = __using(_stack, Logger.suspendLogging(
1129
1303
  "Rendering browser is not installed yet. Downloading now."
1130
1304
  ));
1131
- await registry.install([executable], false);
1305
+ installedBrowser = await browsers.install({
1306
+ cacheDir: getPuppeteerCacheDir(),
1307
+ browser: browserEnumMap[type],
1308
+ buildId,
1309
+ downloadProgressCallback: "default"
1310
+ });
1132
1311
  } catch (_) {
1133
1312
  var _error = _, _hasError = true;
1134
1313
  } finally {
1135
1314
  __callDispose(_stack, _error, _hasError);
1136
1315
  }
1137
1316
  }
1138
- return executable.executablePath();
1317
+ return installedBrowser.executablePath;
1139
1318
  }
1140
1319
  async function launchPreview({
1141
1320
  mode,
@@ -1145,48 +1324,59 @@ async function launchPreview({
1145
1324
  config: { browser: browserConfig, proxy, sandbox, ignoreHttpsErrors }
1146
1325
  }) {
1147
1326
  let executableBrowser = browserConfig.executablePath;
1327
+ Logger.debug(`Specified browser path: ${executableBrowser}`);
1148
1328
  if (executableBrowser) {
1149
1329
  if (!checkBrowserAvailability(executableBrowser)) {
1150
1330
  throw new Error(
1151
1331
  `Cannot find the browser. Please check the executable browser path: ${executableBrowser}`
1152
1332
  );
1153
1333
  }
1334
+ } else if (detectBrowserPlatform() === "linux_arm" && (browserConfig.type === "chrome" || browserConfig.type === "chromium")) {
1335
+ Logger.logInfo(
1336
+ "The official Chrome/Chromium binaries are not available for ARM64 Linux. Using the system-installed Chromium browser instead."
1337
+ );
1338
+ executableBrowser = "/usr/bin/chromium";
1154
1339
  } else {
1155
- executableBrowser = await getExecutableBrowserPath(browserConfig.type);
1340
+ executableBrowser = await getExecutableBrowserPath(browserConfig);
1341
+ Logger.debug(`Using default browser: ${executableBrowser}`);
1156
1342
  if (!checkBrowserAvailability(executableBrowser)) {
1157
- await downloadBrowser(browserConfig.type);
1343
+ await cleanupOutdatedBrowsers();
1344
+ await downloadBrowser(browserConfig);
1158
1345
  }
1159
1346
  }
1160
- Logger.debug(`Executing browser path: ${executableBrowser}`);
1161
- const browser = await launchBrowser({
1347
+ const { browser, browserContext } = await launchBrowser({
1162
1348
  browserType: browserConfig.type,
1163
1349
  proxy,
1164
1350
  executablePath: executableBrowser,
1165
1351
  headless: mode === "build",
1166
1352
  noSandbox: !sandbox,
1167
- disableDevShmUsage: isInContainer()
1353
+ disableDevShmUsage: isInContainer(),
1354
+ ignoreHttpsErrors
1168
1355
  });
1169
1356
  await onBrowserOpen?.(browser);
1170
- const page = await browser.newPage({
1171
- viewport: mode === "build" ? (
1172
- // This viewport size important to detect headless environment in Vivliostyle viewer
1357
+ const page = (await browserContext.pages())[0] ?? await browserContext.newPage();
1358
+ await page.setViewport(
1359
+ mode === "build" ? (
1360
+ // This viewport size is important to detect headless environment in Vivliostyle viewer
1173
1361
  // https://github.com/vivliostyle/vivliostyle.js/blob/73bcf323adcad80126b0175630609451ccd09d8a/packages/core/src/vivliostyle/vgen.ts#L2489-L2500
1174
- {
1175
- width: 800,
1176
- height: 600
1177
- }
1178
- ) : null,
1179
- ignoreHTTPSErrors: ignoreHttpsErrors
1180
- });
1362
+ { width: 800, height: 600 }
1363
+ ) : null
1364
+ );
1181
1365
  await onPageOpen?.(page);
1182
1366
  page.on("dialog", () => {
1183
1367
  });
1368
+ if (proxy?.username && proxy?.password) {
1369
+ await page.authenticate({
1370
+ username: proxy.username,
1371
+ password: proxy.password
1372
+ });
1373
+ }
1184
1374
  await page.goto(url);
1185
1375
  return { browser, page };
1186
1376
  }
1187
1377
 
1188
1378
  // src/server.ts
1189
- import fs11 from "node:fs";
1379
+ import fs10 from "node:fs";
1190
1380
  import { URL as URL2 } from "node:url";
1191
1381
  import upath11 from "upath";
1192
1382
  import {
@@ -1199,170 +1389,22 @@ import escapeRe from "escape-string-regexp";
1199
1389
  import { pathToFileURL as pathToFileURL6 } from "node:url";
1200
1390
  import sirv from "sirv";
1201
1391
  import upath8 from "upath";
1202
-
1203
- // src/processor/asset.ts
1204
- import { copy } from "fs-extra/esm";
1205
- import fs5 from "node:fs";
1206
- import picomatch from "picomatch";
1207
- import { glob } from "tinyglobby";
1208
- import upath3 from "upath";
1209
- var GlobMatcher = class {
1210
- constructor(matcherConfig) {
1211
- this.matcherConfig = matcherConfig;
1212
- this.#_matchers = matcherConfig.map(
1213
- ({ patterns, ...options }) => picomatch(patterns, options)
1214
- );
1215
- }
1216
- #_matchers;
1217
- match(test) {
1218
- return this.#_matchers.some((matcher) => matcher(test));
1219
- }
1220
- async glob(globOptions = {}) {
1221
- return new Set(
1222
- (await Promise.all(
1223
- this.matcherConfig.map(
1224
- (config) => glob({ ...config, ...globOptions })
1225
- )
1226
- )).flat()
1227
- );
1228
- }
1229
- };
1230
- function getIgnoreThemeDirectoryPatterns({
1231
- themesDir,
1232
- cwd: cwd2
1233
- }) {
1234
- return pathContains(cwd2, themesDir) ? [
1235
- `${upath3.relative(cwd2, themesDir)}/node_modules/*/example`,
1236
- `${upath3.relative(cwd2, themesDir)}/node_modules/*/*/example`
1237
- ] : [];
1238
- }
1239
- function getIgnoreAssetPatterns({
1240
- outputs,
1241
- entries,
1242
- cwd: cwd2
1243
- }) {
1244
- return [
1245
- ...outputs.flatMap(
1246
- ({ format, path: p }) => !pathContains(cwd2, p) ? [] : format === "webpub" ? upath3.join(upath3.relative(cwd2, p), "**") : upath3.relative(cwd2, p)
1247
- ),
1248
- ...entries.flatMap(({ template }) => {
1249
- return template?.type === "file" && pathContains(cwd2, template.pathname) ? upath3.relative(cwd2, template.pathname) : [];
1250
- })
1251
- ];
1252
- }
1253
- function getWebPubResourceMatcher({
1254
- outputs,
1255
- themesDir,
1256
- entries,
1257
- cwd: cwd2,
1258
- manifestPath,
1259
- copyAsset: { fileExtensions }
1260
- }) {
1261
- return new GlobMatcher([
1262
- {
1263
- patterns: [
1264
- `**/${upath3.relative(cwd2, manifestPath)}`,
1265
- "**/*.{html,htm,xhtml,xht}",
1266
- `**/*.{${fileExtensions.join(",")}}`
1267
- ],
1268
- ignore: [
1269
- ...getIgnoreAssetPatterns({
1270
- cwd: cwd2,
1271
- outputs,
1272
- entries
1273
- }),
1274
- ...getIgnoreThemeDirectoryPatterns({
1275
- cwd: cwd2,
1276
- themesDir
1277
- }),
1278
- // Ignore node_modules in the root directory
1279
- "node_modules/**",
1280
- // only include dotfiles starting with `.vs-`
1281
- "**/.!(vs-*)/**"
1282
- ],
1283
- dot: true,
1284
- cwd: cwd2
1285
- }
1286
- ]);
1287
- }
1288
- function getAssetMatcher({
1289
- copyAsset: { fileExtensions, includes, excludes },
1290
- outputs,
1291
- themesDir,
1292
- entries,
1293
- cwd: cwd2,
1294
- ignore = []
1295
- }) {
1296
- const ignorePatterns = [
1297
- ...ignore,
1298
- ...excludes,
1299
- ...getIgnoreAssetPatterns({ outputs, entries, cwd: cwd2 })
1300
- ];
1301
- return new GlobMatcher([
1302
- // Step 1: Glob files with an extension in `fileExtension`
1303
- // Ignore files in node_modules directory, theme example files and files matched `excludes`
1304
- {
1305
- patterns: fileExtensions.map((ext) => `**/*.${ext}`),
1306
- ignore: [
1307
- "**/node_modules/**",
1308
- ...ignorePatterns,
1309
- ...getIgnoreThemeDirectoryPatterns({ themesDir, cwd: cwd2 })
1310
- ],
1311
- cwd: cwd2
1312
- },
1313
- // Step 2: Glob files matched with `includes`
1314
- // Ignore only files matched `excludes`
1315
- {
1316
- patterns: includes,
1317
- ignore: ignorePatterns,
1318
- cwd: cwd2
1319
- }
1320
- ]);
1321
- }
1322
- async function copyAssets({
1323
- entryContextDir,
1324
- workspaceDir,
1325
- copyAsset,
1326
- outputs,
1327
- themesDir,
1328
- entries
1329
- }) {
1330
- if (pathEquals(entryContextDir, workspaceDir)) {
1331
- return;
1332
- }
1333
- const relWorkspaceDir = upath3.relative(entryContextDir, workspaceDir);
1334
- const assets = await getAssetMatcher({
1335
- copyAsset,
1336
- cwd: entryContextDir,
1337
- outputs,
1338
- themesDir,
1339
- entries,
1340
- ignore: [
1341
- // don't copy workspace itself
1342
- ...relWorkspaceDir ? [upath3.join(relWorkspaceDir, "**")] : []
1343
- ]
1344
- }).glob({ followSymbolicLinks: true });
1345
- Logger.debug("assets", assets);
1346
- for (const asset of assets) {
1347
- const target = upath3.join(workspaceDir, asset);
1348
- fs5.mkdirSync(upath3.dirname(target), { recursive: true });
1349
- await copy(upath3.resolve(entryContextDir, asset), target);
1350
- }
1351
- }
1392
+ import "vite";
1352
1393
 
1353
1394
  // src/processor/compile.ts
1354
- import { copy as copy4, move } from "fs-extra/esm";
1355
- import fs9 from "node:fs";
1395
+ import "@vivliostyle/jsdom";
1396
+ import { copy as copy3, move } from "fs-extra/esm";
1397
+ import fs8 from "node:fs";
1356
1398
  import upath7 from "upath";
1357
1399
  import serializeToXml2 from "w3c-xmlserializer";
1358
1400
  import MIMEType2 from "whatwg-mimetype";
1359
1401
 
1360
1402
  // src/output/webbook.ts
1361
- import { copy as copy3 } from "fs-extra/esm";
1403
+ import { copy as copy2 } from "fs-extra/esm";
1362
1404
  import { lookup as mime3 } from "mime-types";
1363
- import fs7 from "node:fs";
1405
+ import fs6 from "node:fs";
1364
1406
  import { pathToFileURL as pathToFileURL5 } from "node:url";
1365
- import { glob as glob2 } from "tinyglobby";
1407
+ import { glob } from "tinyglobby";
1366
1408
  import upath6 from "upath";
1367
1409
 
1368
1410
  // src/processor/html.tsx
@@ -1529,8 +1571,8 @@ function getJsdomFromString({
1529
1571
  }
1530
1572
  async function getStructuredSectionFromHtml(htmlPath, href) {
1531
1573
  const dom = await getJsdomFromUrlOrFile({ src: htmlPath });
1532
- const { document } = dom.window;
1533
- const allHeadings = [...document.querySelectorAll("h1, h2, h3, h4, h5, h6")].filter((el) => {
1574
+ const { document: document2 } = dom.window;
1575
+ const allHeadings = [...document2.querySelectorAll("h1, h2, h3, h4, h5, h6")].filter((el) => {
1534
1576
  return !el.matches("blockquote *");
1535
1577
  }).sort((a, b) => {
1536
1578
  const position = a.compareDocumentPosition(b);
@@ -1695,17 +1737,17 @@ async function processTocHtml(dom, {
1695
1737
  sectionDepth,
1696
1738
  transform
1697
1739
  }) {
1698
- const { document } = dom.window;
1699
- if (!document.querySelector(
1740
+ const { document: document2 } = dom.window;
1741
+ if (!document2.querySelector(
1700
1742
  'link[rel="publication"][type="application/ld+json"]'
1701
1743
  )) {
1702
- const l = document.createElement("link");
1744
+ const l = document2.createElement("link");
1703
1745
  l.setAttribute("rel", "publication");
1704
1746
  l.setAttribute("type", "application/ld+json");
1705
1747
  l.setAttribute("href", encodeURI(upath4.relative(distDir, manifestPath)));
1706
- document.head.appendChild(l);
1748
+ document2.head.appendChild(l);
1707
1749
  }
1708
- const style = document.querySelector("style[data-vv-style]");
1750
+ const style = document2.querySelector("style[data-vv-style]");
1709
1751
  if (style) {
1710
1752
  const textContent = getTocHtmlStyle(styleOptions);
1711
1753
  if (textContent) {
@@ -1714,9 +1756,9 @@ async function processTocHtml(dom, {
1714
1756
  style.remove();
1715
1757
  }
1716
1758
  }
1717
- const nav = document.querySelector('nav, [role="doc-toc"]');
1759
+ const nav = document2.querySelector('nav, [role="doc-toc"]');
1718
1760
  if (nav && !nav.hasChildNodes()) {
1719
- const h2 = document.createElement("h2");
1761
+ const h2 = document2.createElement("h2");
1720
1762
  h2.textContent = tocTitle;
1721
1763
  nav.appendChild(h2);
1722
1764
  nav.innerHTML += await generateTocListSection({
@@ -1769,8 +1811,8 @@ async function processCoverHtml(dom, {
1769
1811
  imageAlt,
1770
1812
  styleOptions = {}
1771
1813
  }) {
1772
- const { document } = dom.window;
1773
- const style = document.querySelector("style[data-vv-style]");
1814
+ const { document: document2 } = dom.window;
1815
+ const style = document2.querySelector("style[data-vv-style]");
1774
1816
  if (style) {
1775
1817
  const textContent = getCoverHtmlStyle(styleOptions);
1776
1818
  if (textContent) {
@@ -1779,7 +1821,7 @@ async function processCoverHtml(dom, {
1779
1821
  style.remove();
1780
1822
  }
1781
1823
  }
1782
- const cover = document.querySelector('img[role="doc-cover"]');
1824
+ const cover = document2.querySelector('img[role="doc-cover"]');
1783
1825
  if (cover && !cover.hasAttribute("src")) {
1784
1826
  cover.setAttribute("src", encodeURI(imageSrc));
1785
1827
  }
@@ -1794,30 +1836,30 @@ async function processManuscriptHtml(dom, {
1794
1836
  contentType,
1795
1837
  language
1796
1838
  }) {
1797
- const { document } = dom.window;
1839
+ const { document: document2 } = dom.window;
1798
1840
  if (title) {
1799
- if (!document.querySelector("title")) {
1800
- const t = document.createElement("title");
1801
- document.head.appendChild(t);
1841
+ if (!document2.querySelector("title")) {
1842
+ const t = document2.createElement("title");
1843
+ document2.head.appendChild(t);
1802
1844
  }
1803
- document.title = title;
1845
+ document2.title = title;
1804
1846
  }
1805
1847
  for (const s of style ?? []) {
1806
- const l = document.createElement("link");
1848
+ const l = document2.createElement("link");
1807
1849
  l.setAttribute("rel", "stylesheet");
1808
1850
  l.setAttribute("type", "text/css");
1809
1851
  l.setAttribute("href", encodeURI(s));
1810
- document.head.appendChild(l);
1852
+ document2.head.appendChild(l);
1811
1853
  }
1812
1854
  if (language) {
1813
1855
  if (contentType === "application/xhtml+xml") {
1814
- if (!document.documentElement.getAttribute("xml:lang")) {
1815
- document.documentElement.setAttribute("lang", language);
1816
- document.documentElement.setAttribute("xml:lang", language);
1856
+ if (!document2.documentElement.getAttribute("xml:lang")) {
1857
+ document2.documentElement.setAttribute("lang", language);
1858
+ document2.documentElement.setAttribute("xml:lang", language);
1817
1859
  }
1818
1860
  } else {
1819
- if (!document.documentElement.getAttribute("lang")) {
1820
- document.documentElement.setAttribute("lang", language);
1861
+ if (!document2.documentElement.getAttribute("lang")) {
1862
+ document2.documentElement.setAttribute("lang", language);
1821
1863
  }
1822
1864
  }
1823
1865
  }
@@ -1828,8 +1870,8 @@ async function fetchLinkedPublicationManifest({
1828
1870
  resourceLoader,
1829
1871
  baseUrl
1830
1872
  }) {
1831
- const { document } = dom.window;
1832
- const linkEl = document.querySelector('link[href][rel="publication"]');
1873
+ const { document: document2 } = dom.window;
1874
+ const linkEl = document2.querySelector('link[href][rel="publication"]');
1833
1875
  if (!linkEl) {
1834
1876
  return null;
1835
1877
  }
@@ -1837,7 +1879,7 @@ async function fetchLinkedPublicationManifest({
1837
1879
  let manifest;
1838
1880
  let manifestUrl = baseUrl;
1839
1881
  if (href.startsWith("#")) {
1840
- const scriptEl = document.getElementById(href.slice(1));
1882
+ const scriptEl = document2.getElementById(href.slice(1));
1841
1883
  if (scriptEl?.getAttribute("type") !== "application/ld+json") {
1842
1884
  return null;
1843
1885
  }
@@ -1884,8 +1926,8 @@ ${error}`
1884
1926
  };
1885
1927
  }
1886
1928
  function parseTocDocument(dom) {
1887
- const { document } = dom.window;
1888
- const docTocEl = document.querySelectorAll('[role="doc-toc"]');
1929
+ const { document: document2 } = dom.window;
1930
+ const docTocEl = document2.querySelectorAll('[role="doc-toc"]');
1889
1931
  if (docTocEl.length === 0) {
1890
1932
  return null;
1891
1933
  }
@@ -1935,8 +1977,8 @@ function parseTocDocument(dom) {
1935
1977
  return null;
1936
1978
  }
1937
1979
  function parsePageListDocument(dom) {
1938
- const { document } = dom.window;
1939
- const docPageListEl = document.querySelectorAll('[role="doc-pagelist"]');
1980
+ const { document: document2 } = dom.window;
1981
+ const docPageListEl = document2.querySelectorAll('[role="doc-pagelist"]');
1940
1982
  if (docPageListEl.length === 0) {
1941
1983
  return null;
1942
1984
  }
@@ -1961,10 +2003,10 @@ function parsePageListDocument(dom) {
1961
2003
  import archiver from "archiver";
1962
2004
  import { lookup as lookupLanguage } from "bcp-47-match";
1963
2005
  import { XMLBuilder } from "fast-xml-parser";
1964
- import { copy as copy2 } from "fs-extra/esm";
2006
+ import { copy } from "fs-extra/esm";
1965
2007
  import GithubSlugger from "github-slugger";
1966
2008
  import { lookup as mime2 } from "mime-types";
1967
- import fs6 from "node:fs";
2009
+ import fs5 from "node:fs";
1968
2010
  import { pathToFileURL as pathToFileURL4 } from "node:url";
1969
2011
  import upath5 from "upath";
1970
2012
  import { v4 as uuid } from "uuid";
@@ -2037,8 +2079,8 @@ async function exportEpub({
2037
2079
  epubVersion
2038
2080
  });
2039
2081
  const [tmpDir] = await useTmpDirectory();
2040
- fs6.mkdirSync(upath5.join(tmpDir, "META-INF"), { recursive: true });
2041
- await copy2(webpubDir, upath5.join(tmpDir, "EPUB"));
2082
+ fs5.mkdirSync(upath5.join(tmpDir, "META-INF"), { recursive: true });
2083
+ await copy(webpubDir, upath5.join(tmpDir, "EPUB"));
2042
2084
  const uid = `urn:uuid:${uuid()}`;
2043
2085
  const entryHtmlRelPath = entryHtmlFile && upath5.relative(webpubDir, upath5.resolve(webpubDir, entryHtmlFile));
2044
2086
  const findPublicationLink = (relType, list, filter) => [list].flat().find(
@@ -2077,7 +2119,7 @@ async function exportEpub({
2077
2119
  return acc;
2078
2120
  } catch (e) {
2079
2121
  }
2080
- if (!fs6.existsSync(upath5.join(tmpDir, "EPUB", url))) {
2122
+ if (!fs5.existsSync(upath5.join(tmpDir, "EPUB", url))) {
2081
2123
  return acc;
2082
2124
  }
2083
2125
  const mediaType = encodingFormat || mime2(url) || "text/plain";
@@ -2193,19 +2235,19 @@ async function exportEpub({
2193
2235
  });
2194
2236
  }
2195
2237
  if (relManifestPath) {
2196
- await fs6.promises.rm(upath5.join(tmpDir, "EPUB", relManifestPath), {
2238
+ await fs5.promises.rm(upath5.join(tmpDir, "EPUB", relManifestPath), {
2197
2239
  force: true,
2198
2240
  recursive: true
2199
2241
  });
2200
2242
  delete manifestItem[relManifestPath];
2201
2243
  }
2202
- fs6.writeFileSync(
2244
+ fs5.writeFileSync(
2203
2245
  upath5.join(tmpDir, "META-INF/container.xml"),
2204
2246
  EPUB_CONTAINER_XML,
2205
2247
  "utf8"
2206
2248
  );
2207
2249
  Logger.debug(`Generating content.opf`);
2208
- fs6.writeFileSync(
2250
+ fs5.writeFileSync(
2209
2251
  upath5.join(tmpDir, "EPUB/content.opf"),
2210
2252
  buildEpubPackageDocument({
2211
2253
  epubVersion,
@@ -2223,7 +2265,7 @@ async function exportEpub({
2223
2265
  async function writeAsXhtml(dom, absPath) {
2224
2266
  const xhtml = `${XML_DECLARATION}
2225
2267
  ${serializeToXml(dom.window.document)}`;
2226
- await fs6.promises.writeFile(changeExtname(absPath, ".xhtml"), xhtml, "utf8");
2268
+ await fs5.promises.writeFile(changeExtname(absPath, ".xhtml"), xhtml, "utf8");
2227
2269
  }
2228
2270
  async function transpileHtmlToXhtml({
2229
2271
  target,
@@ -2231,24 +2273,24 @@ async function transpileHtmlToXhtml({
2231
2273
  }) {
2232
2274
  const absPath = upath5.join(contextDir, target);
2233
2275
  const dom = await getJsdomFromUrlOrFile({ src: absPath });
2234
- const { document } = dom.window;
2235
- document.documentElement.removeAttribute("xmlns");
2236
- document.documentElement.setAttribute("xmlns:epub", EPUB_NS);
2237
- document.querySelectorAll("a[href]").forEach((el) => {
2276
+ const { document: document2 } = dom.window;
2277
+ document2.documentElement.removeAttribute("xmlns");
2278
+ document2.documentElement.setAttribute("xmlns:epub", EPUB_NS);
2279
+ document2.querySelectorAll("a[href]").forEach((el) => {
2238
2280
  const href = decodeURI(el.getAttribute("href"));
2239
2281
  el.setAttribute("href", getRelativeHref(href, target, target));
2240
2282
  });
2241
2283
  await writeAsXhtml(dom, absPath);
2242
- await fs6.promises.unlink(absPath);
2284
+ await fs5.promises.unlink(absPath);
2243
2285
  return {
2244
2286
  dom,
2245
2287
  // FIXME: Yes, I recognize this implementation is inadequate.
2246
- hasMathmlContent: !!document.querySelector("math"),
2247
- hasRemoteResources: !!document.querySelector(
2288
+ hasMathmlContent: !!document2.querySelector("math"),
2289
+ hasRemoteResources: !!document2.querySelector(
2248
2290
  '[src^="http://"], [src^="https://"]'
2249
2291
  ),
2250
- hasScriptedContent: !!document.querySelector("script, form"),
2251
- hasSvgContent: !!document.querySelector("svg")
2292
+ hasScriptedContent: !!document2.querySelector("script, form"),
2293
+ hasSvgContent: !!document2.querySelector("svg")
2252
2294
  };
2253
2295
  }
2254
2296
  function replaceWithNavElement(dom, el) {
@@ -2270,9 +2312,9 @@ async function processTocDocument({
2270
2312
  docLanguages,
2271
2313
  landmarks
2272
2314
  }) {
2273
- const { document } = dom.window;
2315
+ const { document: document2 } = dom.window;
2274
2316
  let tocResourceTree = null;
2275
- if (!document.querySelector("nav[epub:type]")) {
2317
+ if (!document2.querySelector("nav[epub:type]")) {
2276
2318
  tocResourceTree = parseTocDocument(dom);
2277
2319
  if (tocResourceTree) {
2278
2320
  const nav = replaceWithNavElement(dom, tocResourceTree.element);
@@ -2280,15 +2322,15 @@ async function processTocDocument({
2280
2322
  nav.setAttribute("epub:type", "toc");
2281
2323
  } else {
2282
2324
  Logger.debug(`Generating toc nav element: ${target}`);
2283
- const nav = document.createElement("nav");
2325
+ const nav = document2.createElement("nav");
2284
2326
  nav.setAttribute("id", TOC_ID);
2285
2327
  nav.setAttribute("role", "doc-toc");
2286
2328
  nav.setAttribute("epub:type", "toc");
2287
2329
  nav.setAttribute("hidden", "");
2288
- const h2 = document.createElement("h2");
2330
+ const h2 = document2.createElement("h2");
2289
2331
  h2.textContent = TOC_TITLE;
2290
2332
  nav.appendChild(h2);
2291
- const ol = document.createElement("ol");
2333
+ const ol = document2.createElement("ol");
2292
2334
  tocResourceTree = {
2293
2335
  element: nav,
2294
2336
  children: []
@@ -2301,8 +2343,8 @@ async function processTocDocument({
2301
2343
  });
2302
2344
  name = dom2.window.document.title;
2303
2345
  }
2304
- const li = document.createElement("li");
2305
- const a = document.createElement("a");
2346
+ const li = document2.createElement("li");
2347
+ const a = document2.createElement("a");
2306
2348
  a.textContent = name;
2307
2349
  a.href = getRelativeHref(content.url, "", target);
2308
2350
  li.appendChild(a);
@@ -2310,22 +2352,22 @@ async function processTocDocument({
2310
2352
  tocResourceTree.children.push({ element: li, label: a });
2311
2353
  }
2312
2354
  nav.appendChild(ol);
2313
- document.body.appendChild(nav);
2355
+ document2.body.appendChild(nav);
2314
2356
  Logger.debug("Generated toc nav element", nav.outerHTML);
2315
2357
  }
2316
2358
  if (landmarks.length > 0) {
2317
2359
  Logger.debug(`Generating landmark nav element: ${target}`);
2318
- const nav = document.createElement("nav");
2360
+ const nav = document2.createElement("nav");
2319
2361
  nav.setAttribute("epub:type", "landmarks");
2320
2362
  nav.setAttribute("id", LANDMARKS_ID);
2321
2363
  nav.setAttribute("hidden", "");
2322
- const h2 = document.createElement("h2");
2364
+ const h2 = document2.createElement("h2");
2323
2365
  h2.textContent = EPUB_LANDMARKS_TITLE;
2324
2366
  nav.appendChild(h2);
2325
- const ol = document.createElement("ol");
2367
+ const ol = document2.createElement("ol");
2326
2368
  for (const { type, href, text } of landmarks) {
2327
- const li = document.createElement("li");
2328
- const a = document.createElement("a");
2369
+ const li = document2.createElement("li");
2370
+ const a = document2.createElement("a");
2329
2371
  a.setAttribute("epub:type", type);
2330
2372
  a.setAttribute("href", getRelativeHref(href, "", target));
2331
2373
  a.text = text;
@@ -2333,17 +2375,17 @@ async function processTocDocument({
2333
2375
  ol.appendChild(li);
2334
2376
  }
2335
2377
  nav.appendChild(ol);
2336
- document.body.appendChild(nav);
2378
+ document2.body.appendChild(nav);
2337
2379
  Logger.debug("Generated landmark nav element", nav.outerHTML);
2338
2380
  }
2339
2381
  }
2340
- const publicationLinkEl = document.querySelector(
2382
+ const publicationLinkEl = document2.querySelector(
2341
2383
  'link[href][rel="publication"]'
2342
2384
  );
2343
2385
  if (publicationLinkEl) {
2344
2386
  const href = publicationLinkEl.getAttribute("href").trim();
2345
2387
  if (href.startsWith("#")) {
2346
- const scriptEl = document.getElementById(href.slice(1));
2388
+ const scriptEl = document2.getElementById(href.slice(1));
2347
2389
  if (scriptEl?.getAttribute("type") === "application/ld+json") {
2348
2390
  scriptEl.parentNode?.removeChild(scriptEl);
2349
2391
  }
@@ -2484,7 +2526,7 @@ async function compressEpub({
2484
2526
  sourceDir
2485
2527
  }) {
2486
2528
  Logger.debug(`Compressing EPUB: ${target}`);
2487
- const output = fs6.createWriteStream(target);
2529
+ const output = fs5.createWriteStream(target);
2488
2530
  const archive = archiver("zip", {
2489
2531
  zlib: { level: 9 }
2490
2532
  // Compression level
@@ -2522,11 +2564,11 @@ function sortManifestResources(manifest) {
2522
2564
  async function prepareWebPublicationDirectory({
2523
2565
  outputDir
2524
2566
  }) {
2525
- if (fs7.existsSync(outputDir)) {
2567
+ if (fs6.existsSync(outputDir)) {
2526
2568
  Logger.debug("going to remove existing webpub", outputDir);
2527
- await fs7.promises.rm(outputDir, { force: true, recursive: true });
2569
+ await fs6.promises.rm(outputDir, { force: true, recursive: true });
2528
2570
  }
2529
- fs7.mkdirSync(outputDir, { recursive: true });
2571
+ fs6.mkdirSync(outputDir, { recursive: true });
2530
2572
  }
2531
2573
  function transformPublicationManifest(entity, transformer) {
2532
2574
  const { url: transformUrl } = transformer;
@@ -2623,8 +2665,8 @@ function writePublicationManifest(output, options) {
2623
2665
  typeof thrownError === "string" ? thrownError : thrownError.stack ?? thrownError.message
2624
2666
  );
2625
2667
  }
2626
- fs7.mkdirSync(upath6.dirname(output), { recursive: true });
2627
- fs7.writeFileSync(output, JSON.stringify(encodedManifest, null, 2));
2668
+ fs6.mkdirSync(upath6.dirname(output), { recursive: true });
2669
+ fs6.writeFileSync(output, JSON.stringify(encodedManifest, null, 2));
2628
2670
  return publication;
2629
2671
  }
2630
2672
  async function retrieveWebbookEntry({
@@ -2735,12 +2777,12 @@ async function supplyWebPublicationManifestForWebbook({
2735
2777
  }) {
2736
2778
  Logger.debug(`Generating publication manifest from HTML: ${entryHtmlFile}`);
2737
2779
  const dom = await getJsdomFromUrlOrFile({ src: entryHtmlFile });
2738
- const { document } = dom.window;
2739
- const language = config.language || document.documentElement.lang || void 0;
2740
- const title = config.title || document.title || "";
2741
- const author = config.author || document.querySelector('meta[name="author"]')?.getAttribute("content") || "";
2780
+ const { document: document2 } = dom.window;
2781
+ const language = config.language || document2.documentElement.lang || void 0;
2782
+ const title = config.title || document2.title || "";
2783
+ const author = config.author || document2.querySelector('meta[name="author"]')?.getAttribute("content") || "";
2742
2784
  const entry = upath6.relative(outputDir, entryHtmlFile);
2743
- const allFiles = await glob2("**", {
2785
+ const allFiles = await glob("**", {
2744
2786
  cwd: outputDir
2745
2787
  });
2746
2788
  const manifest = writePublicationManifest(
@@ -2756,7 +2798,7 @@ async function supplyWebPublicationManifestForWebbook({
2756
2798
  }
2757
2799
  );
2758
2800
  sortManifestResources(manifest);
2759
- const link = document.createElement("link");
2801
+ const link = document2.createElement("link");
2760
2802
  link.setAttribute("rel", "publication");
2761
2803
  link.setAttribute("type", "application/ld+json");
2762
2804
  link.setAttribute(
@@ -2766,8 +2808,8 @@ async function supplyWebPublicationManifestForWebbook({
2766
2808
  upath6.join(outputDir, MANIFEST_FILENAME)
2767
2809
  )
2768
2810
  );
2769
- document.head.appendChild(link);
2770
- await fs7.promises.writeFile(entryHtmlFile, dom.serialize(), "utf8");
2811
+ document2.head.appendChild(link);
2812
+ await fs6.promises.writeFile(entryHtmlFile, dom.serialize(), "utf8");
2771
2813
  Logger.debug(
2772
2814
  "Generated publication manifest from HTML",
2773
2815
  JSON.stringify(manifest, null, 2)
@@ -2834,15 +2876,15 @@ async function copyWebPublicationAssets({
2834
2876
  const relTarget = alias?.target || file;
2835
2877
  resources.push(relTarget);
2836
2878
  const target = upath6.join(outputDir, relTarget);
2837
- fs7.mkdirSync(upath6.dirname(target), { recursive: true });
2838
- await copy3(upath6.join(input, file), target);
2879
+ fs6.mkdirSync(upath6.dirname(target), { recursive: true });
2880
+ await copy2(upath6.join(input, file), target);
2839
2881
  if (alias && pathEquals(upath6.join(input, alias.source), manifestPath)) {
2840
2882
  actualManifestPath = target;
2841
2883
  }
2842
2884
  }
2843
2885
  Logger.debug("webbook publication.json", actualManifestPath);
2844
2886
  const manifest = decodePublicationManifest(
2845
- JSON.parse(fs7.readFileSync(actualManifestPath, "utf8"))
2887
+ JSON.parse(fs6.readFileSync(actualManifestPath, "utf8"))
2846
2888
  );
2847
2889
  for (const entry of relExportAliases) {
2848
2890
  const rewriteAliasPath = (e) => {
@@ -2881,7 +2923,7 @@ async function copyWebPublicationAssets({
2881
2923
  })
2882
2924
  ];
2883
2925
  sortManifestResources(manifest);
2884
- fs7.writeFileSync(
2926
+ fs6.writeFileSync(
2885
2927
  actualManifestPath,
2886
2928
  JSON.stringify(encodePublicationManifest(manifest), null, 2)
2887
2929
  );
@@ -2948,17 +2990,18 @@ async function buildWebPublication({
2948
2990
 
2949
2991
  // src/processor/theme.ts
2950
2992
  import Arborist from "@npmcli/arborist";
2951
- import fs8 from "node:fs";
2993
+ import fs7 from "node:fs";
2952
2994
  async function checkThemeInstallationNecessity({
2953
2995
  themesDir,
2954
2996
  themeIndexes
2955
2997
  }) {
2956
- if (!fs8.existsSync(themesDir)) {
2998
+ if (!fs7.existsSync(themesDir)) {
2957
2999
  return [...themeIndexes].some((theme) => theme.type === "package");
2958
3000
  }
2959
3001
  const commonOpt = {
2960
3002
  path: themesDir,
2961
- lockfileVersion: 3
3003
+ lockfileVersion: 3,
3004
+ installLinks: true
2962
3005
  };
2963
3006
  const arb = new Arborist(commonOpt);
2964
3007
  const tree = await arb.loadActual();
@@ -2971,11 +3014,12 @@ async function installThemeDependencies({
2971
3014
  themesDir,
2972
3015
  themeIndexes
2973
3016
  }) {
2974
- fs8.mkdirSync(themesDir, { recursive: true });
3017
+ fs7.mkdirSync(themesDir, { recursive: true });
2975
3018
  try {
2976
3019
  const commonOpt = {
2977
3020
  path: themesDir,
2978
- lockfileVersion: 3
3021
+ lockfileVersion: 3,
3022
+ installLinks: true
2979
3023
  };
2980
3024
  const tree = await new Arborist(commonOpt).buildIdealTree();
2981
3025
  const existing = Array.from(tree.children.keys());
@@ -3011,7 +3055,7 @@ function locateThemePath(theme, from) {
3011
3055
  if (theme.importPath) {
3012
3056
  return [theme.importPath].flat().map((locator) => {
3013
3057
  const resolvedPath = upath7.resolve(theme.location, locator);
3014
- if (!pathContains(theme.location, resolvedPath) || !fs9.existsSync(resolvedPath)) {
3058
+ if (!pathContains(theme.location, resolvedPath) || !fs8.existsSync(resolvedPath)) {
3015
3059
  throw new Error(
3016
3060
  `Could not find a style path ${theme.importPath} for the theme: ${theme.name}.`
3017
3061
  );
@@ -3020,7 +3064,7 @@ function locateThemePath(theme, from) {
3020
3064
  });
3021
3065
  } else {
3022
3066
  const pkgJsonPath = upath7.join(theme.location, "package.json");
3023
- const packageJson = JSON.parse(fs9.readFileSync(pkgJsonPath, "utf8"));
3067
+ const packageJson = JSON.parse(fs8.readFileSync(pkgJsonPath, "utf8"));
3024
3068
  const maybeStyle = packageJson?.vivliostyle?.theme?.style ?? packageJson.style ?? packageJson.main;
3025
3069
  if (!maybeStyle) {
3026
3070
  throw new DetailError(
@@ -3044,7 +3088,7 @@ async function cleanupWorkspace({
3044
3088
  }
3045
3089
  Logger.debug("cleanup workspace files", workspaceDir);
3046
3090
  let movedWorkspacePath;
3047
- if (pathContains(workspaceDir, themesDir) && fs9.existsSync(themesDir)) {
3091
+ if (pathContains(workspaceDir, themesDir) && fs8.existsSync(themesDir)) {
3048
3092
  movedWorkspacePath = upath7.join(
3049
3093
  upath7.dirname(workspaceDir),
3050
3094
  `.vs-${Date.now()}`
@@ -3053,18 +3097,18 @@ async function cleanupWorkspace({
3053
3097
  movedWorkspacePath,
3054
3098
  upath7.relative(workspaceDir, themesDir)
3055
3099
  );
3056
- fs9.mkdirSync(upath7.dirname(movedThemePath), { recursive: true });
3100
+ fs8.mkdirSync(upath7.dirname(movedThemePath), { recursive: true });
3057
3101
  registerExitHandler(
3058
3102
  `Removing the moved workspace directory: ${movedWorkspacePath}`,
3059
3103
  () => {
3060
- if (movedWorkspacePath && fs9.existsSync(movedWorkspacePath)) {
3061
- fs9.rmSync(movedWorkspacePath, { recursive: true, force: true });
3104
+ if (movedWorkspacePath && fs8.existsSync(movedWorkspacePath)) {
3105
+ fs8.rmSync(movedWorkspacePath, { recursive: true, force: true });
3062
3106
  }
3063
3107
  }
3064
3108
  );
3065
3109
  await move(themesDir, movedThemePath);
3066
3110
  }
3067
- await fs9.promises.rm(workspaceDir, { recursive: true, force: true });
3111
+ await fs8.promises.rm(workspaceDir, { recursive: true, force: true });
3068
3112
  if (movedWorkspacePath) {
3069
3113
  await move(movedWorkspacePath, workspaceDir);
3070
3114
  }
@@ -3073,8 +3117,8 @@ async function prepareThemeDirectory({
3073
3117
  themesDir,
3074
3118
  themeIndexes
3075
3119
  }) {
3076
- if (fs9.existsSync(upath7.join(themesDir, "packages")) && !fs9.existsSync(upath7.join(themesDir, "node_modules"))) {
3077
- fs9.renameSync(
3120
+ if (fs8.existsSync(upath7.join(themesDir, "packages")) && !fs8.existsSync(upath7.join(themesDir, "node_modules"))) {
3121
+ fs8.renameSync(
3078
3122
  upath7.join(themesDir, "packages"),
3079
3123
  upath7.join(themesDir, "node_modules")
3080
3124
  );
@@ -3085,8 +3129,8 @@ async function prepareThemeDirectory({
3085
3129
  }
3086
3130
  for (const theme of themeIndexes) {
3087
3131
  if (theme.type === "file" && !pathEquals(theme.source, theme.location)) {
3088
- fs9.mkdirSync(upath7.dirname(theme.location), { recursive: true });
3089
- await copy4(theme.source, theme.location);
3132
+ fs8.mkdirSync(upath7.dirname(theme.location), { recursive: true });
3133
+ await copy3(theme.source, theme.location);
3090
3134
  }
3091
3135
  }
3092
3136
  }
@@ -3097,7 +3141,6 @@ async function transformManuscript(entry, {
3097
3141
  title,
3098
3142
  entries,
3099
3143
  language,
3100
- documentProcessorFactory,
3101
3144
  vfmOptions,
3102
3145
  rootUrl
3103
3146
  }) {
@@ -3109,9 +3152,10 @@ async function transformManuscript(entry, {
3109
3152
  (theme) => locateThemePath(theme, upath7.dirname(entry.target))
3110
3153
  );
3111
3154
  if (source?.type === "file") {
3112
- if (source.contentType === "text/markdown") {
3155
+ if (source.documentProcessor) {
3113
3156
  const vfile2 = await processMarkdown(
3114
- documentProcessorFactory,
3157
+ source.documentProcessor.processorFactory,
3158
+ source.documentProcessor.metadataReader,
3115
3159
  source.pathname,
3116
3160
  {
3117
3161
  ...vfmOptions,
@@ -3131,7 +3175,7 @@ async function transformManuscript(entry, {
3131
3175
  });
3132
3176
  } else {
3133
3177
  if (!pathEquals(source.pathname, entry.target)) {
3134
- await copy4(source.pathname, entry.target);
3178
+ await copy3(source.pathname, entry.target);
3135
3179
  }
3136
3180
  }
3137
3181
  } else if (source?.type === "uri") {
@@ -3265,7 +3309,7 @@ async function generateManifest({
3265
3309
  const manifestEntries = entries.map((entry) => ({
3266
3310
  title: entry.rel === "contents" && entry.tocTitle || entry.title,
3267
3311
  path: upath7.relative(workspaceDir, entry.target),
3268
- encodingFormat: !("contentType" in entry) || entry.contentType === "text/markdown" || entry.contentType === "text/html" ? void 0 : entry.contentType,
3312
+ encodingFormat: !("contentType" in entry) || entry.contentType === "text/markdown" || entry.contentType === "text/x-vivliostyle-custom" || entry.contentType === "text/html" ? void 0 : entry.contentType,
3269
3313
  rel: entry.rel
3270
3314
  }));
3271
3315
  writePublicationManifest(manifestPath, {
@@ -3670,6 +3714,7 @@ function vsDevServerPlugin({
3670
3714
  // src/vite/vite-plugin-static-serve.ts
3671
3715
  import sirv2 from "sirv";
3672
3716
  import upath9 from "upath";
3717
+ import "vite";
3673
3718
  function vsStaticServePlugin({
3674
3719
  config: _config,
3675
3720
  inlineConfig
@@ -3712,9 +3757,10 @@ function vsStaticServePlugin({
3712
3757
  }
3713
3758
 
3714
3759
  // src/vite/vite-plugin-viewer.ts
3715
- import fs10 from "node:fs";
3760
+ import fs9 from "node:fs";
3716
3761
  import sirv3 from "sirv";
3717
3762
  import upath10 from "upath";
3763
+ import "vite";
3718
3764
  var viewerClientId = "@vivliostyle:viewer:client";
3719
3765
  var viewerClientRequestPath = `/${viewerClientId}`;
3720
3766
  var viewerClientContent = (
@@ -3733,7 +3779,7 @@ function vsViewerPlugin(_) {
3733
3779
  const middleware = async function vivliostyleViewerMiddleware(req, res, next) {
3734
3780
  if (req.url === "/" || req.url === "/index.html") {
3735
3781
  cachedIndexHtml ??= prependToHead(
3736
- fs10.readFileSync(upath10.join(serveRootDir, "index.html"), "utf-8"),
3782
+ fs9.readFileSync(upath10.join(serveRootDir, "index.html"), "utf-8"),
3737
3783
  `<script type="module" src="${viewerClientRequestPath}"></script>`
3738
3784
  );
3739
3785
  res.statusCode = 200;
@@ -3837,7 +3883,7 @@ async function getSourceUrl({
3837
3883
  input = viewerInput.epubOpfPath;
3838
3884
  break;
3839
3885
  case "epub": {
3840
- if (!fs11.existsSync(viewerInput.epubTmpOutputDir)) {
3886
+ if (!fs10.existsSync(viewerInput.epubTmpOutputDir)) {
3841
3887
  await openEpub(viewerInput.epubPath, viewerInput.epubTmpOutputDir);
3842
3888
  }
3843
3889
  input = getDefaultEpubOpfPath(viewerInput.epubTmpOutputDir);
@@ -3899,8 +3945,8 @@ async function createViteServer({
3899
3945
  if (config.serverRootDir === config.workspaceDir) {
3900
3946
  const { cacheDir } = viteInlineConfig;
3901
3947
  registerExitHandler("Removing the Vite cacheDir", () => {
3902
- if (fs11.existsSync(cacheDir)) {
3903
- fs11.rmSync(cacheDir, { recursive: true });
3948
+ if (fs10.existsSync(cacheDir)) {
3949
+ fs10.rmSync(cacheDir, { recursive: true });
3904
3950
  }
3905
3951
  });
3906
3952
  }
@@ -3924,21 +3970,28 @@ function vsBrowserPlugin({
3924
3970
  runExitHandlers();
3925
3971
  }
3926
3972
  async function openPreviewPage() {
3973
+ const locale = await getOsLocale();
3927
3974
  const url = await getViewerFullUrl(config);
3928
3975
  const { page, browser } = await launchPreview({
3929
3976
  mode: "preview",
3930
3977
  url,
3931
3978
  config,
3979
+ /* v8 ignore next 4 */
3932
3980
  onPageOpen: async (page2) => {
3933
3981
  page2.on("close", handlePageClose);
3934
- const locale = Intl.DateTimeFormat().resolvedOptions().locale;
3935
- await page2.addInitScript(
3936
- `window.localStorage.setItem('i18nextLng', '${locale}');`
3937
- );
3938
3982
  }
3939
3983
  });
3984
+ if (!import.meta.env?.VITEST) {
3985
+ await page.evaluate((locale2) => {
3986
+ window.localStorage.setItem("i18nextLng", locale2);
3987
+ }, locale);
3988
+ }
3940
3989
  await page.bringToFront();
3941
- await page.locator("#vivliostyle-input-url").focus({ timeout: 0 });
3990
+ if (!import.meta.env?.VITEST) {
3991
+ await page.evaluate(() => {
3992
+ document.querySelector("#vivliostyle-input-url")?.focus();
3993
+ });
3994
+ }
3942
3995
  closeBrowser = () => {
3943
3996
  page.off("close", handlePageClose);
3944
3997
  browser.close();
@@ -3970,10 +4023,8 @@ export {
3970
4023
  mergeInlineConfig,
3971
4024
  isWebPubConfig,
3972
4025
  resolveTaskConfig,
3973
- getFullBrowserName,
3974
4026
  launchPreview,
3975
4027
  vsBrowserPlugin,
3976
- copyAssets,
3977
4028
  buildWebPublication,
3978
4029
  cleanupWorkspace,
3979
4030
  prepareThemeDirectory,
@@ -3985,4 +4036,4 @@ export {
3985
4036
  getViewerFullUrl,
3986
4037
  createViteServer
3987
4038
  };
3988
- //# sourceMappingURL=chunk-PPI5DA75.js.map
4039
+ //# sourceMappingURL=chunk-YN3JNBNT.js.map