litestar-vite-plugin 0.13.0 → 0.13.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.
Files changed (2) hide show
  1. package/dist/js/index.js +93 -45
  2. package/package.json +2 -2
package/dist/js/index.js CHANGED
@@ -10,12 +10,34 @@ function litestar(config) {
10
10
  const pluginConfig = resolvePluginConfig(config);
11
11
  return [resolveLitestarPlugin(pluginConfig), ...resolveFullReloadConfig(pluginConfig)];
12
12
  }
13
+ async function findIndexHtmlPath(server, pluginConfig) {
14
+ if (!pluginConfig.autoDetectIndex) {
15
+ console.log("Auto-detection disabled.");
16
+ return null;
17
+ }
18
+ const root = server.config.root;
19
+ const possiblePaths = [
20
+ path.join(root, "index.html"),
21
+ path.join(root, pluginConfig.resourceDirectory.replace(/^\//, ""), "index.html"),
22
+ // Ensure resourceDirectory path is relative to root
23
+ path.join(root, "public", "index.html")
24
+ // Check public even if publicDir is false, might exist
25
+ ];
26
+ for (const indexPath of possiblePaths) {
27
+ try {
28
+ await fs.promises.access(indexPath);
29
+ return indexPath;
30
+ } catch {
31
+ }
32
+ }
33
+ return null;
34
+ }
13
35
  function resolveLitestarPlugin(pluginConfig) {
14
36
  let viteDevServerUrl;
15
37
  let resolvedConfig;
16
38
  let userConfig;
17
39
  const defaultAliases = {
18
- "@": pluginConfig.resourceDirectory || "/resources/"
40
+ "@": `/${pluginConfig.resourceDirectory.replace(/^\/+/, "").replace(/\/+$/, "")}/`
19
41
  };
20
42
  return {
21
43
  name: "litestar",
@@ -71,13 +93,21 @@ function resolveLitestarPlugin(pluginConfig) {
71
93
  ssr: {
72
94
  noExternal: noExternalInertiaHelpers(userConfig)
73
95
  }
96
+ // Explicitly set appType if you know you're serving an SPA index.html
97
+ // appType: 'spa', // Try adding this - might simplify things if appropriate
74
98
  };
75
99
  },
76
100
  configResolved(config) {
77
101
  resolvedConfig = config;
102
+ if (resolvedConfig.command === "serve" && resolvedConfig.base && !resolvedConfig.base.endsWith("/")) {
103
+ resolvedConfig = {
104
+ ...resolvedConfig,
105
+ base: `${resolvedConfig.base}/`
106
+ };
107
+ }
78
108
  },
79
- transform(code) {
80
- if (resolvedConfig.command === "serve") {
109
+ transform(code, id) {
110
+ if (resolvedConfig.command === "serve" && code.includes("__litestar_vite_placeholder__")) {
81
111
  const transformedCode = code.replace(/__litestar_vite_placeholder__/g, viteDevServerUrl);
82
112
  return pluginConfig.transformOnServe(transformedCode, viteDevServerUrl);
83
113
  }
@@ -86,22 +116,7 @@ function resolveLitestarPlugin(pluginConfig) {
86
116
  async configureServer(server) {
87
117
  const envDir = resolvedConfig.envDir || process.cwd();
88
118
  const appUrl = loadEnv(resolvedConfig.mode, envDir, "APP_URL").APP_URL ?? "undefined";
89
- const shouldServeIndex = () => {
90
- if (!pluginConfig.autoDetectIndex) return false;
91
- const possiblePaths = [
92
- path.join(server.config.root, "index.html"),
93
- path.join(server.config.root, pluginConfig.resourceDirectory, "index.html"),
94
- path.join(server.config.root, "public", "index.html")
95
- ];
96
- for (const indexPath of possiblePaths) {
97
- try {
98
- fs.accessSync(indexPath);
99
- return true;
100
- } catch {
101
- }
102
- }
103
- return false;
104
- };
119
+ const initialIndexPath = await findIndexHtmlPath(server, pluginConfig);
105
120
  server.httpServer?.once("listening", () => {
106
121
  const address = server.httpServer?.address();
107
122
  const isAddressInfo = (x) => typeof x === "object";
@@ -109,26 +124,26 @@ function resolveLitestarPlugin(pluginConfig) {
109
124
  viteDevServerUrl = userConfig.server?.origin ? userConfig.server.origin : resolveDevServerUrl(address, server.config, userConfig);
110
125
  fs.mkdirSync(path.dirname(pluginConfig.hotFile), { recursive: true });
111
126
  fs.writeFileSync(pluginConfig.hotFile, viteDevServerUrl);
112
- const hasIndex = shouldServeIndex();
113
127
  setTimeout(() => {
114
- server.config.logger.info(`
128
+ resolvedConfig.logger.info(`
115
129
  ${colors.red(`${colors.bold("LITESTAR")} ${litestarVersion()}`)} ${colors.dim("plugin")} ${colors.bold(`v${pluginVersion()}`)}`);
116
- server.config.logger.info("");
117
- if (hasIndex) {
118
- server.config.logger.info(` ${colors.green("\u279C")} ${colors.bold("Serve Index")}: Serving application index with Vite`);
119
- server.config.logger.info(` ${colors.green("\u279C")} ${colors.bold("DEV URL")}: ${colors.cyan(viteDevServerUrl)}`);
120
- server.config.logger.info(` ${colors.green("\u279C")} ${colors.bold("APP_URL")}: ${colors.cyan(appUrl.replace(/:(\d+)/, (_, port) => `:${colors.bold(port)}`))}`);
130
+ resolvedConfig.logger.info("");
131
+ if (initialIndexPath) {
132
+ resolvedConfig.logger.info(
133
+ ` ${colors.green("\u279C")} ${colors.bold("Index Mode")}: SPA (Serving ${colors.cyan(path.relative(server.config.root, initialIndexPath))} from root)`
134
+ );
121
135
  } else {
122
- server.config.logger.info(` ${colors.green("\u279C")} ${colors.bold("Serve Index")}: Serving Litestar index with Vite`);
123
- server.config.logger.info(` ${colors.green("\u279C")} ${colors.bold("DEV URL")}: ${colors.cyan(viteDevServerUrl)}`);
124
- server.config.logger.info(` ${colors.green("\u279C")} ${colors.bold("APP_URL")}: ${colors.cyan(appUrl.replace(/:(\d+)/, (_, port) => `:${colors.bold(port)}`))}`);
136
+ resolvedConfig.logger.info(` ${colors.green("\u279C")} ${colors.bold("Index Mode")}: Litestar (Plugin will serve placeholder for /index.html)`);
125
137
  }
138
+ resolvedConfig.logger.info(` ${colors.green("\u279C")} ${colors.bold("Dev Server")}: ${colors.cyan(viteDevServerUrl)}`);
139
+ resolvedConfig.logger.info(` ${colors.green("\u279C")} ${colors.bold("App URL")}: ${colors.cyan(appUrl.replace(/:(\d+)/, (_, port) => `:${colors.bold(port)}`))}`);
140
+ resolvedConfig.logger.info(` ${colors.green("\u279C")} ${colors.bold("Assets Base")}: ${colors.cyan(resolvedConfig.base)}`);
126
141
  }, 100);
127
142
  }
128
143
  });
129
144
  if (!exitHandlersBound) {
130
145
  const clean = () => {
131
- if (fs.existsSync(pluginConfig.hotFile)) {
146
+ if (pluginConfig.hotFile && fs.existsSync(pluginConfig.hotFile)) {
132
147
  fs.rmSync(pluginConfig.hotFile);
133
148
  }
134
149
  };
@@ -138,15 +153,45 @@ function resolveLitestarPlugin(pluginConfig) {
138
153
  process.on("SIGHUP", () => process.exit());
139
154
  exitHandlersBound = true;
140
155
  }
141
- return () => server.middlewares.use((req, res, next) => {
142
- if (!shouldServeIndex() && req.url === "/index.html") {
143
- res.statusCode = 404;
144
- res.end(
145
- fs.readFileSync(path.join(dirname(), "dev-server-index.html")).toString().replace(/{{ APP_URL }}/g, appUrl)
146
- );
147
- }
148
- next();
149
- });
156
+ return () => {
157
+ server.middlewares.use(async (req, res, next) => {
158
+ const indexPath = await findIndexHtmlPath(server, pluginConfig);
159
+ if (indexPath && (req.url === "/" || req.url === "/index.html")) {
160
+ try {
161
+ const htmlContent = await fs.promises.readFile(indexPath, "utf-8");
162
+ const transformedHtml = await server.transformIndexHtml(
163
+ "/",
164
+ // Use '/' as the URL for transformation context to ensure scripts are injected correctly relative to root
165
+ htmlContent,
166
+ req.originalUrl
167
+ );
168
+ res.statusCode = 200;
169
+ res.setHeader("Content-Type", "text/html");
170
+ res.end(transformedHtml);
171
+ return;
172
+ } catch (e) {
173
+ resolvedConfig.logger.error(`Error serving index.html from ${indexPath}: ${e instanceof Error ? e.message : e}`);
174
+ next(e);
175
+ return;
176
+ }
177
+ }
178
+ if (!indexPath && req.url === "/index.html") {
179
+ try {
180
+ const placeholderPath = path.join(dirname(), "dev-server-index.html");
181
+ const placeholderContent = await fs.promises.readFile(placeholderPath, "utf-8");
182
+ res.statusCode = 200;
183
+ res.setHeader("Content-Type", "text/html");
184
+ res.end(placeholderContent.replace(/{{ APP_URL }}/g, appUrl));
185
+ } catch (e) {
186
+ resolvedConfig.logger.error(`Error serving placeholder index.html: ${e instanceof Error ? e.message : e}`);
187
+ res.statusCode = 404;
188
+ res.end("Not Found (Error loading placeholder)");
189
+ }
190
+ return;
191
+ }
192
+ next();
193
+ });
194
+ };
150
195
  }
151
196
  };
152
197
  }
@@ -185,7 +230,7 @@ function resolvePluginConfig(config) {
185
230
  throw new Error('litestar-vite-plugin: missing configuration for "input".');
186
231
  }
187
232
  if (typeof resolvedConfig.resourceDirectory === "string") {
188
- resolvedConfig.resourceDirectory = resolvedConfig.resourceDirectory.trim().replace(/^\/+/, "");
233
+ resolvedConfig.resourceDirectory = resolvedConfig.resourceDirectory.trim().replace(/^\/+/, "").replace(/\/+$/, "");
189
234
  if (resolvedConfig.resourceDirectory === "") {
190
235
  throw new Error("litestar-vite-plugin: resourceDirectory must be a subdirectory. E.g. 'resources'.");
191
236
  }
@@ -205,8 +250,8 @@ function resolvePluginConfig(config) {
205
250
  return {
206
251
  input: resolvedConfig.input,
207
252
  assetUrl: resolvedConfig.assetUrl ?? "static",
208
- resourceDirectory: resolvedConfig.resourceDirectory ?? "/resources/",
209
- bundleDirectory: resolvedConfig.bundleDirectory || (resolvedConfig.bundleDirectory ?? "public"),
253
+ resourceDirectory: resolvedConfig.resourceDirectory ?? "resources",
254
+ bundleDirectory: resolvedConfig.bundleDirectory ?? "public",
210
255
  ssr: resolvedConfig.ssr ?? resolvedConfig.input,
211
256
  ssrOutputDirectory: resolvedConfig.ssrOutputDirectory ?? path.join(resolvedConfig.resourceDirectory ?? "resources", "bootstrap/ssr"),
212
257
  refresh: resolvedConfig.refresh ?? false,
@@ -217,7 +262,10 @@ function resolvePluginConfig(config) {
217
262
  };
218
263
  }
219
264
  function resolveBase(config, assetUrl) {
220
- return assetUrl + (assetUrl.endsWith("/") ? "" : "/");
265
+ if (process.env.NODE_ENV === "development") {
266
+ return assetUrl;
267
+ }
268
+ return assetUrl.endsWith("/") ? assetUrl : `${assetUrl}/`;
221
269
  }
222
270
  function resolveInput(config, ssr) {
223
271
  if (ssr) {
@@ -227,9 +275,9 @@ function resolveInput(config, ssr) {
227
275
  }
228
276
  function resolveOutDir(config, ssr) {
229
277
  if (ssr) {
230
- return config.ssrOutputDirectory;
278
+ return config.ssrOutputDirectory.replace(/^\/+/, "").replace(/\/+$/, "");
231
279
  }
232
- return path.join(config.bundleDirectory);
280
+ return config.bundleDirectory.replace(/^\/+/, "").replace(/\/+$/, "");
233
281
  }
234
282
  function resolveFullReloadConfig({ refresh: config }) {
235
283
  if (typeof config === "boolean") {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "litestar-vite-plugin",
3
- "version": "0.13.0",
3
+ "version": "0.13.1",
4
4
  "type": "module",
5
5
  "description": "Litestar plugin for Vite.",
6
6
  "keywords": ["litestar", "vite", "vite-plugin"],
@@ -38,7 +38,7 @@
38
38
  "devDependencies": {
39
39
  "@biomejs/biome": "1.9.4",
40
40
  "@types/node": "^22.10.1",
41
- "esbuild": "0.24.0",
41
+ "esbuild": "0.25.0",
42
42
  "happy-dom": "^15.11.7",
43
43
  "typescript": "^5.7.2",
44
44
  "vite": "^6.0.1",