@lovable.dev/vite-tanstack-config 2.15.1 → 2.17.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.
package/dist/index.cjs CHANGED
@@ -189,6 +189,76 @@ async function nitroSupportsDefaultPreset() {
189
189
  }
190
190
  }
191
191
  const LOVABLE_NITRO_PRESETS = ["cloudflare-module", "lovable-fetch-bundle"];
192
+ const ROOT_PRERENDER_PINS = {
193
+ crawlLinks: false,
194
+ failOnError: false,
195
+ maxRedirects: 0,
196
+ autoSubfolderIndex: true
197
+ };
198
+ const PAGE_PRERENDER_PINS = {
199
+ crawlLinks: ROOT_PRERENDER_PINS.crawlLinks,
200
+ autoSubfolderIndex: ROOT_PRERENDER_PINS.autoSubfolderIndex
201
+ };
202
+ function pinPrerenderOptions(source, pins, label) {
203
+ const result = { ...source };
204
+ for (const [key, value] of Object.entries(pins)) {
205
+ if (key in result && result[key] !== value) logWarning(`Ignoring ${label}.${key} inside the Lovable build environment; forcing ${JSON.stringify(value)}.`);
206
+ result[key] = value;
207
+ }
208
+ if ("outputPath" in result) {
209
+ logWarning(`Ignoring ${label}.outputPath inside the Lovable build environment; prerendered routes are always written to <route>/index.html.`);
210
+ delete result.outputPath;
211
+ }
212
+ return result;
213
+ }
214
+ function pinPrerenderForLovableBuild(userOptions) {
215
+ const attempted = /* @__PURE__ */ new Set();
216
+ const rendered = /* @__PURE__ */ new Set();
217
+ const userPrerender = userOptions.prerender;
218
+ const prerender = pinPrerenderOptions(userPrerender, ROOT_PRERENDER_PINS, "prerender");
219
+ const userFilter = userPrerender?.filter;
220
+ prerender.filter = (page) => {
221
+ const keep = typeof userFilter === "function" ? userFilter(page) : true;
222
+ if (keep) attempted.add(page.path);
223
+ return keep;
224
+ };
225
+ const withRenderTracking = (userOnSuccess) => (ctx) => {
226
+ rendered.add(ctx.page.path);
227
+ return typeof userOnSuccess === "function" ? userOnSuccess(ctx) : void 0;
228
+ };
229
+ prerender.onSuccess = withRenderTracking(userPrerender?.onSuccess);
230
+ const startOptions = {
231
+ ...userOptions,
232
+ prerender
233
+ };
234
+ if (Array.isArray(userOptions.pages)) startOptions.pages = userOptions.pages.map((page) => {
235
+ if (!page || typeof page !== "object") return page;
236
+ const entry = page;
237
+ if (!entry.prerender) return entry;
238
+ const pinned = pinPrerenderOptions(entry.prerender, PAGE_PRERENDER_PINS, `pages["${entry.path}"].prerender`);
239
+ if ("onSuccess" in pinned) pinned.onSuccess = withRenderTracking(pinned.onSuccess);
240
+ return {
241
+ ...entry,
242
+ prerender: pinned
243
+ };
244
+ });
245
+ return {
246
+ startOptions,
247
+ skipReporter: {
248
+ name: "lovable:prerender-skip-report",
249
+ apply: "build",
250
+ enforce: "post",
251
+ buildApp: {
252
+ order: "post",
253
+ async handler() {
254
+ const skipped = [...attempted].filter((route) => !rendered.has(route));
255
+ if (skipped.length === 0) return;
256
+ logWarning(`Prerender skipped ${skipped.length} route(s) that failed to render; they fall back to SSR: ${skipped.join(", ")}`);
257
+ }
258
+ }
259
+ }
260
+ };
261
+ }
192
262
  function lovableFetchBundlePreset() {
193
263
  return {
194
264
  entry: (0, node_url.fileURLToPath)(new URL("../runtime/fetch-entry.mjs", require("url").pathToFileURL(__filename).href)),
@@ -481,6 +551,107 @@ function stripRedundantNodejsCompatFlag() {
481
551
  }
482
552
  };
483
553
  }
554
+ const NITRO_SERVER_ENTRY = "index.mjs";
555
+ const NITRO_WRANGLER_CONFIG = "wrangler.json";
556
+ const DEFAULT_SERVER_OUTPUT_DIR = "dist/server";
557
+ const DEFAULT_SERVER_ENTRY_NAME = "server";
558
+ const PRERENDER_PREVIEW_HOST = "127.0.0.1";
559
+ const TSS_PRERENDERING_ENV = "TSS_PRERENDERING";
560
+ const SHIM_MARKER = "// Generated by @lovable.dev/vite-tanstack-config for the prerender preview server.";
561
+ function prerenderShimSource(vars) {
562
+ return `${SHIM_MARKER}
563
+ import server from "./${NITRO_SERVER_ENTRY}";
564
+
565
+ const env = ${JSON.stringify(vars)};
566
+ const ctx = { waitUntil() {}, passThroughOnException() {}, props: {} };
567
+
568
+ export default {
569
+ fetch(request) {
570
+ // srvx's NodeRequest exposes \`ip\` as a getter-only accessor and nitro's
571
+ // cloudflare module handler assigns to it; shadow it with a writable one.
572
+ Object.defineProperty(request, "ip", { value: undefined, writable: true, configurable: true });
573
+ return server.fetch(request, env, ctx);
574
+ },
575
+ };
576
+ `;
577
+ }
578
+ function prerenderPreviewShim(state) {
579
+ let root = process.cwd();
580
+ let serverOutDir = DEFAULT_SERVER_OUTPUT_DIR;
581
+ let serverEntryName = DEFAULT_SERVER_ENTRY_NAME;
582
+ return {
583
+ name: "lovable-prerender-preview-shim",
584
+ apply: "build",
585
+ config(userConfig) {
586
+ const ssrBuild = userConfig.environments?.ssr?.build;
587
+ if (ssrBuild?.outDir) serverOutDir = ssrBuild.outDir;
588
+ const input = ssrBuild?.rolldownOptions?.input ?? ssrBuild?.rollupOptions?.input;
589
+ if (typeof input === "string") serverEntryName = input;
590
+ },
591
+ configResolved(config) {
592
+ root = config.root;
593
+ },
594
+ buildApp: {
595
+ order: "post",
596
+ handler: async () => {
597
+ const { access, readFile, writeFile } = await import("node:fs/promises");
598
+ const nodePath = await import("node:path");
599
+ const exists = async (candidate) => {
600
+ try {
601
+ await access(candidate);
602
+ return true;
603
+ } catch {
604
+ return false;
605
+ }
606
+ };
607
+ const outDir = nodePath.resolve(root, serverOutDir);
608
+ if (!await exists(nodePath.join(outDir, NITRO_SERVER_ENTRY))) return;
609
+ const basename = nodePath.basename(serverEntryName, nodePath.extname(serverEntryName));
610
+ if (!basename || basename === "index") {
611
+ logWarning(`Cannot prerender: the server entry "${serverEntryName}" would need a shim at ${DEFAULT_SERVER_OUTPUT_DIR}/index.js, which outranks nitro's own entry when publishing. Rename the entry to anything but \`index\`.`);
612
+ return;
613
+ }
614
+ const target = nodePath.join(outDir, `${basename}.js`);
615
+ const occupant = await readFile(target, "utf8").catch(() => void 0);
616
+ if (occupant !== void 0 && !occupant.startsWith(SHIM_MARKER)) {
617
+ logWarning(`Cannot prerender: ${basename}.js already exists in ${serverOutDir} and was not written by this plugin.`);
618
+ return;
619
+ }
620
+ let vars = {};
621
+ try {
622
+ const candidate = JSON.parse(await readFile(nodePath.join(outDir, NITRO_WRANGLER_CONFIG), "utf8"))?.vars;
623
+ if (candidate && typeof candidate === "object" && !Array.isArray(candidate)) vars = candidate;
624
+ } catch {}
625
+ await writeFile(target, prerenderShimSource(vars));
626
+ state.file = target;
627
+ }
628
+ }
629
+ };
630
+ }
631
+ function prerenderPreviewShimCleanup(state) {
632
+ return {
633
+ name: "lovable-prerender-preview-shim-cleanup",
634
+ apply: "build",
635
+ enforce: "post",
636
+ buildApp: {
637
+ order: "post",
638
+ handler: async () => {
639
+ if (!state.file) return;
640
+ const { rm } = await import("node:fs/promises");
641
+ await rm(state.file, { force: true });
642
+ state.file = void 0;
643
+ }
644
+ }
645
+ };
646
+ }
647
+ function prerenderIsEnabled(startOptions) {
648
+ const spa = startOptions.spa;
649
+ if (spa && (spa.enabled ?? true)) return true;
650
+ const prerender = startOptions.prerender;
651
+ if (prerender?.enabled === false) return false;
652
+ const pages = Array.isArray(startOptions.pages) ? startOptions.pages : [];
653
+ return !!(prerender?.enabled ?? pages.some((page) => !!page?.prerender?.enabled));
654
+ }
484
655
  function devSsrErrorLogger() {
485
656
  let lastCapture;
486
657
  const CAPTURE_TTL_MS = 5e3;
@@ -660,7 +831,11 @@ function defineConfig(configOrOptions = {}) {
660
831
  specifiers: ["server-only"]
661
832
  }
662
833
  } }, options.tanstackStart ?? {});
663
- internalPlugins.push(tanstackStart(tanstackStartOptions));
834
+ const prerenderEnabled = prerenderIsEnabled(tanstackStartOptions);
835
+ if (command === "build" && isSandbox) {
836
+ const { startOptions, skipReporter } = pinPrerenderForLovableBuild(tanstackStartOptions);
837
+ internalPlugins.push(tanstackStart(startOptions), skipReporter);
838
+ } else internalPlugins.push(tanstackStart(tanstackStartOptions));
664
839
  const explicitNitro = options.nitro === true || typeof options.nitro === "object" && options.nitro !== null;
665
840
  if (options.nitro !== false && command === "build") {
666
841
  let nitroMod;
@@ -709,6 +884,10 @@ function defineConfig(configOrOptions = {}) {
709
884
  }
710
885
  } else if (!nitroOpts.preset && !await nitroSupportsDefaultPreset()) logWarning("The installed `nitro` predates the `defaultPreset` option (3.0.260603-beta), so the Cloudflare fallback is ignored and a zero-config build may target Node instead. Upgrade nitro to >=3.0.260603-beta, or set an explicit `nitro: { preset: \"cloudflare-module\" }`.");
711
886
  internalPlugins.push(nitro(nitroOpts));
887
+ if (prerenderEnabled) {
888
+ const shimState = {};
889
+ internalPlugins.push(prerenderPreviewShim(shimState), prerenderPreviewShimCleanup(shimState));
890
+ }
712
891
  if (isSandbox) internalPlugins.push(stripRedundantNodejsCompatFlag());
713
892
  }
714
893
  }
@@ -784,6 +963,10 @@ function defineConfig(configOrOptions = {}) {
784
963
  host: "::",
785
964
  port: 8080
786
965
  } }, config);
966
+ if (env.isPreview && prerenderEnabled && process.env[TSS_PRERENDERING_ENV] === "true") config = (0, vite.mergeConfig)({ preview: {
967
+ host: PRERENDER_PREVIEW_HOST,
968
+ port: 0
969
+ } }, config);
787
970
  if (isSandbox) return config;
788
971
  return applyWatchDebounceDefaults(config);
789
972
  };
package/dist/index.d.cts CHANGED
@@ -12,6 +12,10 @@ import { ConfigEnv, Plugin, PluginOption, UserConfig, UserConfigFn, UserConfigFn
12
12
  declare function lovableAssetsProxyPlugin(): Plugin;
13
13
  //#endregion
14
14
  //#region src/index.d.ts
15
+ type PrerenderPage = {
16
+ path: string;
17
+ prerender?: Record<string, unknown>;
18
+ };
15
19
  declare function stripRedundantNodejsCompatFlag(): Plugin;
16
20
  interface LovableViteTanstackOptions {
17
21
  plugins?: PluginOption[];
@@ -52,7 +56,7 @@ interface LovableViteTanstackOptions {
52
56
  deployConfig?: boolean;
53
57
  };
54
58
  } | false;
55
- /** Options forwarded to tanstackStart(). */
59
+ /** Options forwarded to tanstackStart(). Inside a Lovable build the prerender output shape is pinned. */
56
60
  tanstackStart?: Record<string, unknown>;
57
61
  /** Options forwarded to viteReact(). */
58
62
  react?: Record<string, unknown>;
@@ -68,4 +72,4 @@ declare function defineConfig(config: UserConfigFnPromise): (env: ConfigEnv) =>
68
72
  declare function defineConfig(config: UserConfigFn): (env: ConfigEnv) => Promise<UserConfig>;
69
73
  declare function defineConfig(options?: LovableViteTanstackOptions): (env: ConfigEnv) => Promise<UserConfig>;
70
74
  //#endregion
71
- export { LovableViteTanstackOptions, defineConfig, lovableAssetsProxyPlugin, stripRedundantNodejsCompatFlag };
75
+ export { LovableViteTanstackOptions, PrerenderPage, defineConfig, lovableAssetsProxyPlugin, stripRedundantNodejsCompatFlag };
package/dist/index.d.ts CHANGED
@@ -12,6 +12,10 @@ import { ConfigEnv, Plugin, PluginOption, UserConfig, UserConfigFn, UserConfigFn
12
12
  declare function lovableAssetsProxyPlugin(): Plugin;
13
13
  //#endregion
14
14
  //#region src/index.d.ts
15
+ type PrerenderPage = {
16
+ path: string;
17
+ prerender?: Record<string, unknown>;
18
+ };
15
19
  declare function stripRedundantNodejsCompatFlag(): Plugin;
16
20
  interface LovableViteTanstackOptions {
17
21
  plugins?: PluginOption[];
@@ -52,7 +56,7 @@ interface LovableViteTanstackOptions {
52
56
  deployConfig?: boolean;
53
57
  };
54
58
  } | false;
55
- /** Options forwarded to tanstackStart(). */
59
+ /** Options forwarded to tanstackStart(). Inside a Lovable build the prerender output shape is pinned. */
56
60
  tanstackStart?: Record<string, unknown>;
57
61
  /** Options forwarded to viteReact(). */
58
62
  react?: Record<string, unknown>;
@@ -68,4 +72,4 @@ declare function defineConfig(config: UserConfigFnPromise): (env: ConfigEnv) =>
68
72
  declare function defineConfig(config: UserConfigFn): (env: ConfigEnv) => Promise<UserConfig>;
69
73
  declare function defineConfig(options?: LovableViteTanstackOptions): (env: ConfigEnv) => Promise<UserConfig>;
70
74
  //#endregion
71
- export { LovableViteTanstackOptions, defineConfig, lovableAssetsProxyPlugin, stripRedundantNodejsCompatFlag };
75
+ export { LovableViteTanstackOptions, PrerenderPage, defineConfig, lovableAssetsProxyPlugin, stripRedundantNodejsCompatFlag };
package/dist/index.js CHANGED
@@ -165,6 +165,76 @@ async function nitroSupportsDefaultPreset() {
165
165
  }
166
166
  }
167
167
  const LOVABLE_NITRO_PRESETS = ["cloudflare-module", "lovable-fetch-bundle"];
168
+ const ROOT_PRERENDER_PINS = {
169
+ crawlLinks: false,
170
+ failOnError: false,
171
+ maxRedirects: 0,
172
+ autoSubfolderIndex: true
173
+ };
174
+ const PAGE_PRERENDER_PINS = {
175
+ crawlLinks: ROOT_PRERENDER_PINS.crawlLinks,
176
+ autoSubfolderIndex: ROOT_PRERENDER_PINS.autoSubfolderIndex
177
+ };
178
+ function pinPrerenderOptions(source, pins, label) {
179
+ const result = { ...source };
180
+ for (const [key, value] of Object.entries(pins)) {
181
+ if (key in result && result[key] !== value) logWarning(`Ignoring ${label}.${key} inside the Lovable build environment; forcing ${JSON.stringify(value)}.`);
182
+ result[key] = value;
183
+ }
184
+ if ("outputPath" in result) {
185
+ logWarning(`Ignoring ${label}.outputPath inside the Lovable build environment; prerendered routes are always written to <route>/index.html.`);
186
+ delete result.outputPath;
187
+ }
188
+ return result;
189
+ }
190
+ function pinPrerenderForLovableBuild(userOptions) {
191
+ const attempted = /* @__PURE__ */ new Set();
192
+ const rendered = /* @__PURE__ */ new Set();
193
+ const userPrerender = userOptions.prerender;
194
+ const prerender = pinPrerenderOptions(userPrerender, ROOT_PRERENDER_PINS, "prerender");
195
+ const userFilter = userPrerender?.filter;
196
+ prerender.filter = (page) => {
197
+ const keep = typeof userFilter === "function" ? userFilter(page) : true;
198
+ if (keep) attempted.add(page.path);
199
+ return keep;
200
+ };
201
+ const withRenderTracking = (userOnSuccess) => (ctx) => {
202
+ rendered.add(ctx.page.path);
203
+ return typeof userOnSuccess === "function" ? userOnSuccess(ctx) : void 0;
204
+ };
205
+ prerender.onSuccess = withRenderTracking(userPrerender?.onSuccess);
206
+ const startOptions = {
207
+ ...userOptions,
208
+ prerender
209
+ };
210
+ if (Array.isArray(userOptions.pages)) startOptions.pages = userOptions.pages.map((page) => {
211
+ if (!page || typeof page !== "object") return page;
212
+ const entry = page;
213
+ if (!entry.prerender) return entry;
214
+ const pinned = pinPrerenderOptions(entry.prerender, PAGE_PRERENDER_PINS, `pages["${entry.path}"].prerender`);
215
+ if ("onSuccess" in pinned) pinned.onSuccess = withRenderTracking(pinned.onSuccess);
216
+ return {
217
+ ...entry,
218
+ prerender: pinned
219
+ };
220
+ });
221
+ return {
222
+ startOptions,
223
+ skipReporter: {
224
+ name: "lovable:prerender-skip-report",
225
+ apply: "build",
226
+ enforce: "post",
227
+ buildApp: {
228
+ order: "post",
229
+ async handler() {
230
+ const skipped = [...attempted].filter((route) => !rendered.has(route));
231
+ if (skipped.length === 0) return;
232
+ logWarning(`Prerender skipped ${skipped.length} route(s) that failed to render; they fall back to SSR: ${skipped.join(", ")}`);
233
+ }
234
+ }
235
+ }
236
+ };
237
+ }
168
238
  function lovableFetchBundlePreset() {
169
239
  return {
170
240
  entry: fileURLToPath(new URL("../runtime/fetch-entry.mjs", import.meta.url)),
@@ -457,6 +527,107 @@ function stripRedundantNodejsCompatFlag() {
457
527
  }
458
528
  };
459
529
  }
530
+ const NITRO_SERVER_ENTRY = "index.mjs";
531
+ const NITRO_WRANGLER_CONFIG = "wrangler.json";
532
+ const DEFAULT_SERVER_OUTPUT_DIR = "dist/server";
533
+ const DEFAULT_SERVER_ENTRY_NAME = "server";
534
+ const PRERENDER_PREVIEW_HOST = "127.0.0.1";
535
+ const TSS_PRERENDERING_ENV = "TSS_PRERENDERING";
536
+ const SHIM_MARKER = "// Generated by @lovable.dev/vite-tanstack-config for the prerender preview server.";
537
+ function prerenderShimSource(vars) {
538
+ return `${SHIM_MARKER}
539
+ import server from "./${NITRO_SERVER_ENTRY}";
540
+
541
+ const env = ${JSON.stringify(vars)};
542
+ const ctx = { waitUntil() {}, passThroughOnException() {}, props: {} };
543
+
544
+ export default {
545
+ fetch(request) {
546
+ // srvx's NodeRequest exposes \`ip\` as a getter-only accessor and nitro's
547
+ // cloudflare module handler assigns to it; shadow it with a writable one.
548
+ Object.defineProperty(request, "ip", { value: undefined, writable: true, configurable: true });
549
+ return server.fetch(request, env, ctx);
550
+ },
551
+ };
552
+ `;
553
+ }
554
+ function prerenderPreviewShim(state) {
555
+ let root = process.cwd();
556
+ let serverOutDir = DEFAULT_SERVER_OUTPUT_DIR;
557
+ let serverEntryName = DEFAULT_SERVER_ENTRY_NAME;
558
+ return {
559
+ name: "lovable-prerender-preview-shim",
560
+ apply: "build",
561
+ config(userConfig) {
562
+ const ssrBuild = userConfig.environments?.ssr?.build;
563
+ if (ssrBuild?.outDir) serverOutDir = ssrBuild.outDir;
564
+ const input = ssrBuild?.rolldownOptions?.input ?? ssrBuild?.rollupOptions?.input;
565
+ if (typeof input === "string") serverEntryName = input;
566
+ },
567
+ configResolved(config) {
568
+ root = config.root;
569
+ },
570
+ buildApp: {
571
+ order: "post",
572
+ handler: async () => {
573
+ const { access, readFile, writeFile } = await import("node:fs/promises");
574
+ const nodePath = await import("node:path");
575
+ const exists = async (candidate) => {
576
+ try {
577
+ await access(candidate);
578
+ return true;
579
+ } catch {
580
+ return false;
581
+ }
582
+ };
583
+ const outDir = nodePath.resolve(root, serverOutDir);
584
+ if (!await exists(nodePath.join(outDir, NITRO_SERVER_ENTRY))) return;
585
+ const basename = nodePath.basename(serverEntryName, nodePath.extname(serverEntryName));
586
+ if (!basename || basename === "index") {
587
+ logWarning(`Cannot prerender: the server entry "${serverEntryName}" would need a shim at ${DEFAULT_SERVER_OUTPUT_DIR}/index.js, which outranks nitro's own entry when publishing. Rename the entry to anything but \`index\`.`);
588
+ return;
589
+ }
590
+ const target = nodePath.join(outDir, `${basename}.js`);
591
+ const occupant = await readFile(target, "utf8").catch(() => void 0);
592
+ if (occupant !== void 0 && !occupant.startsWith(SHIM_MARKER)) {
593
+ logWarning(`Cannot prerender: ${basename}.js already exists in ${serverOutDir} and was not written by this plugin.`);
594
+ return;
595
+ }
596
+ let vars = {};
597
+ try {
598
+ const candidate = JSON.parse(await readFile(nodePath.join(outDir, NITRO_WRANGLER_CONFIG), "utf8"))?.vars;
599
+ if (candidate && typeof candidate === "object" && !Array.isArray(candidate)) vars = candidate;
600
+ } catch {}
601
+ await writeFile(target, prerenderShimSource(vars));
602
+ state.file = target;
603
+ }
604
+ }
605
+ };
606
+ }
607
+ function prerenderPreviewShimCleanup(state) {
608
+ return {
609
+ name: "lovable-prerender-preview-shim-cleanup",
610
+ apply: "build",
611
+ enforce: "post",
612
+ buildApp: {
613
+ order: "post",
614
+ handler: async () => {
615
+ if (!state.file) return;
616
+ const { rm } = await import("node:fs/promises");
617
+ await rm(state.file, { force: true });
618
+ state.file = void 0;
619
+ }
620
+ }
621
+ };
622
+ }
623
+ function prerenderIsEnabled(startOptions) {
624
+ const spa = startOptions.spa;
625
+ if (spa && (spa.enabled ?? true)) return true;
626
+ const prerender = startOptions.prerender;
627
+ if (prerender?.enabled === false) return false;
628
+ const pages = Array.isArray(startOptions.pages) ? startOptions.pages : [];
629
+ return !!(prerender?.enabled ?? pages.some((page) => !!page?.prerender?.enabled));
630
+ }
460
631
  function devSsrErrorLogger() {
461
632
  let lastCapture;
462
633
  const CAPTURE_TTL_MS = 5e3;
@@ -636,7 +807,11 @@ function defineConfig(configOrOptions = {}) {
636
807
  specifiers: ["server-only"]
637
808
  }
638
809
  } }, options.tanstackStart ?? {});
639
- internalPlugins.push(tanstackStart(tanstackStartOptions));
810
+ const prerenderEnabled = prerenderIsEnabled(tanstackStartOptions);
811
+ if (command === "build" && isSandbox) {
812
+ const { startOptions, skipReporter } = pinPrerenderForLovableBuild(tanstackStartOptions);
813
+ internalPlugins.push(tanstackStart(startOptions), skipReporter);
814
+ } else internalPlugins.push(tanstackStart(tanstackStartOptions));
640
815
  const explicitNitro = options.nitro === true || typeof options.nitro === "object" && options.nitro !== null;
641
816
  if (options.nitro !== false && command === "build") {
642
817
  let nitroMod;
@@ -685,6 +860,10 @@ function defineConfig(configOrOptions = {}) {
685
860
  }
686
861
  } else if (!nitroOpts.preset && !await nitroSupportsDefaultPreset()) logWarning("The installed `nitro` predates the `defaultPreset` option (3.0.260603-beta), so the Cloudflare fallback is ignored and a zero-config build may target Node instead. Upgrade nitro to >=3.0.260603-beta, or set an explicit `nitro: { preset: \"cloudflare-module\" }`.");
687
862
  internalPlugins.push(nitro(nitroOpts));
863
+ if (prerenderEnabled) {
864
+ const shimState = {};
865
+ internalPlugins.push(prerenderPreviewShim(shimState), prerenderPreviewShimCleanup(shimState));
866
+ }
688
867
  if (isSandbox) internalPlugins.push(stripRedundantNodejsCompatFlag());
689
868
  }
690
869
  }
@@ -760,6 +939,10 @@ function defineConfig(configOrOptions = {}) {
760
939
  host: "::",
761
940
  port: 8080
762
941
  } }, config);
942
+ if (env.isPreview && prerenderEnabled && process.env[TSS_PRERENDERING_ENV] === "true") config = mergeConfig({ preview: {
943
+ host: PRERENDER_PREVIEW_HOST,
944
+ port: 0
945
+ } }, config);
763
946
  if (isSandbox) return config;
764
947
  return applyWatchDebounceDefaults(config);
765
948
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lovable.dev/vite-tanstack-config",
3
- "version": "2.15.1",
3
+ "version": "2.17.0",
4
4
  "description": "Vite config wrapper for Lovable TanStack Start projects",
5
5
  "main": "./dist/index.cjs",
6
6
  "module": "./dist/index.js",