@lovable.dev/vite-tanstack-config 2.13.1 → 2.14.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/hmr-gate.cjs CHANGED
@@ -18,6 +18,25 @@ function gateStatusHeaders(req) {
18
18
  return headers;
19
19
  }
20
20
  const DEV_SERVER_MODE_EVENT = "lovable:dev-server-mode";
21
+ const BOOT_PROGRESS_EVENT = "lovable:boot-progress";
22
+ const BOOT_PROGRESS_MIN_INTERVAL_MS = 500;
23
+ function firstBuildError(error) {
24
+ if (error == null || typeof error !== "object") return null;
25
+ const errors = error.errors;
26
+ const e = Array.isArray(errors) && errors.length > 0 ? errors[0] : error;
27
+ const message = typeof e.message === "string" ? e.message : "Build failed";
28
+ let file = null;
29
+ if (typeof e.loc?.file === "string") file = e.loc.file;
30
+ else if (typeof e.id === "string") file = e.id;
31
+ return {
32
+ message,
33
+ file,
34
+ line: typeof e.loc?.line === "number" ? e.loc.line : null
35
+ };
36
+ }
37
+ function hookEnvironmentName(context) {
38
+ return context.environment?.name ?? "shared";
39
+ }
21
40
  const EDIT_FREE_RELOAD_MARKER = "edit-free";
22
41
  /** Host-controlled default for `fullReload`; an explicit option still wins. */
23
42
  const FULL_RELOAD_ENV_VAR = "LOVABLE_HMR_FULL_RELOAD";
@@ -33,6 +52,56 @@ function hmrGatePlugin(options = {}) {
33
52
  const lastFlushedHashes = /* @__PURE__ */ new Map();
34
53
  let originalEmit = null;
35
54
  let server = null;
55
+ let generation = null;
56
+ const transformsByEnv = /* @__PURE__ */ new Map();
57
+ const buildErrorsByEnv = /* @__PURE__ */ new Map();
58
+ let bootProgressSentAt = 0;
59
+ let bootProgressTimer = null;
60
+ let lastBootProgressKey = "";
61
+ function bootProgressData() {
62
+ const now = Date.now();
63
+ const idle = (name) => {
64
+ const at = transformsByEnv.get(name)?.lastTransformAt;
65
+ return at === void 0 ? null : now - at;
66
+ };
67
+ return {
68
+ ssrModules: transformsByEnv.get("ssr")?.ids.size ?? 0,
69
+ clientModules: transformsByEnv.get("client")?.ids.size ?? 0,
70
+ ssrIdleMs: idle("ssr"),
71
+ clientIdleMs: idle("client"),
72
+ buildError: buildErrorsByEnv.values().next().value ?? null
73
+ };
74
+ }
75
+ function bootProgressKey(data) {
76
+ const error = data.buildError;
77
+ const errorKey = error ? `${error.message}:${error.file ?? ""}:${error.line ?? ""}` : "";
78
+ return `${data.ssrModules}:${data.clientModules}:${errorKey}`;
79
+ }
80
+ function broadcastBootProgress() {
81
+ const data = bootProgressData();
82
+ const key = bootProgressKey(data);
83
+ if (key === lastBootProgressKey) return;
84
+ lastBootProgressKey = key;
85
+ bootProgressSentAt = Date.now();
86
+ server?.ws.send({
87
+ type: "custom",
88
+ event: BOOT_PROGRESS_EVENT,
89
+ data
90
+ });
91
+ }
92
+ function scheduleBootProgress() {
93
+ if (bootProgressTimer !== null) return;
94
+ const waitMs = bootProgressSentAt + BOOT_PROGRESS_MIN_INTERVAL_MS - Date.now();
95
+ if (waitMs <= 0) {
96
+ broadcastBootProgress();
97
+ return;
98
+ }
99
+ bootProgressTimer = setTimeout(() => {
100
+ bootProgressTimer = null;
101
+ broadcastBootProgress();
102
+ }, waitMs);
103
+ bootProgressTimer.unref?.();
104
+ }
36
105
  let classicFailOpenTimer = null;
37
106
  let transportMode = false;
38
107
  let swallowedUpdates = 0;
@@ -107,15 +176,55 @@ function hmrGatePlugin(options = {}) {
107
176
  apply: "serve",
108
177
  configResolved(config) {
109
178
  transportMode = config.experimental?.bundledDev === true;
179
+ const rawGeneration = process.env.LOVABLE_SPAWN_GENERATION;
180
+ const parsed = rawGeneration === void 0 || rawGeneration === "" ? null : Number(rawGeneration);
181
+ generation = parsed !== null && Number.isSafeInteger(parsed) ? parsed : null;
182
+ },
183
+ transform(_code, id, options) {
184
+ const name = this.environment?.name ?? (options?.ssr === true ? "ssr" : "client");
185
+ let progress = transformsByEnv.get(name);
186
+ if (!progress) {
187
+ progress = {
188
+ ids: /* @__PURE__ */ new Set(),
189
+ lastTransformAt: 0
190
+ };
191
+ transformsByEnv.set(name, progress);
192
+ }
193
+ progress.ids.add(id);
194
+ progress.lastTransformAt = Date.now();
195
+ scheduleBootProgress();
196
+ return null;
197
+ },
198
+ buildStart() {
199
+ buildErrorsByEnv.delete(hookEnvironmentName(this));
200
+ scheduleBootProgress();
201
+ },
202
+ buildEnd(error) {
203
+ const name = hookEnvironmentName(this);
204
+ const parsed = error == null ? null : firstBuildError(error);
205
+ if (parsed === null) buildErrorsByEnv.delete(name);
206
+ else buildErrorsByEnv.set(name, parsed);
207
+ scheduleBootProgress();
110
208
  },
111
209
  configureServer(srv) {
112
210
  server = srv;
211
+ transformsByEnv.clear();
212
+ buildErrorsByEnv.clear();
213
+ lastBootProgressKey = "";
113
214
  srv.ws.on?.("connection", (socket) => {
114
215
  try {
115
216
  socket.send(JSON.stringify({
116
217
  type: "custom",
117
218
  event: DEV_SERVER_MODE_EVENT,
118
- data: { mode: transportMode ? "bundled" : "classic" }
219
+ data: {
220
+ mode: transportMode ? "bundled" : "classic",
221
+ ...generation !== null ? { generation } : {}
222
+ }
223
+ }));
224
+ socket.send(JSON.stringify({
225
+ type: "custom",
226
+ event: BOOT_PROGRESS_EVENT,
227
+ data: bootProgressData()
119
228
  }));
120
229
  } catch {}
121
230
  });
@@ -333,6 +442,14 @@ function hmrGatePlugin(options = {}) {
333
442
  clearTimeout(classicFailOpenTimer);
334
443
  classicFailOpenTimer = null;
335
444
  }
445
+ if (bootProgressTimer !== null) {
446
+ clearTimeout(bootProgressTimer);
447
+ bootProgressTimer = null;
448
+ }
449
+ transformsByEnv.clear();
450
+ buildErrorsByEnv.clear();
451
+ bootProgressSentAt = 0;
452
+ lastBootProgressKey = "";
336
453
  bufferedReloadNeeded.clear();
337
454
  pendingReplay.clear();
338
455
  reloadNeededListener = null;
@@ -348,6 +465,7 @@ function hmrGatePlugin(options = {}) {
348
465
  };
349
466
  }
350
467
  //#endregion
468
+ exports.BOOT_PROGRESS_EVENT = BOOT_PROGRESS_EVENT;
351
469
  exports.DEV_SERVER_MODE_EVENT = DEV_SERVER_MODE_EVENT;
352
470
  exports.FULL_RELOAD_ENV_VAR = FULL_RELOAD_ENV_VAR;
353
471
  exports.hmrGatePlugin = hmrGatePlugin;
@@ -1,6 +1,20 @@
1
1
  import { Plugin } from "vite";
2
2
  //#region src/hmr-gate/index.d.ts
3
3
  declare const DEV_SERVER_MODE_EVENT = "lovable:dev-server-mode";
4
+ declare const BOOT_PROGRESS_EVENT = "lovable:boot-progress";
5
+ interface BootProgressData {
6
+ ssrModules: number;
7
+ clientModules: number;
8
+ /** ms since the newest transform, measured on the server's own clock so the
9
+ browser never differences two machines' timestamps. */
10
+ ssrIdleMs: number | null;
11
+ clientIdleMs: number | null;
12
+ buildError: {
13
+ message: string;
14
+ file: string | null;
15
+ line: number | null;
16
+ } | null;
17
+ }
4
18
  /** Host-controlled default for `fullReload`; an explicit option still wins. */
5
19
  declare const FULL_RELOAD_ENV_VAR = "LOVABLE_HMR_FULL_RELOAD";
6
20
  interface HmrGateOptions {
@@ -24,4 +38,4 @@ interface HmrGateOptions {
24
38
  }
25
39
  declare function hmrGatePlugin(options?: HmrGateOptions): Plugin;
26
40
  //#endregion
27
- export { DEV_SERVER_MODE_EVENT, FULL_RELOAD_ENV_VAR, HmrGateOptions, hmrGatePlugin };
41
+ export { BOOT_PROGRESS_EVENT, BootProgressData, DEV_SERVER_MODE_EVENT, FULL_RELOAD_ENV_VAR, HmrGateOptions, hmrGatePlugin };
@@ -1,6 +1,20 @@
1
1
  import { Plugin } from "vite";
2
2
  //#region src/hmr-gate/index.d.ts
3
3
  declare const DEV_SERVER_MODE_EVENT = "lovable:dev-server-mode";
4
+ declare const BOOT_PROGRESS_EVENT = "lovable:boot-progress";
5
+ interface BootProgressData {
6
+ ssrModules: number;
7
+ clientModules: number;
8
+ /** ms since the newest transform, measured on the server's own clock so the
9
+ browser never differences two machines' timestamps. */
10
+ ssrIdleMs: number | null;
11
+ clientIdleMs: number | null;
12
+ buildError: {
13
+ message: string;
14
+ file: string | null;
15
+ line: number | null;
16
+ } | null;
17
+ }
4
18
  /** Host-controlled default for `fullReload`; an explicit option still wins. */
5
19
  declare const FULL_RELOAD_ENV_VAR = "LOVABLE_HMR_FULL_RELOAD";
6
20
  interface HmrGateOptions {
@@ -24,4 +38,4 @@ interface HmrGateOptions {
24
38
  }
25
39
  declare function hmrGatePlugin(options?: HmrGateOptions): Plugin;
26
40
  //#endregion
27
- export { DEV_SERVER_MODE_EVENT, FULL_RELOAD_ENV_VAR, HmrGateOptions, hmrGatePlugin };
41
+ export { BOOT_PROGRESS_EVENT, BootProgressData, DEV_SERVER_MODE_EVENT, FULL_RELOAD_ENV_VAR, HmrGateOptions, hmrGatePlugin };
package/dist/hmr-gate.js CHANGED
@@ -17,6 +17,25 @@ function gateStatusHeaders(req) {
17
17
  return headers;
18
18
  }
19
19
  const DEV_SERVER_MODE_EVENT = "lovable:dev-server-mode";
20
+ const BOOT_PROGRESS_EVENT = "lovable:boot-progress";
21
+ const BOOT_PROGRESS_MIN_INTERVAL_MS = 500;
22
+ function firstBuildError(error) {
23
+ if (error == null || typeof error !== "object") return null;
24
+ const errors = error.errors;
25
+ const e = Array.isArray(errors) && errors.length > 0 ? errors[0] : error;
26
+ const message = typeof e.message === "string" ? e.message : "Build failed";
27
+ let file = null;
28
+ if (typeof e.loc?.file === "string") file = e.loc.file;
29
+ else if (typeof e.id === "string") file = e.id;
30
+ return {
31
+ message,
32
+ file,
33
+ line: typeof e.loc?.line === "number" ? e.loc.line : null
34
+ };
35
+ }
36
+ function hookEnvironmentName(context) {
37
+ return context.environment?.name ?? "shared";
38
+ }
20
39
  const EDIT_FREE_RELOAD_MARKER = "edit-free";
21
40
  /** Host-controlled default for `fullReload`; an explicit option still wins. */
22
41
  const FULL_RELOAD_ENV_VAR = "LOVABLE_HMR_FULL_RELOAD";
@@ -32,6 +51,56 @@ function hmrGatePlugin(options = {}) {
32
51
  const lastFlushedHashes = /* @__PURE__ */ new Map();
33
52
  let originalEmit = null;
34
53
  let server = null;
54
+ let generation = null;
55
+ const transformsByEnv = /* @__PURE__ */ new Map();
56
+ const buildErrorsByEnv = /* @__PURE__ */ new Map();
57
+ let bootProgressSentAt = 0;
58
+ let bootProgressTimer = null;
59
+ let lastBootProgressKey = "";
60
+ function bootProgressData() {
61
+ const now = Date.now();
62
+ const idle = (name) => {
63
+ const at = transformsByEnv.get(name)?.lastTransformAt;
64
+ return at === void 0 ? null : now - at;
65
+ };
66
+ return {
67
+ ssrModules: transformsByEnv.get("ssr")?.ids.size ?? 0,
68
+ clientModules: transformsByEnv.get("client")?.ids.size ?? 0,
69
+ ssrIdleMs: idle("ssr"),
70
+ clientIdleMs: idle("client"),
71
+ buildError: buildErrorsByEnv.values().next().value ?? null
72
+ };
73
+ }
74
+ function bootProgressKey(data) {
75
+ const error = data.buildError;
76
+ const errorKey = error ? `${error.message}:${error.file ?? ""}:${error.line ?? ""}` : "";
77
+ return `${data.ssrModules}:${data.clientModules}:${errorKey}`;
78
+ }
79
+ function broadcastBootProgress() {
80
+ const data = bootProgressData();
81
+ const key = bootProgressKey(data);
82
+ if (key === lastBootProgressKey) return;
83
+ lastBootProgressKey = key;
84
+ bootProgressSentAt = Date.now();
85
+ server?.ws.send({
86
+ type: "custom",
87
+ event: BOOT_PROGRESS_EVENT,
88
+ data
89
+ });
90
+ }
91
+ function scheduleBootProgress() {
92
+ if (bootProgressTimer !== null) return;
93
+ const waitMs = bootProgressSentAt + BOOT_PROGRESS_MIN_INTERVAL_MS - Date.now();
94
+ if (waitMs <= 0) {
95
+ broadcastBootProgress();
96
+ return;
97
+ }
98
+ bootProgressTimer = setTimeout(() => {
99
+ bootProgressTimer = null;
100
+ broadcastBootProgress();
101
+ }, waitMs);
102
+ bootProgressTimer.unref?.();
103
+ }
35
104
  let classicFailOpenTimer = null;
36
105
  let transportMode = false;
37
106
  let swallowedUpdates = 0;
@@ -106,15 +175,55 @@ function hmrGatePlugin(options = {}) {
106
175
  apply: "serve",
107
176
  configResolved(config) {
108
177
  transportMode = config.experimental?.bundledDev === true;
178
+ const rawGeneration = process.env.LOVABLE_SPAWN_GENERATION;
179
+ const parsed = rawGeneration === void 0 || rawGeneration === "" ? null : Number(rawGeneration);
180
+ generation = parsed !== null && Number.isSafeInteger(parsed) ? parsed : null;
181
+ },
182
+ transform(_code, id, options) {
183
+ const name = this.environment?.name ?? (options?.ssr === true ? "ssr" : "client");
184
+ let progress = transformsByEnv.get(name);
185
+ if (!progress) {
186
+ progress = {
187
+ ids: /* @__PURE__ */ new Set(),
188
+ lastTransformAt: 0
189
+ };
190
+ transformsByEnv.set(name, progress);
191
+ }
192
+ progress.ids.add(id);
193
+ progress.lastTransformAt = Date.now();
194
+ scheduleBootProgress();
195
+ return null;
196
+ },
197
+ buildStart() {
198
+ buildErrorsByEnv.delete(hookEnvironmentName(this));
199
+ scheduleBootProgress();
200
+ },
201
+ buildEnd(error) {
202
+ const name = hookEnvironmentName(this);
203
+ const parsed = error == null ? null : firstBuildError(error);
204
+ if (parsed === null) buildErrorsByEnv.delete(name);
205
+ else buildErrorsByEnv.set(name, parsed);
206
+ scheduleBootProgress();
109
207
  },
110
208
  configureServer(srv) {
111
209
  server = srv;
210
+ transformsByEnv.clear();
211
+ buildErrorsByEnv.clear();
212
+ lastBootProgressKey = "";
112
213
  srv.ws.on?.("connection", (socket) => {
113
214
  try {
114
215
  socket.send(JSON.stringify({
115
216
  type: "custom",
116
217
  event: DEV_SERVER_MODE_EVENT,
117
- data: { mode: transportMode ? "bundled" : "classic" }
218
+ data: {
219
+ mode: transportMode ? "bundled" : "classic",
220
+ ...generation !== null ? { generation } : {}
221
+ }
222
+ }));
223
+ socket.send(JSON.stringify({
224
+ type: "custom",
225
+ event: BOOT_PROGRESS_EVENT,
226
+ data: bootProgressData()
118
227
  }));
119
228
  } catch {}
120
229
  });
@@ -332,6 +441,14 @@ function hmrGatePlugin(options = {}) {
332
441
  clearTimeout(classicFailOpenTimer);
333
442
  classicFailOpenTimer = null;
334
443
  }
444
+ if (bootProgressTimer !== null) {
445
+ clearTimeout(bootProgressTimer);
446
+ bootProgressTimer = null;
447
+ }
448
+ transformsByEnv.clear();
449
+ buildErrorsByEnv.clear();
450
+ bootProgressSentAt = 0;
451
+ lastBootProgressKey = "";
335
452
  bufferedReloadNeeded.clear();
336
453
  pendingReplay.clear();
337
454
  reloadNeededListener = null;
@@ -347,4 +464,4 @@ function hmrGatePlugin(options = {}) {
347
464
  };
348
465
  }
349
466
  //#endregion
350
- export { DEV_SERVER_MODE_EVENT, FULL_RELOAD_ENV_VAR, hmrGatePlugin };
467
+ export { BOOT_PROGRESS_EVENT, DEV_SERVER_MODE_EVENT, FULL_RELOAD_ENV_VAR, hmrGatePlugin };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lovable.dev/vite-tanstack-config",
3
- "version": "2.13.1",
3
+ "version": "2.14.0",
4
4
  "description": "Vite config wrapper for Lovable TanStack Start projects",
5
5
  "main": "./dist/index.cjs",
6
6
  "module": "./dist/index.js",