@lovable.dev/vite-tanstack-config 2.15.1 → 2.16.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)),
@@ -660,7 +730,10 @@ function defineConfig(configOrOptions = {}) {
660
730
  specifiers: ["server-only"]
661
731
  }
662
732
  } }, options.tanstackStart ?? {});
663
- internalPlugins.push(tanstackStart(tanstackStartOptions));
733
+ if (command === "build" && isSandbox) {
734
+ const { startOptions, skipReporter } = pinPrerenderForLovableBuild(tanstackStartOptions);
735
+ internalPlugins.push(tanstackStart(startOptions), skipReporter);
736
+ } else internalPlugins.push(tanstackStart(tanstackStartOptions));
664
737
  const explicitNitro = options.nitro === true || typeof options.nitro === "object" && options.nitro !== null;
665
738
  if (options.nitro !== false && command === "build") {
666
739
  let nitroMod;
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)),
@@ -636,7 +706,10 @@ function defineConfig(configOrOptions = {}) {
636
706
  specifiers: ["server-only"]
637
707
  }
638
708
  } }, options.tanstackStart ?? {});
639
- internalPlugins.push(tanstackStart(tanstackStartOptions));
709
+ if (command === "build" && isSandbox) {
710
+ const { startOptions, skipReporter } = pinPrerenderForLovableBuild(tanstackStartOptions);
711
+ internalPlugins.push(tanstackStart(startOptions), skipReporter);
712
+ } else internalPlugins.push(tanstackStart(tanstackStartOptions));
640
713
  const explicitNitro = options.nitro === true || typeof options.nitro === "object" && options.nitro !== null;
641
714
  if (options.nitro !== false && command === "build") {
642
715
  let nitroMod;
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.16.0",
4
4
  "description": "Vite config wrapper for Lovable TanStack Start projects",
5
5
  "main": "./dist/index.cjs",
6
6
  "module": "./dist/index.js",