@lovable.dev/vite-tanstack-config 2.18.0 → 2.19.1
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 +48 -10
- package/dist/index.js +48 -10
- package/package.json +1 -1
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.
|
|
155
|
+
var version = "2.19.1";
|
|
156
156
|
//#endregion
|
|
157
157
|
//#region src/logging.ts
|
|
158
158
|
const PACKAGE_NAME = "@lovable.dev/vite-tanstack-config";
|
|
@@ -198,15 +198,17 @@ function normalizeBasePath(raw) {
|
|
|
198
198
|
return trimmed.startsWith("/") ? trimmed : `/${trimmed}`;
|
|
199
199
|
}
|
|
200
200
|
function withoutBasePath(route, basePath) {
|
|
201
|
-
if (route === basePath) return "/";
|
|
202
201
|
if (basePath === "") return route;
|
|
203
|
-
|
|
202
|
+
if (route === basePath) return "/";
|
|
203
|
+
if (route.startsWith(`${basePath}/`)) return route.slice(basePath.length);
|
|
204
|
+
return route.startsWith(basePath) ? void 0 : route;
|
|
204
205
|
}
|
|
205
206
|
function documentEntryForPage(page, basePath = "") {
|
|
206
207
|
if (typeof page.prerender?.outputPath === "string") return void 0;
|
|
207
208
|
const pagePath = normalizeRoute(page.path);
|
|
208
209
|
if (pagePath === void 0) return void 0;
|
|
209
210
|
const inner = withoutBasePath(pagePath, basePath);
|
|
211
|
+
if (inner === void 0) return void 0;
|
|
210
212
|
const route = normalizeRoute(`${basePath}${inner}`);
|
|
211
213
|
if (route === void 0) return void 0;
|
|
212
214
|
const file = inner === "/" ? "index.html" : `${inner.slice(1)}/index.html`;
|
|
@@ -253,13 +255,24 @@ function serializeDocumentSet(entries, generator) {
|
|
|
253
255
|
});
|
|
254
256
|
}
|
|
255
257
|
const EXISTENCE_BATCH_SIZE = 64;
|
|
258
|
+
async function inBatches(items, run) {
|
|
259
|
+
const results = [];
|
|
260
|
+
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)));
|
|
261
|
+
return results;
|
|
262
|
+
}
|
|
256
263
|
async function whichExist(paths, access) {
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
264
|
+
return inBatches(paths, (path) => access(path).then(() => true, () => false));
|
|
265
|
+
}
|
|
266
|
+
async function whichMatch(pairs, readFile) {
|
|
267
|
+
const read = (path) => readFile(path).catch((error) => {
|
|
268
|
+
if (error.code !== "ENOENT") logWarning(`Could not read ${path} while checking prerender collisions: ${String(error)}`);
|
|
269
|
+
});
|
|
270
|
+
return inBatches(pairs, ([left, right]) => Promise.all([read(left), read(right)]).then(([a, b]) => a !== void 0 && b !== void 0 && a.equals(b)));
|
|
271
|
+
}
|
|
272
|
+
/** How the error names the public dir, which vite lets a project point anywhere. */
|
|
273
|
+
function publicDirLabel(root, publicDir, nodePath) {
|
|
274
|
+
const relative = nodePath.relative(root, publicDir);
|
|
275
|
+
return relative !== "" && !relative.startsWith("..") ? relative.split(nodePath.sep).join("/") : publicDir;
|
|
263
276
|
}
|
|
264
277
|
function createDocumentSet(routerBasePath) {
|
|
265
278
|
const basePath = normalizeBasePath(routerBasePath);
|
|
@@ -268,6 +281,7 @@ function createDocumentSet(routerBasePath) {
|
|
|
268
281
|
const documents = /* @__PURE__ */ new Map();
|
|
269
282
|
let root = process.cwd();
|
|
270
283
|
let clientOutputDir = CLIENT_OUTPUT_DIR;
|
|
284
|
+
let publicDir = "";
|
|
271
285
|
const plugin = {
|
|
272
286
|
name: DOCUMENT_SET_PLUGIN_NAME,
|
|
273
287
|
apply: "build",
|
|
@@ -279,11 +293,12 @@ function createDocumentSet(routerBasePath) {
|
|
|
279
293
|
const ours = names.indexOf(DOCUMENT_SET_PLUGIN_NAME);
|
|
280
294
|
if (theirs !== -1 && ours !== -1 && ours < theirs) logWarning(`Prerendered routes will fall back to SSR: ${DOCUMENT_SET_PLUGIN_NAME} is registered before ${TANSTACK_POST_BUILD_PLUGIN}, so the document set is written before the prerender pass runs.`);
|
|
281
295
|
clientOutputDir = config.environments?.client?.build?.outDir ?? CLIENT_OUTPUT_DIR;
|
|
296
|
+
publicDir = (config.environments?.client?.build?.copyPublicDir ?? config.build?.copyPublicDir) !== false && typeof config.publicDir === "string" ? config.publicDir : "";
|
|
282
297
|
},
|
|
283
298
|
buildApp: {
|
|
284
299
|
order: "post",
|
|
285
300
|
async handler() {
|
|
286
|
-
const { access, mkdir, rm, writeFile } = await import("node:fs/promises");
|
|
301
|
+
const { access, mkdir, readFile, rm, writeFile } = await import("node:fs/promises");
|
|
287
302
|
const nodePath = await import("node:path");
|
|
288
303
|
const artifact = nodePath.join(root, PUBLISH_OUTPUT_DIR, DOCUMENT_SET_DIR, DOCUMENT_SET_FILE);
|
|
289
304
|
await rm(artifact, { force: true }).catch((error) => {
|
|
@@ -291,6 +306,29 @@ function createDocumentSet(routerBasePath) {
|
|
|
291
306
|
});
|
|
292
307
|
if (documents.size === 0) return;
|
|
293
308
|
const clientDir = nodePath.resolve(root, clientOutputDir);
|
|
309
|
+
const label = publicDirLabel(root, publicDir, nodePath);
|
|
310
|
+
const collisions = [];
|
|
311
|
+
if (publicDir !== "") {
|
|
312
|
+
const candidates = [...documents].map(([route, file]) => ({
|
|
313
|
+
route,
|
|
314
|
+
file
|
|
315
|
+
}));
|
|
316
|
+
const committed = await whichExist(candidates.map(({ file }) => nodePath.join(publicDir, file)), access);
|
|
317
|
+
const suspects = candidates.filter((_candidate, index) => committed[index]);
|
|
318
|
+
const survived = await whichMatch(suspects.map(({ file }) => [nodePath.join(publicDir, file), nodePath.resolve(clientDir, file)]), readFile);
|
|
319
|
+
for (const [index, suspect] of suspects.entries()) {
|
|
320
|
+
if (!survived[index]) {
|
|
321
|
+
collisions.push(suspect);
|
|
322
|
+
continue;
|
|
323
|
+
}
|
|
324
|
+
documents.delete(suspect.route);
|
|
325
|
+
logWarning(`Not publishing prerendered route ${suspect.route}: it would serve the committed ${label}/${suspect.file}, which the prerender pass left untouched.`);
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
if (collisions.length > 0) {
|
|
329
|
+
const pairs = collisions.sort(compareRoutes).map(({ route, file }) => ` ${route} overwrites ${label}/${file}`);
|
|
330
|
+
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\`).`);
|
|
331
|
+
}
|
|
294
332
|
const entries = [...documents].map(([route, file]) => ({
|
|
295
333
|
route,
|
|
296
334
|
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.
|
|
131
|
+
var version = "2.19.1";
|
|
132
132
|
//#endregion
|
|
133
133
|
//#region src/logging.ts
|
|
134
134
|
const PACKAGE_NAME = "@lovable.dev/vite-tanstack-config";
|
|
@@ -174,15 +174,17 @@ function normalizeBasePath(raw) {
|
|
|
174
174
|
return trimmed.startsWith("/") ? trimmed : `/${trimmed}`;
|
|
175
175
|
}
|
|
176
176
|
function withoutBasePath(route, basePath) {
|
|
177
|
-
if (route === basePath) return "/";
|
|
178
177
|
if (basePath === "") return route;
|
|
179
|
-
|
|
178
|
+
if (route === basePath) return "/";
|
|
179
|
+
if (route.startsWith(`${basePath}/`)) return route.slice(basePath.length);
|
|
180
|
+
return route.startsWith(basePath) ? void 0 : route;
|
|
180
181
|
}
|
|
181
182
|
function documentEntryForPage(page, basePath = "") {
|
|
182
183
|
if (typeof page.prerender?.outputPath === "string") return void 0;
|
|
183
184
|
const pagePath = normalizeRoute(page.path);
|
|
184
185
|
if (pagePath === void 0) return void 0;
|
|
185
186
|
const inner = withoutBasePath(pagePath, basePath);
|
|
187
|
+
if (inner === void 0) return void 0;
|
|
186
188
|
const route = normalizeRoute(`${basePath}${inner}`);
|
|
187
189
|
if (route === void 0) return void 0;
|
|
188
190
|
const file = inner === "/" ? "index.html" : `${inner.slice(1)}/index.html`;
|
|
@@ -229,13 +231,24 @@ function serializeDocumentSet(entries, generator) {
|
|
|
229
231
|
});
|
|
230
232
|
}
|
|
231
233
|
const EXISTENCE_BATCH_SIZE = 64;
|
|
234
|
+
async function inBatches(items, run) {
|
|
235
|
+
const results = [];
|
|
236
|
+
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)));
|
|
237
|
+
return results;
|
|
238
|
+
}
|
|
232
239
|
async function whichExist(paths, access) {
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
240
|
+
return inBatches(paths, (path) => access(path).then(() => true, () => false));
|
|
241
|
+
}
|
|
242
|
+
async function whichMatch(pairs, readFile) {
|
|
243
|
+
const read = (path) => readFile(path).catch((error) => {
|
|
244
|
+
if (error.code !== "ENOENT") logWarning(`Could not read ${path} while checking prerender collisions: ${String(error)}`);
|
|
245
|
+
});
|
|
246
|
+
return inBatches(pairs, ([left, right]) => Promise.all([read(left), read(right)]).then(([a, b]) => a !== void 0 && b !== void 0 && a.equals(b)));
|
|
247
|
+
}
|
|
248
|
+
/** How the error names the public dir, which vite lets a project point anywhere. */
|
|
249
|
+
function publicDirLabel(root, publicDir, nodePath) {
|
|
250
|
+
const relative = nodePath.relative(root, publicDir);
|
|
251
|
+
return relative !== "" && !relative.startsWith("..") ? relative.split(nodePath.sep).join("/") : publicDir;
|
|
239
252
|
}
|
|
240
253
|
function createDocumentSet(routerBasePath) {
|
|
241
254
|
const basePath = normalizeBasePath(routerBasePath);
|
|
@@ -244,6 +257,7 @@ function createDocumentSet(routerBasePath) {
|
|
|
244
257
|
const documents = /* @__PURE__ */ new Map();
|
|
245
258
|
let root = process.cwd();
|
|
246
259
|
let clientOutputDir = CLIENT_OUTPUT_DIR;
|
|
260
|
+
let publicDir = "";
|
|
247
261
|
const plugin = {
|
|
248
262
|
name: DOCUMENT_SET_PLUGIN_NAME,
|
|
249
263
|
apply: "build",
|
|
@@ -255,11 +269,12 @@ function createDocumentSet(routerBasePath) {
|
|
|
255
269
|
const ours = names.indexOf(DOCUMENT_SET_PLUGIN_NAME);
|
|
256
270
|
if (theirs !== -1 && ours !== -1 && ours < theirs) logWarning(`Prerendered routes will fall back to SSR: ${DOCUMENT_SET_PLUGIN_NAME} is registered before ${TANSTACK_POST_BUILD_PLUGIN}, so the document set is written before the prerender pass runs.`);
|
|
257
271
|
clientOutputDir = config.environments?.client?.build?.outDir ?? CLIENT_OUTPUT_DIR;
|
|
272
|
+
publicDir = (config.environments?.client?.build?.copyPublicDir ?? config.build?.copyPublicDir) !== false && typeof config.publicDir === "string" ? config.publicDir : "";
|
|
258
273
|
},
|
|
259
274
|
buildApp: {
|
|
260
275
|
order: "post",
|
|
261
276
|
async handler() {
|
|
262
|
-
const { access, mkdir, rm, writeFile } = await import("node:fs/promises");
|
|
277
|
+
const { access, mkdir, readFile, rm, writeFile } = await import("node:fs/promises");
|
|
263
278
|
const nodePath = await import("node:path");
|
|
264
279
|
const artifact = nodePath.join(root, PUBLISH_OUTPUT_DIR, DOCUMENT_SET_DIR, DOCUMENT_SET_FILE);
|
|
265
280
|
await rm(artifact, { force: true }).catch((error) => {
|
|
@@ -267,6 +282,29 @@ function createDocumentSet(routerBasePath) {
|
|
|
267
282
|
});
|
|
268
283
|
if (documents.size === 0) return;
|
|
269
284
|
const clientDir = nodePath.resolve(root, clientOutputDir);
|
|
285
|
+
const label = publicDirLabel(root, publicDir, nodePath);
|
|
286
|
+
const collisions = [];
|
|
287
|
+
if (publicDir !== "") {
|
|
288
|
+
const candidates = [...documents].map(([route, file]) => ({
|
|
289
|
+
route,
|
|
290
|
+
file
|
|
291
|
+
}));
|
|
292
|
+
const committed = await whichExist(candidates.map(({ file }) => nodePath.join(publicDir, file)), access);
|
|
293
|
+
const suspects = candidates.filter((_candidate, index) => committed[index]);
|
|
294
|
+
const survived = await whichMatch(suspects.map(({ file }) => [nodePath.join(publicDir, file), nodePath.resolve(clientDir, file)]), readFile);
|
|
295
|
+
for (const [index, suspect] of suspects.entries()) {
|
|
296
|
+
if (!survived[index]) {
|
|
297
|
+
collisions.push(suspect);
|
|
298
|
+
continue;
|
|
299
|
+
}
|
|
300
|
+
documents.delete(suspect.route);
|
|
301
|
+
logWarning(`Not publishing prerendered route ${suspect.route}: it would serve the committed ${label}/${suspect.file}, which the prerender pass left untouched.`);
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
if (collisions.length > 0) {
|
|
305
|
+
const pairs = collisions.sort(compareRoutes).map(({ route, file }) => ` ${route} overwrites ${label}/${file}`);
|
|
306
|
+
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\`).`);
|
|
307
|
+
}
|
|
270
308
|
const entries = [...documents].map(([route, file]) => ({
|
|
271
309
|
route,
|
|
272
310
|
file
|