@lovable.dev/vite-tanstack-config 2.19.0 → 2.19.2

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
@@ -152,7 +152,7 @@ function bundledDevCssUrlShim() {
152
152
  //#endregion
153
153
  //#region package.json
154
154
  var name = "@lovable.dev/vite-tanstack-config";
155
- var version = "2.19.0";
155
+ var version = "2.19.2";
156
156
  //#endregion
157
157
  //#region src/logging.ts
158
158
  const PACKAGE_NAME = "@lovable.dev/vite-tanstack-config";
@@ -170,8 +170,6 @@ const DOCUMENT_SET_VERSION = 1;
170
170
  const GENERATOR = `${name}@${version}`;
171
171
  const DOCUMENT_SET_DIR = ".lovable";
172
172
  const DOCUMENT_SET_FILE = "output.json";
173
- const DOCUMENT_SET_MAX_ENTRIES = 1e4;
174
- const DOCUMENT_SET_MAX_BYTES = 4e6;
175
173
  const DOCUMENT_SET_PLUGIN_NAME = "lovable:document-set";
176
174
  const TANSTACK_POST_BUILD_PLUGIN = "tanstack-start-core:post-build";
177
175
  const DOT_SEGMENT = /(^|\/)\.(\/|$)/;
@@ -234,12 +232,12 @@ function serializeDocumentSet(entries, generator) {
234
232
  documents: []
235
233
  }).length;
236
234
  for (const entry of sorted) {
237
- if (selected.length === DOCUMENT_SET_MAX_ENTRIES) {
235
+ if (selected.length === 1e4) {
238
236
  cappedBy = "entry limit";
239
237
  break;
240
238
  }
241
239
  const added = JSON.stringify(entry).length + 1;
242
- if (length + added > DOCUMENT_SET_MAX_BYTES) {
240
+ if (length + added > 4e6) {
243
241
  cappedBy = "byte limit";
244
242
  break;
245
243
  }
@@ -255,13 +253,19 @@ function serializeDocumentSet(entries, generator) {
255
253
  });
256
254
  }
257
255
  const EXISTENCE_BATCH_SIZE = 64;
256
+ async function inBatches(items, run) {
257
+ const results = [];
258
+ for (let i = 0; i < items.length; i += EXISTENCE_BATCH_SIZE) results.push(...await Promise.all(items.slice(i, i + EXISTENCE_BATCH_SIZE).map(run)));
259
+ return results;
260
+ }
258
261
  async function whichExist(paths, access) {
259
- const exists = [];
260
- for (let i = 0; i < paths.length; i += EXISTENCE_BATCH_SIZE) {
261
- const batch = paths.slice(i, i + EXISTENCE_BATCH_SIZE).map((path) => access(path).then(() => true, () => false));
262
- exists.push(...await Promise.all(batch));
263
- }
264
- return exists;
262
+ return inBatches(paths, (path) => access(path).then(() => true, () => false));
263
+ }
264
+ async function whichMatch(pairs, readFile) {
265
+ const read = (path) => readFile(path).catch((error) => {
266
+ if (error.code !== "ENOENT") logWarning(`Could not read ${path} while checking prerender collisions: ${String(error)}`);
267
+ });
268
+ return inBatches(pairs, ([left, right]) => Promise.all([read(left), read(right)]).then(([a, b]) => a !== void 0 && b !== void 0 && a.equals(b)));
265
269
  }
266
270
  /** How the error names the public dir, which vite lets a project point anywhere. */
267
271
  function publicDirLabel(root, publicDir, nodePath) {
@@ -292,13 +296,15 @@ function createDocumentSet(routerBasePath) {
292
296
  buildApp: {
293
297
  order: "post",
294
298
  async handler() {
295
- const { access, mkdir, rm, writeFile } = await import("node:fs/promises");
299
+ const { access, mkdir, readFile, rm, writeFile } = await import("node:fs/promises");
296
300
  const nodePath = await import("node:path");
297
301
  const artifact = nodePath.join(root, PUBLISH_OUTPUT_DIR, DOCUMENT_SET_DIR, DOCUMENT_SET_FILE);
298
302
  await rm(artifact, { force: true }).catch((error) => {
299
303
  logWarning(`Could not remove a previous build's document set: ${String(error)}`);
300
304
  });
301
305
  if (documents.size === 0) return;
306
+ const clientDir = nodePath.resolve(root, clientOutputDir);
307
+ const label = publicDirLabel(root, publicDir, nodePath);
302
308
  const collisions = [];
303
309
  if (publicDir !== "") {
304
310
  const candidates = [...documents].map(([route, file]) => ({
@@ -306,14 +312,21 @@ function createDocumentSet(routerBasePath) {
306
312
  file
307
313
  }));
308
314
  const committed = await whichExist(candidates.map(({ file }) => nodePath.join(publicDir, file)), access);
309
- for (const [index, candidate] of candidates.entries()) if (committed[index]) collisions.push(candidate);
315
+ const suspects = candidates.filter((_candidate, index) => committed[index]);
316
+ const survived = await whichMatch(suspects.map(({ file }) => [nodePath.join(publicDir, file), nodePath.resolve(clientDir, file)]), readFile);
317
+ for (const [index, suspect] of suspects.entries()) {
318
+ if (!survived[index]) {
319
+ collisions.push(suspect);
320
+ continue;
321
+ }
322
+ documents.delete(suspect.route);
323
+ logWarning(`Not publishing prerendered route ${suspect.route}: it would serve the committed ${label}/${suspect.file}, which the prerender pass left untouched.`);
324
+ }
310
325
  }
311
326
  if (collisions.length > 0) {
312
- const label = publicDirLabel(root, publicDir, nodePath);
313
327
  const pairs = collisions.sort(compareRoutes).map(({ route, file }) => ` ${route} overwrites ${label}/${file}`);
314
328
  throw new Error(`[${PACKAGE_NAME}] Prerendering would overwrite ${collisions.length} committed file(s) under ${label}/:\n${pairs.join("\n")}\nEach route's prerendered HTML is written into the client build after vite copies ${label}/, so every committed file above is replaced by its rendered route and never ships.\nFix each line above in one of two ways: delete or rename the ${label}/ file, or stop prerendering the route (drop it from \`pages\` in vite.config, or return false for it from \`prerender.filter\`).`);
315
329
  }
316
- const clientDir = nodePath.resolve(root, clientOutputDir);
317
330
  const entries = [...documents].map(([route, file]) => ({
318
331
  route,
319
332
  file
package/dist/index.js CHANGED
@@ -128,7 +128,7 @@ function bundledDevCssUrlShim() {
128
128
  //#endregion
129
129
  //#region package.json
130
130
  var name = "@lovable.dev/vite-tanstack-config";
131
- var version = "2.19.0";
131
+ var version = "2.19.2";
132
132
  //#endregion
133
133
  //#region src/logging.ts
134
134
  const PACKAGE_NAME = "@lovable.dev/vite-tanstack-config";
@@ -146,8 +146,6 @@ const DOCUMENT_SET_VERSION = 1;
146
146
  const GENERATOR = `${name}@${version}`;
147
147
  const DOCUMENT_SET_DIR = ".lovable";
148
148
  const DOCUMENT_SET_FILE = "output.json";
149
- const DOCUMENT_SET_MAX_ENTRIES = 1e4;
150
- const DOCUMENT_SET_MAX_BYTES = 4e6;
151
149
  const DOCUMENT_SET_PLUGIN_NAME = "lovable:document-set";
152
150
  const TANSTACK_POST_BUILD_PLUGIN = "tanstack-start-core:post-build";
153
151
  const DOT_SEGMENT = /(^|\/)\.(\/|$)/;
@@ -210,12 +208,12 @@ function serializeDocumentSet(entries, generator) {
210
208
  documents: []
211
209
  }).length;
212
210
  for (const entry of sorted) {
213
- if (selected.length === DOCUMENT_SET_MAX_ENTRIES) {
211
+ if (selected.length === 1e4) {
214
212
  cappedBy = "entry limit";
215
213
  break;
216
214
  }
217
215
  const added = JSON.stringify(entry).length + 1;
218
- if (length + added > DOCUMENT_SET_MAX_BYTES) {
216
+ if (length + added > 4e6) {
219
217
  cappedBy = "byte limit";
220
218
  break;
221
219
  }
@@ -231,13 +229,19 @@ function serializeDocumentSet(entries, generator) {
231
229
  });
232
230
  }
233
231
  const EXISTENCE_BATCH_SIZE = 64;
232
+ async function inBatches(items, run) {
233
+ const results = [];
234
+ for (let i = 0; i < items.length; i += EXISTENCE_BATCH_SIZE) results.push(...await Promise.all(items.slice(i, i + EXISTENCE_BATCH_SIZE).map(run)));
235
+ return results;
236
+ }
234
237
  async function whichExist(paths, access) {
235
- const exists = [];
236
- for (let i = 0; i < paths.length; i += EXISTENCE_BATCH_SIZE) {
237
- const batch = paths.slice(i, i + EXISTENCE_BATCH_SIZE).map((path) => access(path).then(() => true, () => false));
238
- exists.push(...await Promise.all(batch));
239
- }
240
- return exists;
238
+ return inBatches(paths, (path) => access(path).then(() => true, () => false));
239
+ }
240
+ async function whichMatch(pairs, readFile) {
241
+ const read = (path) => readFile(path).catch((error) => {
242
+ if (error.code !== "ENOENT") logWarning(`Could not read ${path} while checking prerender collisions: ${String(error)}`);
243
+ });
244
+ return inBatches(pairs, ([left, right]) => Promise.all([read(left), read(right)]).then(([a, b]) => a !== void 0 && b !== void 0 && a.equals(b)));
241
245
  }
242
246
  /** How the error names the public dir, which vite lets a project point anywhere. */
243
247
  function publicDirLabel(root, publicDir, nodePath) {
@@ -268,13 +272,15 @@ function createDocumentSet(routerBasePath) {
268
272
  buildApp: {
269
273
  order: "post",
270
274
  async handler() {
271
- const { access, mkdir, rm, writeFile } = await import("node:fs/promises");
275
+ const { access, mkdir, readFile, rm, writeFile } = await import("node:fs/promises");
272
276
  const nodePath = await import("node:path");
273
277
  const artifact = nodePath.join(root, PUBLISH_OUTPUT_DIR, DOCUMENT_SET_DIR, DOCUMENT_SET_FILE);
274
278
  await rm(artifact, { force: true }).catch((error) => {
275
279
  logWarning(`Could not remove a previous build's document set: ${String(error)}`);
276
280
  });
277
281
  if (documents.size === 0) return;
282
+ const clientDir = nodePath.resolve(root, clientOutputDir);
283
+ const label = publicDirLabel(root, publicDir, nodePath);
278
284
  const collisions = [];
279
285
  if (publicDir !== "") {
280
286
  const candidates = [...documents].map(([route, file]) => ({
@@ -282,14 +288,21 @@ function createDocumentSet(routerBasePath) {
282
288
  file
283
289
  }));
284
290
  const committed = await whichExist(candidates.map(({ file }) => nodePath.join(publicDir, file)), access);
285
- for (const [index, candidate] of candidates.entries()) if (committed[index]) collisions.push(candidate);
291
+ const suspects = candidates.filter((_candidate, index) => committed[index]);
292
+ const survived = await whichMatch(suspects.map(({ file }) => [nodePath.join(publicDir, file), nodePath.resolve(clientDir, file)]), readFile);
293
+ for (const [index, suspect] of suspects.entries()) {
294
+ if (!survived[index]) {
295
+ collisions.push(suspect);
296
+ continue;
297
+ }
298
+ documents.delete(suspect.route);
299
+ logWarning(`Not publishing prerendered route ${suspect.route}: it would serve the committed ${label}/${suspect.file}, which the prerender pass left untouched.`);
300
+ }
286
301
  }
287
302
  if (collisions.length > 0) {
288
- const label = publicDirLabel(root, publicDir, nodePath);
289
303
  const pairs = collisions.sort(compareRoutes).map(({ route, file }) => ` ${route} overwrites ${label}/${file}`);
290
304
  throw new Error(`[${PACKAGE_NAME}] Prerendering would overwrite ${collisions.length} committed file(s) under ${label}/:\n${pairs.join("\n")}\nEach route's prerendered HTML is written into the client build after vite copies ${label}/, so every committed file above is replaced by its rendered route and never ships.\nFix each line above in one of two ways: delete or rename the ${label}/ file, or stop prerendering the route (drop it from \`pages\` in vite.config, or return false for it from \`prerender.filter\`).`);
291
305
  }
292
- const clientDir = nodePath.resolve(root, clientOutputDir);
293
306
  const entries = [...documents].map(([route, file]) => ({
294
307
  route,
295
308
  file
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lovable.dev/vite-tanstack-config",
3
- "version": "2.19.0",
3
+ "version": "2.19.2",
4
4
  "description": "Vite config wrapper for Lovable TanStack Start projects",
5
5
  "main": "./dist/index.cjs",
6
6
  "module": "./dist/index.js",