vite-ssg-optimized 0.24.2-optimized.5 → 0.24.2-optimized.50

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 (32) hide show
  1. package/README.md +32 -1
  2. package/dist/client/single-page.cjs +1 -1
  3. package/dist/client/single-page.d.cts +2 -2
  4. package/dist/client/single-page.d.mts +2 -2
  5. package/dist/client/single-page.d.ts +2 -2
  6. package/dist/client/single-page.mjs +2 -2
  7. package/dist/index.cjs +20 -3
  8. package/dist/index.d.cts +2 -2
  9. package/dist/index.d.mts +2 -2
  10. package/dist/index.d.ts +2 -2
  11. package/dist/index.mjs +22 -5
  12. package/dist/node/cli.cjs +1 -1
  13. package/dist/node/cli.mjs +1 -1
  14. package/dist/node.cjs +1 -1
  15. package/dist/node.d.cts +8 -3
  16. package/dist/node.d.mts +8 -3
  17. package/dist/node.d.ts +8 -3
  18. package/dist/node.mjs +1 -1
  19. package/dist/shared/build.worker.cjs +99 -18
  20. package/dist/shared/build.worker.d.cts +4 -14
  21. package/dist/shared/build.worker.d.mts +4 -14
  22. package/dist/shared/build.worker.d.ts +4 -14
  23. package/dist/shared/build.worker.mjs +100 -19
  24. package/dist/shared/{vite-ssg-optimized.cf5cb4ee.d.cts → vite-ssg-optimized.341e382e.d.cts} +6 -1
  25. package/dist/shared/{vite-ssg-optimized.cf5cb4ee.d.mts → vite-ssg-optimized.341e382e.d.mts} +6 -1
  26. package/dist/shared/{vite-ssg-optimized.cf5cb4ee.d.ts → vite-ssg-optimized.341e382e.d.ts} +6 -1
  27. package/dist/shared/{vite-ssg-optimized.62fed880.mjs → vite-ssg-optimized.65f46348.mjs} +198 -87
  28. package/dist/shared/{vite-ssg-optimized.46e3caf6.cjs → vite-ssg-optimized.e58a8d97.cjs} +200 -87
  29. package/package.json +1 -1
  30. package/dist/shared/vite-ssg-optimized.12fd9d22.d.cts +0 -9
  31. package/dist/shared/vite-ssg-optimized.892682c8.d.mts +0 -9
  32. package/dist/shared/vite-ssg-optimized.950926bc.d.ts +0 -9
@@ -1,7 +1,7 @@
1
1
  import { createRequire } from 'node:module';
2
2
  import { parentPort, workerData } from 'node:worker_threads';
3
- import { g as getBeastiesOrCritters, e as executeTaskFn } from './vite-ssg-optimized.62fed880.mjs';
4
- import { gray, blue } from 'kolorist';
3
+ import { p as plainify, e as executeTaskFn, a as buildClient, c as buildServer } from './vite-ssg-optimized.65f46348.mjs';
4
+ import { red, gray, blue } from 'kolorist';
5
5
  import { resolveConfig } from 'vite';
6
6
  import 'node:path';
7
7
  import 'node:process';
@@ -10,9 +10,39 @@ import 'fs-extra';
10
10
  import './vite-ssg-optimized.579feabb.mjs';
11
11
  import 'html5parser';
12
12
 
13
+ async function getBeastiesOrCritters(outDir, options = {}) {
14
+ try {
15
+ const BeastiesClass = (await import('beasties')).default;
16
+ return new BeastiesClass({
17
+ path: outDir,
18
+ logLevel: "warn",
19
+ external: true,
20
+ inlineFonts: true,
21
+ preloadFonts: true,
22
+ ...options
23
+ });
24
+ } catch {
25
+ }
26
+ try {
27
+ const CrittersClass = (await import('critters')).default;
28
+ console.warn("`critters` is deprecated. Please use `beasties` instead.");
29
+ return new CrittersClass({
30
+ path: outDir,
31
+ logLevel: "warn",
32
+ external: true,
33
+ inlineFonts: true,
34
+ preloadFonts: true,
35
+ ...options
36
+ });
37
+ } catch {
38
+ return void 0;
39
+ }
40
+ }
41
+
13
42
  (async () => {
14
- const fnLog = (level = "info", msg) => {
15
- parentPort.postMessage({ type: "log", args: [msg], level });
43
+ const fnLog = (level = "info", ...msg) => {
44
+ const newMsg = msg.map(plainify);
45
+ parentPort.postMessage({ type: "log", args: newMsg, level });
16
46
  };
17
47
  globalThis.console = Object.assign(globalThis.console, {
18
48
  info: fnLog.bind(globalThis.console, "info"),
@@ -22,23 +52,53 @@ import 'html5parser';
22
52
  trace: fnLog.bind(globalThis.console, "trace"),
23
53
  debug: fnLog.bind(globalThis.console, "debug")
24
54
  });
25
- const { serverEntry, out, beastiesOptions, viteConfig, mode, format, dirStyle, ...extraOpts } = workerData;
55
+ const noop = () => void 0;
56
+ const proccessInjections = {
57
+ clearLine: noop,
58
+ cursorTo: noop,
59
+ clearScreenDown: noop,
60
+ moveCursor: noop,
61
+ isTTY: false
62
+ };
63
+ Object.assign(process.stdout, proccessInjections);
64
+ Object.assign(process.stderr, proccessInjections);
65
+ const { format, out, dirStyle, viteConfig, mode, ...extraOpts } = workerData;
26
66
  const nodeEnv = process.env.NODE_ENV || "production";
27
67
  const config = await resolveConfig(viteConfig, "build", mode, nodeEnv);
28
68
  const {
29
69
  onPageRendered,
30
70
  onBeforePageRender,
31
- onDonePageRender
71
+ // onDonePageRender,
72
+ onFinished
32
73
  } = config.ssgOptions || {};
33
74
  const { renderToString } = await import('vue/server-renderer');
34
75
  const outDir = out.replace(process.cwd(), "").replace(/^\//g, "");
35
76
  const _require = createRequire(import.meta.url);
36
- const beasties = beastiesOptions !== false ? await getBeastiesOrCritters(outDir, beastiesOptions) : void 0;
37
- if (beasties)
38
- console.log(`${gray("[vite-ssg]")} ${blue("Critical CSS generation enabled via `beasties`")}`);
39
- const { createApp } = format === "esm" ? await import(serverEntry) : _require(serverEntry);
77
+ let createAppPromise = void 0;
78
+ let beastiesPromise = void 0;
79
+ function cancelablePromise(promise) {
80
+ let cancel = () => void 0;
81
+ const newPromise = new Promise((resolve, reject) => {
82
+ cancel = () => void reject(new Error("Cancelled"));
83
+ promise.then((result) => {
84
+ resolve(result);
85
+ });
86
+ });
87
+ return Object.assign(newPromise, { cancel });
88
+ }
40
89
  const execMap = {
41
90
  executeTaskFn: async (opts) => {
91
+ const { serverEntry } = opts;
92
+ createAppPromise ?? (createAppPromise = Promise.resolve(format === "esm" ? import(serverEntry) : _require(serverEntry)).then(({ createApp: createApp2 }) => createApp2));
93
+ const createApp = await createAppPromise;
94
+ const beastiesOptions = opts.beastiesOptions;
95
+ beastiesPromise ?? (beastiesPromise = Promise.resolve(beastiesOptions !== false ? getBeastiesOrCritters(outDir, beastiesOptions) : void 0).then((beasties2) => {
96
+ if (!beasties2)
97
+ return;
98
+ console.log(`${gray("[vite-ssg]")} ${blue("Critical CSS generation enabled via `beasties`")}`);
99
+ return beasties2;
100
+ }));
101
+ const beasties = await beastiesPromise;
42
102
  const newOpts = {
43
103
  ...extraOpts,
44
104
  out,
@@ -47,14 +107,34 @@ import 'html5parser';
47
107
  renderToString,
48
108
  onPageRendered,
49
109
  onBeforePageRender,
50
- onDonePageRender,
110
+ // onDonePageRender: onDonePageRender,
51
111
  beasties,
52
112
  config: { logger: { info: (msg) => {
53
113
  parentPort.postMessage({ type: "log", args: [msg] });
54
114
  } } },
55
115
  ...opts
56
116
  };
57
- return executeTaskFn(newOpts);
117
+ const resultPromise = cancelablePromise(executeTaskFn(newOpts));
118
+ const cancel = async () => {
119
+ resultPromise.cancel();
120
+ };
121
+ process.once("beforeExit", cancel);
122
+ process.once("SIGINT", cancel);
123
+ process.once("SIGTERM", cancel);
124
+ return resultPromise;
125
+ },
126
+ onFinished,
127
+ buildClient: async (...args) => {
128
+ let [_config, _viteConfig] = args;
129
+ _config = Object.assign({}, config, _config);
130
+ _viteConfig = Object.assign({}, viteConfig, _viteConfig);
131
+ return await buildClient(_config, _viteConfig);
132
+ },
133
+ buildServer: async (...args) => {
134
+ let [_config, _viteConfig, _opts] = args;
135
+ _config = Object.assign({}, config, _config);
136
+ _viteConfig = Object.assign({}, viteConfig, _viteConfig);
137
+ return await buildServer(_config, _viteConfig, _opts);
58
138
  }
59
139
  };
60
140
  parentPort?.on("message", async (message) => {
@@ -62,15 +142,16 @@ import 'html5parser';
62
142
  if (type in execMap) {
63
143
  parentPort.postMessage(`running ${type}`);
64
144
  try {
65
- const result = await execMap[type](...args ?? []);
66
- if (result.appCtx) {
67
- Object.assign(result, {
68
- appCtx: result.appCtx.router.push(result.route)
69
- });
70
- }
145
+ let result = await execMap[type](...args ?? []);
146
+ result = plainify(result);
71
147
  parentPort.postMessage({ type: "result", id, result });
72
148
  } catch (e) {
73
- parentPort.postMessage({ type: "error", id, error: e.toString() });
149
+ const message2 = e.message || e.toString();
150
+ const stack = e.stack || "";
151
+ const error = { message: message2, stack };
152
+ process.stderr.write(`${red("[vite-ssg-worker]")} ${message2} ${stack}
153
+ `);
154
+ parentPort.postMessage({ type: "error", id, error });
74
155
  }
75
156
  }
76
157
  });
@@ -113,8 +113,13 @@ interface ViteSSGOptions {
113
113
  * It's useful to debug memory leaks
114
114
  *
115
115
  */
116
- onDonePageRender?: (route: string, renderedHTML: string, appCtx: ViteSSGContext<true>) => Promise<void> | void;
117
116
  onFinished?: () => Promise<void> | void;
117
+ /**
118
+ * The number of workers to use.
119
+ *
120
+ * @default 5
121
+ */
122
+ numberOfWorkers?: number;
118
123
  /**
119
124
  * The application's root container `id`.
120
125
  *
@@ -113,8 +113,13 @@ interface ViteSSGOptions {
113
113
  * It's useful to debug memory leaks
114
114
  *
115
115
  */
116
- onDonePageRender?: (route: string, renderedHTML: string, appCtx: ViteSSGContext<true>) => Promise<void> | void;
117
116
  onFinished?: () => Promise<void> | void;
117
+ /**
118
+ * The number of workers to use.
119
+ *
120
+ * @default 5
121
+ */
122
+ numberOfWorkers?: number;
118
123
  /**
119
124
  * The application's root container `id`.
120
125
  *
@@ -113,8 +113,13 @@ interface ViteSSGOptions {
113
113
  * It's useful to debug memory leaks
114
114
  *
115
115
  */
116
- onDonePageRender?: (route: string, renderedHTML: string, appCtx: ViteSSGContext<true>) => Promise<void> | void;
117
116
  onFinished?: () => Promise<void> | void;
117
+ /**
118
+ * The number of workers to use.
119
+ *
120
+ * @default 5
121
+ */
122
+ numberOfWorkers?: number;
118
123
  /**
119
124
  * The application's root container `id`.
120
125
  *
@@ -3,7 +3,7 @@ import { isAbsolute, join, parse, dirname } from 'node:path';
3
3
  import process$1 from 'node:process';
4
4
  import { renderSSRHead } from '@unhead/ssr';
5
5
  import fs from 'fs-extra';
6
- import { gray, yellow, blue, green, dim, cyan, red } from 'kolorist';
6
+ import { gray, yellow, blue, reset, green, cyan, dim, red } from 'kolorist';
7
7
  import { resolveConfig, build as build$1, mergeConfig } from 'vite';
8
8
  import { s as serializeState } from './vite-ssg-optimized.579feabb.mjs';
9
9
  import html5Parser, { SyntaxKind } from 'html5parser';
@@ -830,35 +830,6 @@ class PQueue extends EventEmitter {
830
830
  }
831
831
  }
832
832
 
833
- async function getBeastiesOrCritters(outDir, options = {}) {
834
- try {
835
- const BeastiesClass = (await import('beasties')).default;
836
- return new BeastiesClass({
837
- path: outDir,
838
- logLevel: "warn",
839
- external: true,
840
- inlineFonts: true,
841
- preloadFonts: true,
842
- ...options
843
- });
844
- } catch {
845
- }
846
- try {
847
- const CrittersClass = (await import('critters')).default;
848
- console.warn("`critters` is deprecated. Please use `beasties` instead.");
849
- return new CrittersClass({
850
- path: outDir,
851
- logLevel: "warn",
852
- external: true,
853
- inlineFonts: true,
854
- preloadFonts: true,
855
- ...options
856
- });
857
- } catch {
858
- return void 0;
859
- }
860
- }
861
-
862
833
  function isMatchOption(node, opts) {
863
834
  if (opts.match.tag && !(node.name === opts.match.tag)) {
864
835
  return false;
@@ -1044,15 +1015,16 @@ class BuildWorkerProxy {
1044
1015
  constructor(path, options) {
1045
1016
  __publicField(this, "worker");
1046
1017
  __publicField(this, "pending", /* @__PURE__ */ new Map());
1018
+ __publicField(this, "_id");
1047
1019
  this.worker = new Worker(path, options);
1020
+ this._id = options.workerData.workerId;
1048
1021
  this.worker.on("message", (message) => {
1049
1022
  const { type, level = "info", args = [] } = message;
1050
1023
  if (type !== "log")
1051
1024
  return;
1052
1025
  const fn = console[level]?.bind(console);
1053
- let msg = args.map((arg) => typeof arg === "object" && !!arg ? "[object]" : arg).join(" ");
1054
1026
  const workerId = options.workerData.workerId;
1055
- fn?.(`[woker #${workerId}] ${msg}`);
1027
+ fn?.(`[woker #${workerId}] `, ...args, reset(""));
1056
1028
  });
1057
1029
  this.worker.on("message", (message) => {
1058
1030
  const { id, type, result = void 0, error = void 0 } = message;
@@ -1067,12 +1039,18 @@ class BuildWorkerProxy {
1067
1039
  }
1068
1040
  });
1069
1041
  }
1042
+ get id() {
1043
+ return this._id;
1044
+ }
1070
1045
  on(type, listener) {
1071
1046
  this.worker.on(type, listener);
1072
1047
  }
1073
1048
  off(type, listener) {
1074
1049
  this.worker.off(type, listener);
1075
1050
  }
1051
+ once(type, listener) {
1052
+ this.worker.once(type, listener);
1053
+ }
1076
1054
  async send(type, args) {
1077
1055
  const id = crypto.randomUUID();
1078
1056
  const promise = new Promise((resolve, reject) => {
@@ -1085,7 +1063,9 @@ class BuildWorkerProxy {
1085
1063
  return promise;
1086
1064
  }
1087
1065
  terminate() {
1088
- this.worker.terminate();
1066
+ return this.worker.terminate().finally(() => {
1067
+ this.pending.clear();
1068
+ });
1089
1069
  }
1090
1070
  }
1091
1071
 
@@ -1113,10 +1093,14 @@ async function buildClient(config, viteConfig) {
1113
1093
  mode: config.mode
1114
1094
  }));
1115
1095
  }
1116
- async function buildServer(config, viteConfig, { ssrEntry, ssgOut, format }) {
1096
+ async function buildServer(config, viteConfig, { ssrEntry, ssgOut, format, mock }) {
1117
1097
  buildLog("Build for server...");
1118
1098
  process$1.env.VITE_SSG = "true";
1119
1099
  const { base } = config;
1100
+ if (mock) {
1101
+ const { jsdomGlobal } = await import('../chunks/jsdomGlobal.mjs');
1102
+ jsdomGlobal();
1103
+ }
1120
1104
  await build$1(mergeConfig(viteConfig, {
1121
1105
  base,
1122
1106
  build: {
@@ -1137,6 +1121,19 @@ async function buildServer(config, viteConfig, { ssrEntry, ssgOut, format }) {
1137
1121
  mode: config.mode
1138
1122
  }));
1139
1123
  }
1124
+ function createProxy(options) {
1125
+ const workerExt = options.format === "esm" ? ".mjs" : ".cjs";
1126
+ const workerProxy = new BuildWorkerProxy(new URL(`./build.worker${workerExt}`, import.meta.url), {
1127
+ env: process$1.env,
1128
+ workerData: options
1129
+ });
1130
+ process$1.once("SIGINT", workerProxy.terminate.bind(workerProxy));
1131
+ process$1.once("SIGTERM", workerProxy.terminate.bind(workerProxy));
1132
+ process$1.once("SIGBREAK", workerProxy.terminate.bind(workerProxy));
1133
+ process$1.once("beforeExit", workerProxy.terminate.bind(workerProxy));
1134
+ process$1.once("exit", workerProxy.terminate.bind(workerProxy));
1135
+ return workerProxy;
1136
+ }
1140
1137
  async function build(ssgOptions = {}, viteConfig = {}) {
1141
1138
  const nodeEnv = process$1.env.NODE_ENV || "production";
1142
1139
  const mode = process$1.env.MODE || ssgOptions.mode || nodeEnv;
@@ -1151,12 +1148,13 @@ async function build(ssgOptions = {}, viteConfig = {}) {
1151
1148
  ssgOut: _ssgOutDir = join(root, ".vite-ssg-temp", Math.random().toString(36).substring(2, 12)),
1152
1149
  formatting = "none",
1153
1150
  minifyOptions = {},
1154
- crittersOptions = {},
1151
+ // crittersOptions = {},
1155
1152
  beastiesOptions = {},
1156
1153
  includedRoutes: configIncludedRoutes = DefaultIncludedRoutes,
1157
- onBeforePageRender,
1158
- onPageRendered,
1159
- onDonePageRender,
1154
+ // onBeforePageRender,
1155
+ // onPageRendered,
1156
+ // onDonePageRender,
1157
+ numberOfWorkers: _numberOfWorkers = 5,
1160
1158
  onFinished,
1161
1159
  dirStyle = "flat",
1162
1160
  includeAllRoutes = false,
@@ -1165,6 +1163,14 @@ async function build(ssgOptions = {}, viteConfig = {}) {
1165
1163
  rootContainerId = "app"
1166
1164
  } = Object.assign({}, config.ssgOptions || {}, ssgOptions);
1167
1165
  const ssgOut = isAbsolute(_ssgOutDir) ? _ssgOutDir : join(root, _ssgOutDir);
1166
+ const createProxyOptions = {
1167
+ format,
1168
+ out,
1169
+ dirStyle,
1170
+ viteConfig: {
1171
+ configFile: config.configFile
1172
+ }
1173
+ };
1168
1174
  let willRunBuild = true;
1169
1175
  if (fs.existsSync(ssgOut)) {
1170
1176
  willRunBuild = !ssgOptions["skip-build"];
@@ -1172,17 +1178,79 @@ async function build(ssgOptions = {}, viteConfig = {}) {
1172
1178
  await fs.remove(ssgOut);
1173
1179
  }
1174
1180
  }
1175
- if (willRunBuild)
1176
- await buildClient(config, viteConfig);
1177
- if (mock) {
1178
- const { jsdomGlobal } = await import('../chunks/jsdomGlobal.mjs');
1179
- jsdomGlobal();
1181
+ const buildPromises = [];
1182
+ if (willRunBuild) {
1183
+ const clientWorker = createProxy({
1184
+ ...createProxyOptions,
1185
+ workerId: "client"
1186
+ });
1187
+ clientWorker.on("unhandledRejection", (error) => {
1188
+ console.error(error);
1189
+ clientWorker.terminate();
1190
+ });
1191
+ const cpBuildClient = execInWorker(clientWorker, buildClient, config, viteConfig).finally(() => clientWorker.terminate());
1192
+ buildPromises.push(cpBuildClient);
1180
1193
  }
1181
1194
  const ssrEntry = await resolveAlias(config, entry);
1182
- if (willRunBuild)
1183
- await buildServer(config, viteConfig, { ssrEntry, ssgOut, format });
1195
+ if (willRunBuild) {
1196
+ const serverWorker = createProxy({
1197
+ ...createProxyOptions,
1198
+ workerId: "server"
1199
+ });
1200
+ const cpBuildServer = execInWorker(serverWorker, buildServer, config, viteConfig, { ssrEntry, ssgOut, format, mock }).finally(() => serverWorker.terminate());
1201
+ buildPromises.push(cpBuildServer);
1202
+ }
1203
+ await Promise.all(buildPromises);
1184
1204
  const prefix = format === "esm" && process$1.platform === "win32" ? "file://" : "";
1185
1205
  const ext = format === "esm" ? ".mjs" : ".cjs";
1206
+ const numberOfWorkers = Math.max(1, _numberOfWorkers);
1207
+ console.log(`${gray("[vite-ssg]")} ${blue(`Using ${numberOfWorkers} workers`)}`);
1208
+ const workers = Array.from({ length: numberOfWorkers }, (_, index) => createProxy({
1209
+ ...createProxyOptions,
1210
+ workerId: index
1211
+ }));
1212
+ const workersInUse = /* @__PURE__ */ new Map();
1213
+ const terminateWorker = async (worker, onFinished2) => {
1214
+ if (onFinished2) {
1215
+ await execInWorker(worker, onFinished2);
1216
+ }
1217
+ const foundIndex = workers.indexOf(worker);
1218
+ if (foundIndex > -1) {
1219
+ workers.splice(foundIndex, 1);
1220
+ }
1221
+ await worker.terminate().finally(() => {
1222
+ workersInUse.delete(worker);
1223
+ });
1224
+ };
1225
+ const terminateWorkers = async (onFinished2) => {
1226
+ await Promise.all(workers.map((worker) => terminateWorker(worker, onFinished2)));
1227
+ };
1228
+ let workerIndex = 0;
1229
+ const maxTasksPerWorker = Math.ceil(concurrency / numberOfWorkers);
1230
+ const workerTasksRunning = (w) => workersInUse.get(w)?.length || 0;
1231
+ const selectIdleWorker = () => workers.filter((w) => workerTasksRunning(w) < maxTasksPerWorker).sort((a, b) => workerTasksRunning(a) - workerTasksRunning(b))[0];
1232
+ const selectWorker = async (workerIndex2) => {
1233
+ const index = workerIndex2 ?? Math.round(Math.random() * numberOfWorkers);
1234
+ const maybeWorker = workers[index % numberOfWorkers];
1235
+ const worker = maybeWorker && workerTasksRunning(maybeWorker) < maxTasksPerWorker ? maybeWorker : selectIdleWorker();
1236
+ if (!worker) {
1237
+ await Promise.race(Array.from(workersInUse.values()).flat());
1238
+ return selectWorker(workerIndex2);
1239
+ }
1240
+ const workerPromises = workersInUse.get(worker) || [];
1241
+ const delayPromise = new Promise((resolve) => setImmediate(resolve));
1242
+ workerPromises.push(delayPromise);
1243
+ workersInUse.set(worker, workerPromises);
1244
+ delayPromise.finally(() => {
1245
+ const workerPromises2 = workersInUse.get(worker) || [];
1246
+ const foundIndex = workerPromises2.indexOf(delayPromise);
1247
+ if (foundIndex > -1) {
1248
+ workerPromises2.splice(foundIndex, 1);
1249
+ }
1250
+ workersInUse.set(worker, workerPromises2);
1251
+ });
1252
+ return worker;
1253
+ };
1186
1254
  const serverEntry = prefix + join(ssgOut, parse(ssrEntry).name + ext).replace(/\\/g, "/");
1187
1255
  const _require = createRequire(import.meta.url);
1188
1256
  const { createApp, includedRoutes: serverEntryIncludedRoutes } = format === "esm" ? await import(serverEntry) : _require(serverEntry);
@@ -1191,9 +1259,6 @@ async function build(ssgOptions = {}, viteConfig = {}) {
1191
1259
  let routesPaths = includeAllRoutes ? routesToPaths(routes) : await includedRoutes(routesToPaths(routes), routes || []);
1192
1260
  routesPaths = Array.from(new Set(routesPaths));
1193
1261
  buildLog("Rendering Pages...", routesPaths.length);
1194
- const beasties = beastiesOptions !== false ? await getBeastiesOrCritters(outDir, beastiesOptions) : void 0;
1195
- if (beasties)
1196
- console.log(`${gray("[vite-ssg]")} ${blue("Critical CSS generation enabled via `beasties`")}`);
1197
1262
  const {
1198
1263
  path: _ssrManifestPath,
1199
1264
  content: ssrManifestRaw
@@ -1208,46 +1273,76 @@ async function build(ssgOptions = {}, viteConfig = {}) {
1208
1273
  indexHTML = rewriteScripts(indexHTML, script);
1209
1274
  const IS_PROD = nodeEnv === "production";
1210
1275
  indexHTML = await formatHtml(indexHTML, IS_PROD ? "minify" : formatting, minifyOptions);
1276
+ const workerRunCount = /* @__PURE__ */ new WeakMap();
1277
+ const MAX_RUNS_PER_WORKER = 100;
1278
+ let lastWorkerIndex = workers.length - 1;
1279
+ function replaceWorker(workerProxy) {
1280
+ const index = workers.indexOf(workerProxy);
1281
+ if (index === -1) {
1282
+ return workerProxy;
1283
+ }
1284
+ ++lastWorkerIndex;
1285
+ config.logger.info(`${blue("[vite-ssg]")} ${yellow(`Replace worker #${workerProxy.id} => #${lastWorkerIndex}`)}`);
1286
+ const workerPromises = workersInUse.get(workerProxy) || [];
1287
+ const newWorkerProxy = createProxy({
1288
+ ...createProxyOptions,
1289
+ workerId: lastWorkerIndex
1290
+ });
1291
+ workers[index] = newWorkerProxy;
1292
+ Promise.allSettled([...workerPromises, Promise.resolve()]).then(async () => {
1293
+ await terminateWorker(workerProxy, onFinished);
1294
+ });
1295
+ return newWorkerProxy;
1296
+ }
1211
1297
  const queue = new PQueue({ concurrency });
1212
- const workerExt = format === "esm" ? ".mjs" : ".cjs";
1213
- const createProxy = (index) => {
1214
- const workerProxy = new BuildWorkerProxy(new URL(`./build.worker${workerExt}`, import.meta.url), {
1215
- env: process$1.env,
1216
- workerData: {
1217
- workerId: index,
1218
- serverEntry,
1298
+ for (const route of routesPaths) {
1299
+ await queue.onSizeLessThan(concurrency);
1300
+ queue.add(async () => {
1301
+ let workerProxy = await selectWorker(workerIndex++ % numberOfWorkers);
1302
+ const currentCount = (workerRunCount.get(workerProxy) ?? 0) + 1;
1303
+ workerRunCount.set(workerProxy, currentCount);
1304
+ if (currentCount > MAX_RUNS_PER_WORKER) {
1305
+ workerRunCount.delete(workerProxy);
1306
+ workerProxy = replaceWorker(workerProxy);
1307
+ }
1308
+ let retryCount = 0;
1309
+ const maxRetries = 3;
1310
+ const execOpts = {
1311
+ route,
1219
1312
  ssrManifest,
1220
- format,
1221
- out,
1222
- beastiesOptions,
1223
- dirStyle,
1224
1313
  indexHTML,
1225
1314
  rootContainerId,
1226
1315
  formatting,
1227
1316
  minifyOptions,
1228
- viteConfig: {
1229
- configFile: config.configFile || "vite.config.ts"
1317
+ // out,
1318
+ // dirStyle,
1319
+ beastiesOptions,
1320
+ serverEntry
1321
+ };
1322
+ const taskPromise = executeTaskInWorker(workerProxy, execOpts);
1323
+ const workerPromises = workersInUse.get(workerProxy) || [];
1324
+ workerPromises.push(taskPromise);
1325
+ workersInUse.set(workerProxy, workerPromises);
1326
+ const retryFn = async (e) => {
1327
+ if (retryCount++ < maxRetries) {
1328
+ console.log(`${gray("[vite-ssg]")} ${yellow(`Retrying ${retryCount} of ${maxRetries} for route: ${cyan(route)}`)}`);
1329
+ return await executeTaskInWorker(workerProxy, execOpts).catch(retryFn);
1230
1330
  }
1231
- }
1232
- });
1233
- return workerProxy;
1234
- };
1235
- const numberOfWorkers = 5;
1236
- const workers = Array.from({ length: numberOfWorkers }, (_, index) => createProxy(index));
1237
- let workerIndex = 0;
1238
- for (const route of routesPaths) {
1239
- await queue.onSizeLessThan(concurrency + 5);
1240
- const workerProxy = workers[workerIndex];
1241
- workerIndex = (workerIndex + 1) % numberOfWorkers;
1242
- queue.add(async () => {
1243
- const taskPromise = executeTaskInWorker(workerProxy, {
1244
- route
1331
+ throw e;
1332
+ };
1333
+ taskPromise.catch(retryFn).finally(() => {
1334
+ const workerPromises2 = workersInUse.get(workerProxy) || [];
1335
+ const foundIndex = workerPromises2.indexOf(taskPromise);
1336
+ if (foundIndex > -1) {
1337
+ workerPromises2.splice(foundIndex, 1);
1338
+ }
1339
+ workersInUse.set(workerProxy, workerPromises2);
1245
1340
  });
1246
1341
  return taskPromise;
1247
1342
  });
1248
1343
  }
1249
1344
  await queue.start().onIdle();
1250
- workers.forEach((worker) => worker.terminate());
1345
+ await terminateWorkers(onFinished);
1251
1346
  if (!ssgOptions["skip-build"]) {
1252
1347
  await fs.remove(ssgOut);
1253
1348
  }
@@ -1267,14 +1362,10 @@ ${gray("[vite-ssg]")} ${green("Build finished.")}`);
1267
1362
  timeout.unref();
1268
1363
  }
1269
1364
  function executeTaskInWorker(worker, opts) {
1270
- opts = Object.entries(opts).reduce((acc, [key, value]) => {
1271
- if (typeof value === "function")
1272
- return acc;
1273
- const newKey = key;
1274
- acc[newKey] = value;
1275
- return acc;
1276
- }, {});
1277
- return worker.send("executeTaskFn", [opts]);
1365
+ return execInWorker(worker, executeTaskFn, opts);
1366
+ }
1367
+ async function execInWorker(worker, fn, ...args) {
1368
+ return await worker.send(fn.name, plainify(args ?? []));
1278
1369
  }
1279
1370
  async function executeTaskFn(opts) {
1280
1371
  const {
@@ -1283,7 +1374,7 @@ async function executeTaskFn(opts) {
1283
1374
  renderToString,
1284
1375
  indexHTML,
1285
1376
  onBeforePageRender,
1286
- onDonePageRender,
1377
+ // onDonePageRender,
1287
1378
  onPageRendered,
1288
1379
  ssrManifest,
1289
1380
  rootContainerId,
@@ -1343,7 +1434,6 @@ async function executeTaskFn(opts) {
1343
1434
  config.logger.info(
1344
1435
  `${dim(`${outDir}/`)}${cyan(filename.padEnd(15, " "))} ${dim(getSize(formatted))}`
1345
1436
  );
1346
- onDonePageRender?.(route, html, appCtx);
1347
1437
  return { route, html };
1348
1438
  });
1349
1439
  } catch (err) {
@@ -1351,6 +1441,27 @@ async function executeTaskFn(opts) {
1351
1441
  ${err.stack}`);
1352
1442
  }
1353
1443
  }
1444
+ function plainify(m) {
1445
+ if (m instanceof Function) {
1446
+ return void 0;
1447
+ }
1448
+ if (Array.isArray(m)) {
1449
+ return m.map(plainify);
1450
+ }
1451
+ if (typeof m === "object" && m !== null) {
1452
+ if (m instanceof Error || "stack" in m) {
1453
+ return {
1454
+ message: m.message,
1455
+ stack: m.stack
1456
+ };
1457
+ }
1458
+ return Object.entries(m).reduce((acc, [key, value]) => {
1459
+ acc[key] = plainify(value);
1460
+ return acc;
1461
+ }, {});
1462
+ }
1463
+ return m;
1464
+ }
1354
1465
  async function detectEntry(root) {
1355
1466
  const scriptSrcReg = /<script.*?src=["'](.+?)["'](?!<).*>\s*<\/script>/gi;
1356
1467
  const html = await fs.readFile(join(root, "index.html"), "utf-8");
@@ -1449,4 +1560,4 @@ async function readFiles(...paths) {
1449
1560
  throw new Error(`Could not find any of the following files: ${paths.join(", ")}`);
1450
1561
  }
1451
1562
 
1452
- export { build as b, executeTaskFn as e, getBeastiesOrCritters as g };
1563
+ export { buildClient as a, build as b, buildServer as c, executeTaskFn as e, plainify as p };