litestar-vite-plugin 0.15.0-alpha.7 → 0.15.0-beta.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/README.md +1 -1
- package/dist/js/index.d.ts +72 -6
- package/dist/js/index.js +101 -47
- package/dist/js/shared/format-path.d.ts +22 -0
- package/dist/js/shared/format-path.js +24 -0
- package/dist/js/shared/logger.d.ts +43 -0
- package/dist/js/shared/logger.js +59 -0
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -160,7 +160,7 @@ litestar assets generate-types # one-off or CI
|
|
|
160
160
|
|
|
161
161
|
- Prints Python vs Vite config snapshot (asset URLs, bundle/hot paths, ports, modes).
|
|
162
162
|
- Flags missing hot file (dev proxy), missing manifest (prod), type-gen exports, env/config mismatches, and plugin install issues.
|
|
163
|
-
- `--fix` can rewrite simple vite.config values (assetUrl,
|
|
163
|
+
- `--fix` can rewrite simple vite.config values (assetUrl, bundleDir, hotFile, type paths) after creating a backup.
|
|
164
164
|
|
|
165
165
|
## Links
|
|
166
166
|
|
package/dist/js/index.d.ts
CHANGED
|
@@ -54,6 +54,16 @@ export interface TypesConfig {
|
|
|
54
54
|
* @default false
|
|
55
55
|
*/
|
|
56
56
|
generateSdk?: boolean;
|
|
57
|
+
/**
|
|
58
|
+
* Register route() function globally on window object.
|
|
59
|
+
*
|
|
60
|
+
* When true, the generated routes.ts will include code that registers
|
|
61
|
+
* the type-safe route() function on `window.route`, similar to Laravel's
|
|
62
|
+
* Ziggy library. This allows using route() without imports.
|
|
63
|
+
*
|
|
64
|
+
* @default false
|
|
65
|
+
*/
|
|
66
|
+
globalRoute?: boolean;
|
|
57
67
|
/**
|
|
58
68
|
* Debounce time in milliseconds for type regeneration.
|
|
59
69
|
* Prevents regeneration from running too frequently when
|
|
@@ -79,7 +89,7 @@ export interface PluginConfig {
|
|
|
79
89
|
*
|
|
80
90
|
* @default 'public/dist'
|
|
81
91
|
*/
|
|
82
|
-
|
|
92
|
+
bundleDir?: string;
|
|
83
93
|
/**
|
|
84
94
|
* Vite's public directory for static, unprocessed assets.
|
|
85
95
|
* Mirrors Vite's `publicDir` option.
|
|
@@ -90,13 +100,13 @@ export interface PluginConfig {
|
|
|
90
100
|
/**
|
|
91
101
|
* Litestar's public assets directory. These are the assets that Vite will serve when developing.
|
|
92
102
|
*
|
|
93
|
-
* @default '
|
|
103
|
+
* @default 'src'
|
|
94
104
|
*/
|
|
95
|
-
|
|
105
|
+
resourceDir?: string;
|
|
96
106
|
/**
|
|
97
107
|
* The path to the "hot" file.
|
|
98
108
|
*
|
|
99
|
-
* @default `${
|
|
109
|
+
* @default `${bundleDir}/hot`
|
|
100
110
|
*/
|
|
101
111
|
hotFile?: string;
|
|
102
112
|
/**
|
|
@@ -106,9 +116,9 @@ export interface PluginConfig {
|
|
|
106
116
|
/**
|
|
107
117
|
* The directory where the SSR bundle should be written.
|
|
108
118
|
*
|
|
109
|
-
* @default '${
|
|
119
|
+
* @default '${bundleDir}/bootstrap/ssr'
|
|
110
120
|
*/
|
|
111
|
-
|
|
121
|
+
ssrOutDir?: string;
|
|
112
122
|
/**
|
|
113
123
|
* Configuration for performing full page refresh on python (or other) file changes.
|
|
114
124
|
*
|
|
@@ -128,6 +138,18 @@ export interface PluginConfig {
|
|
|
128
138
|
* @default true
|
|
129
139
|
*/
|
|
130
140
|
autoDetectIndex?: boolean;
|
|
141
|
+
/**
|
|
142
|
+
* Enable Inertia mode, which disables index.html auto-detection.
|
|
143
|
+
*
|
|
144
|
+
* In Inertia apps, the backend (Litestar) serves all HTML responses.
|
|
145
|
+
* When enabled, direct access to the Vite dev server will show a placeholder
|
|
146
|
+
* page directing users to access the app through the backend.
|
|
147
|
+
*
|
|
148
|
+
* Auto-detected from `.litestar.json` when mode is "inertia".
|
|
149
|
+
*
|
|
150
|
+
* @default false (auto-detected from .litestar.json)
|
|
151
|
+
*/
|
|
152
|
+
inertiaMode?: boolean;
|
|
131
153
|
/**
|
|
132
154
|
* Transform the code while serving.
|
|
133
155
|
*/
|
|
@@ -193,6 +215,50 @@ interface RefreshConfig {
|
|
|
193
215
|
paths: string[];
|
|
194
216
|
config?: FullReloadConfig;
|
|
195
217
|
}
|
|
218
|
+
/**
|
|
219
|
+
* Bridge schema for `.litestar.json` - the shared configuration contract
|
|
220
|
+
* between Python (Litestar) and TypeScript (Vite plugin).
|
|
221
|
+
*
|
|
222
|
+
* Python writes this file on startup; TypeScript reads it as defaults.
|
|
223
|
+
* Field names use camelCase (JavaScript convention) and match exactly
|
|
224
|
+
* between the JSON file and this TypeScript interface.
|
|
225
|
+
*
|
|
226
|
+
* Precedence: vite.config.ts > .litestar.json > hardcoded defaults
|
|
227
|
+
*/
|
|
228
|
+
export interface BridgeSchema {
|
|
229
|
+
assetUrl: string;
|
|
230
|
+
bundleDir: string;
|
|
231
|
+
resourceDir: string;
|
|
232
|
+
publicDir: string;
|
|
233
|
+
hotFile: string;
|
|
234
|
+
manifest: string;
|
|
235
|
+
mode: "spa" | "inertia" | "ssr" | "hybrid";
|
|
236
|
+
proxyMode: "vite_proxy" | "vite_direct" | "external_proxy";
|
|
237
|
+
host: string;
|
|
238
|
+
port: number;
|
|
239
|
+
protocol: "http" | "https";
|
|
240
|
+
ssrEnabled: boolean;
|
|
241
|
+
ssrOutDir: string | null;
|
|
242
|
+
types: {
|
|
243
|
+
enabled: boolean;
|
|
244
|
+
output: string;
|
|
245
|
+
openapiPath: string;
|
|
246
|
+
routesPath: string;
|
|
247
|
+
pagePropsPath?: string;
|
|
248
|
+
generateZod: boolean;
|
|
249
|
+
generateSdk: boolean;
|
|
250
|
+
globalRoute: boolean;
|
|
251
|
+
} | null;
|
|
252
|
+
executor: "node" | "bun" | "deno" | "yarn" | "pnpm";
|
|
253
|
+
logging: {
|
|
254
|
+
level: "quiet" | "normal" | "verbose";
|
|
255
|
+
showPathsAbsolute: boolean;
|
|
256
|
+
suppressNpmOutput: boolean;
|
|
257
|
+
suppressViteBanner: boolean;
|
|
258
|
+
timestamps: boolean;
|
|
259
|
+
} | null;
|
|
260
|
+
litestarVersion: string;
|
|
261
|
+
}
|
|
196
262
|
type DevServerUrl = `${"http" | "https"}://${string}:${number}`;
|
|
197
263
|
export declare const refreshPaths: string[];
|
|
198
264
|
/**
|
package/dist/js/index.js
CHANGED
|
@@ -10,6 +10,8 @@ import fullReload from "vite-plugin-full-reload";
|
|
|
10
10
|
import { resolveInstallHint, resolvePackageExecutor } from "./install-hint.js";
|
|
11
11
|
import { checkBackendAvailability, loadLitestarMeta } from "./litestar-meta.js";
|
|
12
12
|
import { debounce } from "./shared/debounce.js";
|
|
13
|
+
import { formatPath } from "./shared/format-path.js";
|
|
14
|
+
import { createLogger } from "./shared/logger.js";
|
|
13
15
|
const execAsync = promisify(exec);
|
|
14
16
|
let exitHandlersBound = false;
|
|
15
17
|
let warnedMissingRuntimeConfig = false;
|
|
@@ -23,16 +25,19 @@ function litestar(config) {
|
|
|
23
25
|
return plugins;
|
|
24
26
|
}
|
|
25
27
|
async function findIndexHtmlPath(server, pluginConfig) {
|
|
28
|
+
if (pluginConfig.inertiaMode) {
|
|
29
|
+
return null;
|
|
30
|
+
}
|
|
26
31
|
if (!pluginConfig.autoDetectIndex) {
|
|
27
32
|
return null;
|
|
28
33
|
}
|
|
29
34
|
const root = server.config.root;
|
|
30
35
|
const possiblePaths = [
|
|
31
36
|
path.join(root, "index.html"),
|
|
32
|
-
path.join(root, pluginConfig.
|
|
33
|
-
// Ensure
|
|
37
|
+
path.join(root, pluginConfig.resourceDir.replace(/^\//, ""), "index.html"),
|
|
38
|
+
// Ensure resourceDir path is relative to root
|
|
34
39
|
path.join(root, pluginConfig.publicDir.replace(/^\//, ""), "index.html"),
|
|
35
|
-
path.join(root, pluginConfig.
|
|
40
|
+
path.join(root, pluginConfig.bundleDir.replace(/^\//, ""), "index.html")
|
|
36
41
|
];
|
|
37
42
|
for (const indexPath of possiblePaths) {
|
|
38
43
|
try {
|
|
@@ -63,8 +68,9 @@ function resolveLitestarPlugin(pluginConfig) {
|
|
|
63
68
|
let shuttingDown = false;
|
|
64
69
|
const pythonDefaults = loadPythonDefaults();
|
|
65
70
|
const proxyMode = pythonDefaults?.proxyMode ?? "vite_proxy";
|
|
71
|
+
const logger = createLogger(pythonDefaults?.logging);
|
|
66
72
|
const defaultAliases = {
|
|
67
|
-
"@": `/${pluginConfig.
|
|
73
|
+
"@": `/${pluginConfig.resourceDir.replace(/^\/+/, "").replace(/\/+$/, "")}/`
|
|
68
74
|
};
|
|
69
75
|
return {
|
|
70
76
|
name: "litestar",
|
|
@@ -195,9 +201,9 @@ function resolveLitestarPlugin(pluginConfig) {
|
|
|
195
201
|
resolvedConfig.logger.warn(formatMissingConfigWarning());
|
|
196
202
|
}
|
|
197
203
|
}
|
|
198
|
-
const
|
|
199
|
-
if (!fs.existsSync(
|
|
200
|
-
resolvedConfig.logger.warn(`${colors.cyan("litestar-vite")} ${colors.yellow("Resource directory not found:")} ${pluginConfig.
|
|
204
|
+
const resourceDirPath = path.resolve(resolvedConfig.root, pluginConfig.resourceDir);
|
|
205
|
+
if (!fs.existsSync(resourceDirPath) && typeof resolvedConfig.logger?.warn === "function") {
|
|
206
|
+
resolvedConfig.logger.warn(`${colors.cyan("litestar-vite")} ${colors.yellow("Resource directory not found:")} ${pluginConfig.resourceDir}`);
|
|
201
207
|
}
|
|
202
208
|
const hint = pluginConfig.types !== false ? pluginConfig.types.routesPath : void 0;
|
|
203
209
|
litestarMeta = await loadLitestarMeta(resolvedConfig, hint);
|
|
@@ -229,19 +235,20 @@ function resolveLitestarPlugin(pluginConfig) {
|
|
|
229
235
|
fs.writeFileSync(pluginConfig.hotFile, viteDevServerUrl);
|
|
230
236
|
}
|
|
231
237
|
setTimeout(async () => {
|
|
232
|
-
|
|
238
|
+
if (logger.config.level === "quiet") return;
|
|
239
|
+
const litestarVersion = litestarMeta.litestarVersion ?? process.env.LITESTAR_VERSION ?? "unknown";
|
|
233
240
|
const backendStatus = await checkBackendAvailability(appUrl);
|
|
234
241
|
resolvedConfig.logger.info(`
|
|
235
|
-
${colors.red(`${colors.bold("LITESTAR")} ${
|
|
242
|
+
${colors.red(`${colors.bold("LITESTAR")} ${litestarVersion}`)}`);
|
|
236
243
|
resolvedConfig.logger.info("");
|
|
237
244
|
if (initialIndexPath) {
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
245
|
+
const relIndexPath = logger.path(initialIndexPath, server.config.root);
|
|
246
|
+
resolvedConfig.logger.info(` ${colors.green("\u279C")} ${colors.bold("Mode")}: SPA (${colors.cyan(relIndexPath)})`);
|
|
247
|
+
} else if (pluginConfig.inertiaMode) {
|
|
248
|
+
resolvedConfig.logger.info(` ${colors.green("\u279C")} ${colors.bold("Mode")}: Inertia`);
|
|
241
249
|
} else {
|
|
242
|
-
resolvedConfig.logger.info(` ${colors.green("\u279C")} ${colors.bold("
|
|
250
|
+
resolvedConfig.logger.info(` ${colors.green("\u279C")} ${colors.bold("Mode")}: Litestar`);
|
|
243
251
|
}
|
|
244
|
-
resolvedConfig.logger.info(` ${colors.green("\u279C")} ${colors.bold("Dev Server")}: ${colors.cyan(viteDevServerUrl)}`);
|
|
245
252
|
if (backendStatus.available) {
|
|
246
253
|
resolvedConfig.logger.info(
|
|
247
254
|
` ${colors.green("\u279C")} ${colors.bold("App URL")}: ${colors.cyan(appUrl.replace(/:(\d+)/, (_, port) => `:${colors.bold(port)}`))} ${colors.green("\u2713")}`
|
|
@@ -251,12 +258,13 @@ function resolveLitestarPlugin(pluginConfig) {
|
|
|
251
258
|
` ${colors.yellow("\u279C")} ${colors.bold("App URL")}: ${colors.cyan(appUrl.replace(/:(\d+)/, (_, port) => `:${colors.bold(port)}`))} ${colors.yellow("\u26A0")}`
|
|
252
259
|
);
|
|
253
260
|
}
|
|
254
|
-
resolvedConfig.logger.info(` ${colors.green("\u279C")} ${colors.bold("
|
|
261
|
+
resolvedConfig.logger.info(` ${colors.green("\u279C")} ${colors.bold("Dev Server")}: ${colors.cyan(viteDevServerUrl)}`);
|
|
255
262
|
if (pluginConfig.types !== false && pluginConfig.types.enabled) {
|
|
256
263
|
const openapiExists = fs.existsSync(path.resolve(process.cwd(), pluginConfig.types.openapiPath));
|
|
257
264
|
const routesExists = fs.existsSync(path.resolve(process.cwd(), pluginConfig.types.routesPath));
|
|
265
|
+
const relTypesOutput = logger.path(pluginConfig.types.output, process.cwd());
|
|
258
266
|
if (openapiExists || routesExists) {
|
|
259
|
-
resolvedConfig.logger.info(` ${colors.green("\u279C")} ${colors.bold("Type Gen")}: ${colors.
|
|
267
|
+
resolvedConfig.logger.info(` ${colors.green("\u279C")} ${colors.bold("Type Gen")}: ${colors.dim(`${relTypesOutput}/`)}`);
|
|
260
268
|
} else {
|
|
261
269
|
resolvedConfig.logger.info(` ${colors.yellow("\u279C")} ${colors.bold("Type Gen")}: ${colors.yellow("waiting")} ${colors.dim("(no schema files yet)")}`);
|
|
262
270
|
}
|
|
@@ -413,7 +421,7 @@ function formatMissingConfigWarning() {
|
|
|
413
421
|
`${y("\u2502")} ${d("litestar({")} ${y("\u2502")}`,
|
|
414
422
|
`${y("\u2502")} ${d(' input: ["src/main.tsx"],')} ${y("\u2502")}`,
|
|
415
423
|
`${y("\u2502")} ${d(' assetUrl: "/static/",')} ${y("\u2502")}`,
|
|
416
|
-
`${y("\u2502")} ${d('
|
|
424
|
+
`${y("\u2502")} ${d(' bundleDir: "public",')} ${y("\u2502")}`,
|
|
417
425
|
`${y("\u2502")} ${d(" types: false,")} ${y("\u2502")}`,
|
|
418
426
|
`${y("\u2502")} ${d("})")} ${y("\u2502")}`,
|
|
419
427
|
`${y("\u2502")} ${y("\u2502")}`,
|
|
@@ -440,16 +448,16 @@ function resolvePluginConfig(config) {
|
|
|
440
448
|
if (typeof resolvedConfig.input === "undefined") {
|
|
441
449
|
throw new Error('litestar-vite-plugin: missing configuration for "input".');
|
|
442
450
|
}
|
|
443
|
-
if (typeof resolvedConfig.
|
|
444
|
-
resolvedConfig.
|
|
445
|
-
if (resolvedConfig.
|
|
446
|
-
throw new Error("litestar-vite-plugin:
|
|
451
|
+
if (typeof resolvedConfig.resourceDir === "string") {
|
|
452
|
+
resolvedConfig.resourceDir = resolvedConfig.resourceDir.trim().replace(/^\/+/, "").replace(/\/+$/, "");
|
|
453
|
+
if (resolvedConfig.resourceDir === "") {
|
|
454
|
+
throw new Error("litestar-vite-plugin: resourceDir must be a subdirectory. E.g. 'resources'.");
|
|
447
455
|
}
|
|
448
456
|
}
|
|
449
|
-
if (typeof resolvedConfig.
|
|
450
|
-
resolvedConfig.
|
|
451
|
-
if (resolvedConfig.
|
|
452
|
-
throw new Error("litestar-vite-plugin:
|
|
457
|
+
if (typeof resolvedConfig.bundleDir === "string") {
|
|
458
|
+
resolvedConfig.bundleDir = resolvedConfig.bundleDir.trim().replace(/^\/+/, "").replace(/\/+$/, "");
|
|
459
|
+
if (resolvedConfig.bundleDir === "") {
|
|
460
|
+
throw new Error("litestar-vite-plugin: bundleDir must be a subdirectory. E.g. 'public'.");
|
|
453
461
|
}
|
|
454
462
|
}
|
|
455
463
|
if (typeof resolvedConfig.publicDir === "string") {
|
|
@@ -458,8 +466,8 @@ function resolvePluginConfig(config) {
|
|
|
458
466
|
throw new Error("litestar-vite-plugin: publicDir must be a subdirectory. E.g. 'public'.");
|
|
459
467
|
}
|
|
460
468
|
}
|
|
461
|
-
if (typeof resolvedConfig.
|
|
462
|
-
resolvedConfig.
|
|
469
|
+
if (typeof resolvedConfig.ssrOutDir === "string") {
|
|
470
|
+
resolvedConfig.ssrOutDir = resolvedConfig.ssrOutDir.trim().replace(/^\/+/, "").replace(/\/+$/, "");
|
|
463
471
|
}
|
|
464
472
|
if (resolvedConfig.refresh === true) {
|
|
465
473
|
resolvedConfig.refresh = [{ paths: refreshPaths }];
|
|
@@ -475,6 +483,7 @@ function resolvePluginConfig(config) {
|
|
|
475
483
|
pagePropsPath: "src/generated/inertia-pages.json",
|
|
476
484
|
generateZod: false,
|
|
477
485
|
generateSdk: false,
|
|
486
|
+
globalRoute: false,
|
|
478
487
|
debounce: 300
|
|
479
488
|
};
|
|
480
489
|
} else if (resolvedConfig.types === "auto" || typeof resolvedConfig.types === "undefined") {
|
|
@@ -487,6 +496,7 @@ function resolvePluginConfig(config) {
|
|
|
487
496
|
pagePropsPath: pythonDefaults.types.pagePropsPath ?? path.join(pythonDefaults.types.output, "inertia-pages.json"),
|
|
488
497
|
generateZod: pythonDefaults.types.generateZod,
|
|
489
498
|
generateSdk: pythonDefaults.types.generateSdk,
|
|
499
|
+
globalRoute: pythonDefaults.types.globalRoute ?? false,
|
|
490
500
|
debounce: 300
|
|
491
501
|
};
|
|
492
502
|
}
|
|
@@ -502,6 +512,7 @@ function resolvePluginConfig(config) {
|
|
|
502
512
|
pagePropsPath: resolvedConfig.types.pagePropsPath ?? (resolvedConfig.types.output ? path.join(resolvedConfig.types.output, "inertia-pages.json") : "src/generated/inertia-pages.json"),
|
|
503
513
|
generateZod: resolvedConfig.types.generateZod ?? false,
|
|
504
514
|
generateSdk: resolvedConfig.types.generateSdk ?? false,
|
|
515
|
+
globalRoute: resolvedConfig.types.globalRoute ?? false,
|
|
505
516
|
debounce: resolvedConfig.types.debounce ?? 300
|
|
506
517
|
};
|
|
507
518
|
if (!userProvidedOpenapi && resolvedConfig.types.output) {
|
|
@@ -514,23 +525,55 @@ function resolvePluginConfig(config) {
|
|
|
514
525
|
typesConfig.pagePropsPath = path.join(typesConfig.output, "inertia-pages.json");
|
|
515
526
|
}
|
|
516
527
|
}
|
|
517
|
-
|
|
528
|
+
const inertiaMode = resolvedConfig.inertiaMode ?? pythonDefaults?.mode === "inertia";
|
|
529
|
+
const result = {
|
|
518
530
|
input: resolvedConfig.input,
|
|
519
531
|
assetUrl: normalizeAssetUrl(resolvedConfig.assetUrl ?? pythonDefaults?.assetUrl ?? "/static/"),
|
|
520
|
-
|
|
521
|
-
|
|
532
|
+
resourceDir: resolvedConfig.resourceDir ?? pythonDefaults?.resourceDir ?? "src",
|
|
533
|
+
bundleDir: resolvedConfig.bundleDir ?? pythonDefaults?.bundleDir ?? "public",
|
|
522
534
|
publicDir: resolvedConfig.publicDir ?? pythonDefaults?.publicDir ?? "public",
|
|
523
535
|
ssr: resolvedConfig.ssr ?? resolvedConfig.input,
|
|
524
|
-
|
|
536
|
+
ssrOutDir: resolvedConfig.ssrOutDir ?? pythonDefaults?.ssrOutDir ?? path.join(resolvedConfig.resourceDir ?? pythonDefaults?.resourceDir ?? "src", "bootstrap/ssr"),
|
|
525
537
|
refresh: resolvedConfig.refresh ?? false,
|
|
526
|
-
hotFile: resolvedConfig.hotFile ?? path.join(resolvedConfig.
|
|
538
|
+
hotFile: resolvedConfig.hotFile ?? path.join(resolvedConfig.bundleDir ?? "public", "hot"),
|
|
527
539
|
detectTls: resolvedConfig.detectTls ?? false,
|
|
528
540
|
autoDetectIndex: resolvedConfig.autoDetectIndex ?? true,
|
|
541
|
+
inertiaMode,
|
|
529
542
|
transformOnServe: resolvedConfig.transformOnServe ?? ((code) => code),
|
|
530
543
|
types: typesConfig,
|
|
531
544
|
executor: resolvedConfig.executor ?? pythonDefaults?.executor,
|
|
532
545
|
hasPythonConfig: pythonDefaults !== null
|
|
533
546
|
};
|
|
547
|
+
validateAgainstPythonDefaults(result, pythonDefaults, resolvedConfig);
|
|
548
|
+
return result;
|
|
549
|
+
}
|
|
550
|
+
function validateAgainstPythonDefaults(resolved, pythonDefaults, userConfig) {
|
|
551
|
+
if (!pythonDefaults) return;
|
|
552
|
+
const warnings = [];
|
|
553
|
+
const hasPythonValue = (value) => typeof value === "string" && value.length > 0;
|
|
554
|
+
if (userConfig.assetUrl !== void 0 && hasPythonValue(pythonDefaults.assetUrl) && resolved.assetUrl !== pythonDefaults.assetUrl) {
|
|
555
|
+
warnings.push(`assetUrl: vite.config.ts="${resolved.assetUrl}" differs from Python="${pythonDefaults.assetUrl}"`);
|
|
556
|
+
}
|
|
557
|
+
if (userConfig.bundleDir !== void 0 && hasPythonValue(pythonDefaults.bundleDir) && resolved.bundleDir !== pythonDefaults.bundleDir) {
|
|
558
|
+
warnings.push(`bundleDir: vite.config.ts="${resolved.bundleDir}" differs from Python="${pythonDefaults.bundleDir}"`);
|
|
559
|
+
}
|
|
560
|
+
if (userConfig.resourceDir !== void 0 && hasPythonValue(pythonDefaults.resourceDir) && resolved.resourceDir !== pythonDefaults.resourceDir) {
|
|
561
|
+
warnings.push(`resourceDir: vite.config.ts="${resolved.resourceDir}" differs from Python="${pythonDefaults.resourceDir}"`);
|
|
562
|
+
}
|
|
563
|
+
if (userConfig.publicDir !== void 0 && hasPythonValue(pythonDefaults.publicDir) && resolved.publicDir !== pythonDefaults.publicDir) {
|
|
564
|
+
warnings.push(`publicDir: vite.config.ts="${resolved.publicDir}" differs from Python="${pythonDefaults.publicDir}"`);
|
|
565
|
+
}
|
|
566
|
+
if (pythonDefaults.ssrEnabled && userConfig.ssrOutDir !== void 0 && hasPythonValue(pythonDefaults.ssrOutDir) && resolved.ssrOutDir !== pythonDefaults.ssrOutDir) {
|
|
567
|
+
warnings.push(`ssrOutDir: vite.config.ts="${resolved.ssrOutDir}" differs from Python="${pythonDefaults.ssrOutDir}"`);
|
|
568
|
+
}
|
|
569
|
+
if (warnings.length > 0) {
|
|
570
|
+
console.warn(
|
|
571
|
+
colors.yellow("[litestar-vite] Configuration mismatch detected:\n") + warnings.map((w) => ` ${colors.dim("\u2022")} ${w}`).join("\n") + `
|
|
572
|
+
|
|
573
|
+
${colors.dim("Precedence: vite.config.ts > .litestar.json > defaults")}
|
|
574
|
+
` + colors.dim("See: https://docs.litestar.dev/vite/config-precedence\n")
|
|
575
|
+
);
|
|
576
|
+
}
|
|
534
577
|
}
|
|
535
578
|
function resolveBase(_config, assetUrl) {
|
|
536
579
|
if (process.env.NODE_ENV === "development") {
|
|
@@ -546,9 +589,9 @@ function resolveInput(config, ssr) {
|
|
|
546
589
|
}
|
|
547
590
|
function resolveOutDir(config, ssr) {
|
|
548
591
|
if (ssr) {
|
|
549
|
-
return config.
|
|
592
|
+
return config.ssrOutDir.replace(/^\/+/, "").replace(/\/+$/, "");
|
|
550
593
|
}
|
|
551
|
-
return config.
|
|
594
|
+
return config.bundleDir.replace(/^\/+/, "").replace(/\/+$/, "");
|
|
552
595
|
}
|
|
553
596
|
function resolveFullReloadConfig({ refresh: config }) {
|
|
554
597
|
if (typeof config === "boolean") {
|
|
@@ -717,7 +760,7 @@ declare module "litestar-vite/inertia" {
|
|
|
717
760
|
`;
|
|
718
761
|
await fs.promises.writeFile(outFile, body, "utf-8");
|
|
719
762
|
}
|
|
720
|
-
async function emitRouteTypes(routesPath, outputDir) {
|
|
763
|
+
async function emitRouteTypes(routesPath, outputDir, globalRoute = false) {
|
|
721
764
|
const contents = await fs.promises.readFile(routesPath, "utf-8");
|
|
722
765
|
const json = JSON.parse(contents);
|
|
723
766
|
const outDir = path.resolve(process.cwd(), outputDir);
|
|
@@ -830,12 +873,23 @@ declare global {
|
|
|
830
873
|
*/
|
|
831
874
|
routes?: Record<string, string>
|
|
832
875
|
serverRoutes?: Record<string, string>
|
|
876
|
+
/**
|
|
877
|
+
* Global route helper (available when globalRoute=true in TypeGenConfig).
|
|
878
|
+
* @see route
|
|
879
|
+
*/
|
|
880
|
+
route?: typeof route
|
|
833
881
|
}
|
|
834
882
|
}
|
|
835
883
|
|
|
836
884
|
// Re-export helper functions from litestar-vite-plugin
|
|
837
885
|
// These work with the routes defined above
|
|
838
886
|
export { getCsrfToken, csrfHeaders, csrfFetch } from "litestar-vite-plugin/helpers"
|
|
887
|
+
${globalRoute ? `
|
|
888
|
+
// Register route() globally on window for Laravel/Ziggy-style usage
|
|
889
|
+
if (typeof window !== "undefined") {
|
|
890
|
+
window.route = route
|
|
891
|
+
}
|
|
892
|
+
` : ""}
|
|
839
893
|
`;
|
|
840
894
|
await fs.promises.writeFile(outFile, `${banner}${body}`, "utf-8");
|
|
841
895
|
}
|
|
@@ -864,10 +918,10 @@ function resolveTypeGenerationPlugin(typesConfig, executor, hasPythonConfig) {
|
|
|
864
918
|
chosenConfigPath = configPath;
|
|
865
919
|
const shouldRunOpenApiTs = configPath || typesConfig.generateSdk;
|
|
866
920
|
if (fs.existsSync(openapiPath) && shouldRunOpenApiTs) {
|
|
867
|
-
resolvedConfig?.logger.info(`${colors.cyan("
|
|
868
|
-
if (resolvedConfig) {
|
|
869
|
-
const relConfigPath = configPath
|
|
870
|
-
resolvedConfig.logger.info(`${colors.cyan("
|
|
921
|
+
resolvedConfig?.logger.info(`${colors.cyan("\u2022")} Generating TypeScript types...`);
|
|
922
|
+
if (resolvedConfig && configPath) {
|
|
923
|
+
const relConfigPath = formatPath(configPath, resolvedConfig.root);
|
|
924
|
+
resolvedConfig.logger.info(`${colors.cyan("\u2022")} openapi-ts config: ${relConfigPath}`);
|
|
871
925
|
}
|
|
872
926
|
const sdkOutput = path.join(typesConfig.output, "api");
|
|
873
927
|
let args;
|
|
@@ -890,7 +944,7 @@ function resolveTypeGenerationPlugin(typesConfig, executor, hasPythonConfig) {
|
|
|
890
944
|
try {
|
|
891
945
|
require.resolve("zod", { paths: [process.cwd()] });
|
|
892
946
|
} catch {
|
|
893
|
-
resolvedConfig?.logger.warn(`${colors.
|
|
947
|
+
resolvedConfig?.logger.warn(`${colors.yellow("!")} zod not installed - run: ${resolveInstallHint()} zod`);
|
|
894
948
|
}
|
|
895
949
|
}
|
|
896
950
|
await execAsync(resolvePackageExecutor(args.join(" "), executor), {
|
|
@@ -899,7 +953,7 @@ function resolveTypeGenerationPlugin(typesConfig, executor, hasPythonConfig) {
|
|
|
899
953
|
generated = true;
|
|
900
954
|
}
|
|
901
955
|
if (fs.existsSync(routesPath)) {
|
|
902
|
-
await emitRouteTypes(routesPath, typesConfig.output);
|
|
956
|
+
await emitRouteTypes(routesPath, typesConfig.output, typesConfig.globalRoute ?? false);
|
|
903
957
|
generated = true;
|
|
904
958
|
}
|
|
905
959
|
if (fs.existsSync(pagePropsPath)) {
|
|
@@ -908,7 +962,7 @@ function resolveTypeGenerationPlugin(typesConfig, executor, hasPythonConfig) {
|
|
|
908
962
|
}
|
|
909
963
|
if (generated && resolvedConfig) {
|
|
910
964
|
const duration = Date.now() - startTime;
|
|
911
|
-
resolvedConfig.logger.info(`${colors.
|
|
965
|
+
resolvedConfig.logger.info(`${colors.green("\u2713")} TypeScript artifacts updated ${colors.dim(`(${duration}ms)`)}`);
|
|
912
966
|
}
|
|
913
967
|
if (generated && server) {
|
|
914
968
|
server.ws.send({
|
|
@@ -949,12 +1003,12 @@ function resolveTypeGenerationPlugin(typesConfig, executor, hasPythonConfig) {
|
|
|
949
1003
|
server = devServer;
|
|
950
1004
|
if (typesConfig.enabled) {
|
|
951
1005
|
const root = resolvedConfig?.root ?? process.cwd();
|
|
952
|
-
const openapiRel = typesConfig.openapiPath;
|
|
953
|
-
const routesRel = typesConfig.routesPath;
|
|
954
|
-
resolvedConfig?.logger.info(`${colors.cyan("
|
|
1006
|
+
const openapiRel = path.basename(typesConfig.openapiPath);
|
|
1007
|
+
const routesRel = path.basename(typesConfig.routesPath);
|
|
1008
|
+
resolvedConfig?.logger.info(`${colors.cyan("\u2022")} Watching: ${colors.yellow(openapiRel)}, ${colors.yellow(routesRel)}`);
|
|
955
1009
|
if (chosenConfigPath) {
|
|
956
|
-
const relConfigPath =
|
|
957
|
-
resolvedConfig?.logger.info(`${colors.cyan("
|
|
1010
|
+
const relConfigPath = formatPath(chosenConfigPath, root);
|
|
1011
|
+
resolvedConfig?.logger.info(`${colors.cyan("\u2022")} openapi-ts config: ${colors.yellow(relConfigPath)}`);
|
|
958
1012
|
}
|
|
959
1013
|
}
|
|
960
1014
|
},
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Path formatting utilities for consistent logging output.
|
|
3
|
+
*
|
|
4
|
+
* @module
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
* Format an absolute path as relative to the project root for cleaner logging.
|
|
8
|
+
*
|
|
9
|
+
* @param absolutePath - The absolute path to format
|
|
10
|
+
* @param root - The project root directory (defaults to process.cwd())
|
|
11
|
+
* @returns The path relative to root, or the original path if already relative or on different drive
|
|
12
|
+
*/
|
|
13
|
+
export declare function formatPath(absolutePath: string, root?: string): string;
|
|
14
|
+
/**
|
|
15
|
+
* Format multiple paths, joining them with a separator.
|
|
16
|
+
*
|
|
17
|
+
* @param paths - Array of absolute paths to format
|
|
18
|
+
* @param root - The project root directory (defaults to process.cwd())
|
|
19
|
+
* @param separator - Separator between paths (defaults to ", ")
|
|
20
|
+
* @returns Formatted paths joined by separator
|
|
21
|
+
*/
|
|
22
|
+
export declare function formatPaths(paths: string[], root?: string, separator?: string): string;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import path from "node:path";
|
|
2
|
+
function formatPath(absolutePath, root) {
|
|
3
|
+
if (!absolutePath) return absolutePath;
|
|
4
|
+
const projectRoot = root ?? process.cwd();
|
|
5
|
+
if (!path.isAbsolute(absolutePath)) {
|
|
6
|
+
return absolutePath;
|
|
7
|
+
}
|
|
8
|
+
try {
|
|
9
|
+
const relativePath = path.relative(projectRoot, absolutePath);
|
|
10
|
+
if (path.isAbsolute(relativePath)) {
|
|
11
|
+
return absolutePath;
|
|
12
|
+
}
|
|
13
|
+
return relativePath;
|
|
14
|
+
} catch {
|
|
15
|
+
return absolutePath;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
function formatPaths(paths, root, separator = ", ") {
|
|
19
|
+
return paths.map((p) => formatPath(p, root)).join(separator);
|
|
20
|
+
}
|
|
21
|
+
export {
|
|
22
|
+
formatPath,
|
|
23
|
+
formatPaths
|
|
24
|
+
};
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Logging utilities for litestar-vite with configurable output.
|
|
3
|
+
*
|
|
4
|
+
* @module
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
* Logging configuration matching the Python LoggingConfig.
|
|
8
|
+
*/
|
|
9
|
+
export interface LoggingConfig {
|
|
10
|
+
level: "quiet" | "normal" | "verbose";
|
|
11
|
+
showPathsAbsolute: boolean;
|
|
12
|
+
suppressNpmOutput: boolean;
|
|
13
|
+
suppressViteBanner: boolean;
|
|
14
|
+
timestamps: boolean;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Default logging configuration.
|
|
18
|
+
*/
|
|
19
|
+
export declare const defaultLoggingConfig: LoggingConfig;
|
|
20
|
+
/**
|
|
21
|
+
* Logger instance with configurable behavior.
|
|
22
|
+
*/
|
|
23
|
+
export interface Logger {
|
|
24
|
+
/** Log a message at normal level */
|
|
25
|
+
info: (message: string) => void;
|
|
26
|
+
/** Log a message at verbose level */
|
|
27
|
+
debug: (message: string) => void;
|
|
28
|
+
/** Log a warning (always shown except in quiet mode) */
|
|
29
|
+
warn: (message: string) => void;
|
|
30
|
+
/** Log an error (always shown) */
|
|
31
|
+
error: (message: string) => void;
|
|
32
|
+
/** Format a path according to config (relative or absolute) */
|
|
33
|
+
path: (absolutePath: string, root?: string) => string;
|
|
34
|
+
/** Get the current config */
|
|
35
|
+
config: LoggingConfig;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Create a logger instance with the given configuration.
|
|
39
|
+
*
|
|
40
|
+
* @param config - Logging configuration (partial, will be merged with defaults)
|
|
41
|
+
* @returns A Logger instance
|
|
42
|
+
*/
|
|
43
|
+
export declare function createLogger(config?: Partial<LoggingConfig> | null): Logger;
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { formatPath } from "./format-path.js";
|
|
2
|
+
const defaultLoggingConfig = {
|
|
3
|
+
level: "normal",
|
|
4
|
+
showPathsAbsolute: false,
|
|
5
|
+
suppressNpmOutput: false,
|
|
6
|
+
suppressViteBanner: false,
|
|
7
|
+
timestamps: false
|
|
8
|
+
};
|
|
9
|
+
const LOG_LEVELS = {
|
|
10
|
+
quiet: 0,
|
|
11
|
+
normal: 1,
|
|
12
|
+
verbose: 2
|
|
13
|
+
};
|
|
14
|
+
function createLogger(config) {
|
|
15
|
+
const mergedConfig = {
|
|
16
|
+
...defaultLoggingConfig,
|
|
17
|
+
...config
|
|
18
|
+
};
|
|
19
|
+
const levelNum = LOG_LEVELS[mergedConfig.level];
|
|
20
|
+
const formatMessage = (message) => {
|
|
21
|
+
if (mergedConfig.timestamps) {
|
|
22
|
+
const now = (/* @__PURE__ */ new Date()).toISOString().slice(11, 23);
|
|
23
|
+
return `[${now}] ${message}`;
|
|
24
|
+
}
|
|
25
|
+
return message;
|
|
26
|
+
};
|
|
27
|
+
const formatPathValue = (absolutePath, root) => {
|
|
28
|
+
if (mergedConfig.showPathsAbsolute) {
|
|
29
|
+
return absolutePath;
|
|
30
|
+
}
|
|
31
|
+
return formatPath(absolutePath, root);
|
|
32
|
+
};
|
|
33
|
+
return {
|
|
34
|
+
info: (message) => {
|
|
35
|
+
if (levelNum >= LOG_LEVELS.normal) {
|
|
36
|
+
console.log(formatMessage(message));
|
|
37
|
+
}
|
|
38
|
+
},
|
|
39
|
+
debug: (message) => {
|
|
40
|
+
if (levelNum >= LOG_LEVELS.verbose) {
|
|
41
|
+
console.log(formatMessage(message));
|
|
42
|
+
}
|
|
43
|
+
},
|
|
44
|
+
warn: (message) => {
|
|
45
|
+
if (levelNum >= LOG_LEVELS.normal) {
|
|
46
|
+
console.warn(formatMessage(message));
|
|
47
|
+
}
|
|
48
|
+
},
|
|
49
|
+
error: (message) => {
|
|
50
|
+
console.error(formatMessage(message));
|
|
51
|
+
},
|
|
52
|
+
path: formatPathValue,
|
|
53
|
+
config: mergedConfig
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
export {
|
|
57
|
+
createLogger,
|
|
58
|
+
defaultLoggingConfig
|
|
59
|
+
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "litestar-vite-plugin",
|
|
3
|
-
"version": "0.15.0-
|
|
3
|
+
"version": "0.15.0-beta.1",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Litestar plugin for Vite.",
|
|
6
6
|
"keywords": [
|
|
@@ -55,7 +55,7 @@
|
|
|
55
55
|
"build": "npm run build-plugin && npm run build-helpers && npm run build-inertia-helpers && npm run build-integrations",
|
|
56
56
|
"build-plugin": "rm -rf dist/js && npm run build-plugin-types && npm run build-plugin-esm && cp src/js/src/dev-server-index.html dist/js/",
|
|
57
57
|
"build-plugin-types": "tsc --project src/js/tsconfig.json --emitDeclarationOnly",
|
|
58
|
-
"build-plugin-esm": "esbuild src/js/src/index.ts --platform=node --format=esm --outfile=dist/js/index.js && esbuild src/js/src/install-hint.ts --platform=node --format=esm --outfile=dist/js/install-hint.js && esbuild src/js/src/litestar-meta.ts --platform=node --format=esm --outfile=dist/js/litestar-meta.js && mkdir -p dist/js/shared && esbuild src/js/src/shared/debounce.ts --platform=node --format=esm --
|
|
58
|
+
"build-plugin-esm": "esbuild src/js/src/index.ts --platform=node --format=esm --outfile=dist/js/index.js && esbuild src/js/src/install-hint.ts --platform=node --format=esm --outfile=dist/js/install-hint.js && esbuild src/js/src/litestar-meta.ts --platform=node --format=esm --outfile=dist/js/litestar-meta.js && mkdir -p dist/js/shared && esbuild src/js/src/shared/debounce.ts src/js/src/shared/format-path.ts src/js/src/shared/logger.ts --platform=node --format=esm --outdir=dist/js/shared",
|
|
59
59
|
"build-helpers": "rm -rf dist/js/helpers && tsc --project src/js/tsconfig.helpers.json",
|
|
60
60
|
"build-inertia-helpers": "rm -rf dist/js/inertia-helpers && tsc --project src/js/tsconfig.inertia-helpers.json",
|
|
61
61
|
"build-integrations": "esbuild src/js/src/astro.ts src/js/src/sveltekit.ts src/js/src/nuxt.ts --platform=node --format=esm --outdir=dist/js",
|