litestar-vite 0.13.0__tar.gz → 0.13.1__tar.gz

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.

Potentially problematic release.


This version of litestar-vite might be problematic. Click here for more details.

Files changed (81) hide show
  1. {litestar_vite-0.13.0 → litestar_vite-0.13.1}/PKG-INFO +3 -3
  2. {litestar_vite-0.13.0 → litestar_vite-0.13.1}/pyproject.toml +25 -74
  3. {litestar_vite-0.13.0 → litestar_vite-0.13.1}/src/js/src/index.ts +132 -57
  4. {litestar_vite-0.13.0 → litestar_vite-0.13.1}/src/js/tests/index.test.ts +159 -9
  5. {litestar_vite-0.13.0 → litestar_vite-0.13.1}/src/py/litestar_vite/__init__.py +0 -2
  6. {litestar_vite-0.13.0 → litestar_vite-0.13.1}/src/py/litestar_vite/__metadata__.py +0 -2
  7. {litestar_vite-0.13.0 → litestar_vite-0.13.1}/src/py/litestar_vite/cli.py +33 -38
  8. {litestar_vite-0.13.0 → litestar_vite-0.13.1}/src/py/litestar_vite/commands.py +45 -35
  9. {litestar_vite-0.13.0 → litestar_vite-0.13.1}/src/py/litestar_vite/config.py +6 -7
  10. litestar_vite-0.13.1/src/py/litestar_vite/inertia/_utils.py +99 -0
  11. {litestar_vite-0.13.0 → litestar_vite-0.13.1}/src/py/litestar_vite/inertia/config.py +5 -7
  12. {litestar_vite-0.13.0 → litestar_vite-0.13.1}/src/py/litestar_vite/inertia/exception_handler.py +22 -8
  13. {litestar_vite-0.13.0 → litestar_vite-0.13.1}/src/py/litestar_vite/inertia/helpers.py +57 -61
  14. {litestar_vite-0.13.0 → litestar_vite-0.13.1}/src/py/litestar_vite/inertia/middleware.py +4 -6
  15. {litestar_vite-0.13.0 → litestar_vite-0.13.1}/src/py/litestar_vite/inertia/plugin.py +22 -9
  16. {litestar_vite-0.13.0 → litestar_vite-0.13.1}/src/py/litestar_vite/inertia/request.py +58 -20
  17. {litestar_vite-0.13.0 → litestar_vite-0.13.1}/src/py/litestar_vite/inertia/response.py +42 -40
  18. {litestar_vite-0.13.0 → litestar_vite-0.13.1}/src/py/litestar_vite/inertia/routes.py +7 -9
  19. {litestar_vite-0.13.0 → litestar_vite-0.13.1}/src/py/litestar_vite/inertia/types.py +6 -8
  20. {litestar_vite-0.13.0 → litestar_vite-0.13.1}/src/py/litestar_vite/loader.py +93 -29
  21. {litestar_vite-0.13.0 → litestar_vite-0.13.1}/src/py/litestar_vite/plugin.py +41 -33
  22. {litestar_vite-0.13.0 → litestar_vite-0.13.1}/src/py/tests/conftest.py +1 -1
  23. {litestar_vite-0.13.0 → litestar_vite-0.13.1}/src/py/tests/test_asset_loader.py +2 -1
  24. {litestar_vite-0.13.0 → litestar_vite-0.13.1}/src/py/tests/test_cli/conftest.py +2 -1
  25. {litestar_vite-0.13.0 → litestar_vite-0.13.1}/src/py/tests/test_inertia/test_response.py +11 -11
  26. {litestar_vite-0.13.0 → litestar_vite-0.13.1}/tools/sphinx_ext/__init__.py +3 -1
  27. {litestar_vite-0.13.0 → litestar_vite-0.13.1}/tools/sphinx_ext/missing_references.py +3 -3
  28. litestar_vite-0.13.0/src/py/litestar_vite/inertia/_utils.py +0 -63
  29. {litestar_vite-0.13.0 → litestar_vite-0.13.1}/.gitignore +0 -0
  30. {litestar_vite-0.13.0 → litestar_vite-0.13.1}/LICENSE +0 -0
  31. {litestar_vite-0.13.0 → litestar_vite-0.13.1}/README.md +0 -0
  32. {litestar_vite-0.13.0 → litestar_vite-0.13.1}/src/js/LICENSE +0 -0
  33. {litestar_vite-0.13.0 → litestar_vite-0.13.1}/src/js/Makefile +0 -0
  34. {litestar_vite-0.13.0 → litestar_vite-0.13.1}/src/js/NOTICE +0 -0
  35. {litestar_vite-0.13.0 → litestar_vite-0.13.1}/src/js/README.md +0 -0
  36. {litestar_vite-0.13.0 → litestar_vite-0.13.1}/src/js/src/dev-server-index.html +0 -0
  37. {litestar_vite-0.13.0 → litestar_vite-0.13.1}/src/js/src/inertia-helpers/index.ts +0 -0
  38. {litestar_vite-0.13.0 → litestar_vite-0.13.1}/src/js/tests/__data__/dummy.ts +0 -0
  39. {litestar_vite-0.13.0 → litestar_vite-0.13.1}/src/js/tsconfig.inertia-helpers.json +0 -0
  40. {litestar_vite-0.13.0 → litestar_vite-0.13.1}/src/js/tsconfig.json +0 -0
  41. {litestar_vite-0.13.0 → litestar_vite-0.13.1}/src/js/vitest.config.ts +0 -0
  42. {litestar_vite-0.13.0 → litestar_vite-0.13.1}/src/js/vitest.workspace.ts +0 -0
  43. {litestar_vite-0.13.0 → litestar_vite-0.13.1}/src/py/litestar_vite/inertia/__init__.py +0 -0
  44. {litestar_vite-0.13.0 → litestar_vite-0.13.1}/src/py/litestar_vite/py.typed +0 -0
  45. {litestar_vite-0.13.0 → litestar_vite-0.13.1}/src/py/litestar_vite/templates/__init__.py +0 -0
  46. {litestar_vite-0.13.0 → litestar_vite-0.13.1}/src/py/litestar_vite/templates/index.html.j2 +0 -0
  47. {litestar_vite-0.13.0 → litestar_vite-0.13.1}/src/py/litestar_vite/templates/main.ts.j2 +0 -0
  48. {litestar_vite-0.13.0 → litestar_vite-0.13.1}/src/py/litestar_vite/templates/package.json.j2 +0 -0
  49. {litestar_vite-0.13.0 → litestar_vite-0.13.1}/src/py/litestar_vite/templates/styles.css.j2 +0 -0
  50. {litestar_vite-0.13.0 → litestar_vite-0.13.1}/src/py/litestar_vite/templates/tsconfig.json.j2 +0 -0
  51. {litestar_vite-0.13.0 → litestar_vite-0.13.1}/src/py/litestar_vite/templates/vite.config.ts.j2 +0 -0
  52. {litestar_vite-0.13.0 → litestar_vite-0.13.1}/src/py/tests/__init__.py +0 -0
  53. {litestar_vite-0.13.0 → litestar_vite-0.13.1}/src/py/tests/py.typed +0 -0
  54. {litestar_vite-0.13.0 → litestar_vite-0.13.1}/src/py/tests/templates/__init__.py +0 -0
  55. {litestar_vite-0.13.0 → litestar_vite-0.13.1}/src/py/tests/templates/index.html.j2 +0 -0
  56. {litestar_vite-0.13.0 → litestar_vite-0.13.1}/src/py/tests/test_app/__init__.py +0 -0
  57. {litestar_vite-0.13.0 → litestar_vite-0.13.1}/src/py/tests/test_app/app.py +0 -0
  58. {litestar_vite-0.13.0 → litestar_vite-0.13.1}/src/py/tests/test_app/web/__init__.py +0 -0
  59. {litestar_vite-0.13.0 → litestar_vite-0.13.1}/src/py/tests/test_app/web/public/.gitkeep +0 -0
  60. {litestar_vite-0.13.0 → litestar_vite-0.13.1}/src/py/tests/test_app/web/public/assets/main-l0sNRNKZ.js +0 -0
  61. {litestar_vite-0.13.0 → litestar_vite-0.13.1}/src/py/tests/test_app/web/public/assets/styles-l0sNRNKZ.js +0 -0
  62. {litestar_vite-0.13.0 → litestar_vite-0.13.1}/src/py/tests/test_app/web/public/manifest.json +0 -0
  63. {litestar_vite-0.13.0 → litestar_vite-0.13.1}/src/py/tests/test_app/web/resources/.gitkeep +0 -0
  64. {litestar_vite-0.13.0 → litestar_vite-0.13.1}/src/py/tests/test_app/web/resources/main.ts +0 -0
  65. {litestar_vite-0.13.0 → litestar_vite-0.13.1}/src/py/tests/test_app/web/resources/styles.css +0 -0
  66. {litestar_vite-0.13.0 → litestar_vite-0.13.1}/src/py/tests/test_app/web/templates/.gitkeep +0 -0
  67. {litestar_vite-0.13.0 → litestar_vite-0.13.1}/src/py/tests/test_app/web/templates/index.html +0 -0
  68. {litestar_vite-0.13.0 → litestar_vite-0.13.1}/src/py/tests/test_cli/__init__.py +0 -0
  69. {litestar_vite-0.13.0 → litestar_vite-0.13.1}/src/py/tests/test_cli/test_init.py +0 -0
  70. {litestar_vite-0.13.0 → litestar_vite-0.13.1}/src/py/tests/test_commands.py +0 -0
  71. {litestar_vite-0.13.0 → litestar_vite-0.13.1}/src/py/tests/test_config.py +0 -0
  72. {litestar_vite-0.13.0 → litestar_vite-0.13.1}/src/py/tests/test_inertia/__init__.py +0 -0
  73. {litestar_vite-0.13.0 → litestar_vite-0.13.1}/src/py/tests/test_inertia/conftest.py +0 -0
  74. {litestar_vite-0.13.0 → litestar_vite-0.13.1}/src/py/tests/test_inertia/templates/index.html.j2 +0 -0
  75. {litestar_vite-0.13.0 → litestar_vite-0.13.1}/src/py/tests/test_inertia/test_request.py +0 -0
  76. {litestar_vite-0.13.0 → litestar_vite-0.13.1}/src/py/tests/test_inertia/test_routes.py +0 -0
  77. {litestar_vite-0.13.0 → litestar_vite-0.13.1}/tools/__init__.py +0 -0
  78. {litestar_vite-0.13.0 → litestar_vite-0.13.1}/tools/build_docs.py +0 -0
  79. {litestar_vite-0.13.0 → litestar_vite-0.13.1}/tools/clean.js +0 -0
  80. {litestar_vite-0.13.0 → litestar_vite-0.13.1}/tools/pypi_readme.py +0 -0
  81. {litestar_vite-0.13.0 → litestar_vite-0.13.1}/tools/sphinx_ext/changelog.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: litestar-vite
3
- Version: 0.13.0
3
+ Version: 0.13.1
4
4
  Summary: Vite plugin for Litestar
5
5
  Project-URL: Changelog, https://cofin.github.io/litestar-vite/latest/changelog
6
6
  Project-URL: Discord, https://discord.gg/X3FJqy8d2j
@@ -19,16 +19,16 @@ Classifier: License :: OSI Approved :: MIT License
19
19
  Classifier: Natural Language :: English
20
20
  Classifier: Operating System :: OS Independent
21
21
  Classifier: Programming Language :: Python
22
- Classifier: Programming Language :: Python :: 3.8
23
22
  Classifier: Programming Language :: Python :: 3.9
24
23
  Classifier: Programming Language :: Python :: 3.10
25
24
  Classifier: Programming Language :: Python :: 3.11
26
25
  Classifier: Programming Language :: Python :: 3.12
26
+ Classifier: Programming Language :: Python :: 3.13
27
27
  Classifier: Topic :: Database
28
28
  Classifier: Topic :: Database :: Database Engines/Servers
29
29
  Classifier: Topic :: Software Development
30
30
  Classifier: Typing :: Typed
31
- Requires-Python: >=3.8
31
+ Requires-Python: >=3.9
32
32
  Requires-Dist: litestar[jinja]>=2.7.0
33
33
  Provides-Extra: nodeenv
34
34
  Requires-Dist: nodeenv; extra == 'nodeenv'
@@ -5,11 +5,11 @@ classifiers = [
5
5
  "License :: OSI Approved :: MIT License",
6
6
  "Natural Language :: English",
7
7
  "Operating System :: OS Independent",
8
- "Programming Language :: Python :: 3.8",
9
8
  "Programming Language :: Python :: 3.9",
10
9
  "Programming Language :: Python :: 3.10",
11
10
  "Programming Language :: Python :: 3.11",
12
11
  "Programming Language :: Python :: 3.12",
12
+ "Programming Language :: Python :: 3.13",
13
13
  "Programming Language :: Python",
14
14
  "Topic :: Software Development",
15
15
  "Typing :: Typed",
@@ -24,8 +24,8 @@ keywords = ["litestar", "vite"]
24
24
  license = { text = "MIT" }
25
25
  name = "litestar-vite"
26
26
  readme = "README.md"
27
- requires-python = ">=3.8"
28
- version = "0.13.0"
27
+ requires-python = ">=3.9"
28
+ version = "0.13.1"
29
29
 
30
30
  [project.urls]
31
31
  Changelog = "https://cofin.github.io/litestar-vite/latest/changelog"
@@ -83,7 +83,7 @@ test = [
83
83
  allow_dirty = true
84
84
  commit = true
85
85
  commit_args = "--no-verify"
86
- current_version = "0.13.0"
86
+ current_version = "0.13.1"
87
87
  ignore_missing_files = false
88
88
  ignore_missing_version = false
89
89
  message = "chore(release): bump to v{new_version}"
@@ -262,17 +262,29 @@ lint.ignore = [
262
262
  "PLR0913", # too many arguments
263
263
  "PT",
264
264
  "TD",
265
+ "ARG002", # ignore for now; investigate
266
+ "ARG003", # ignore for now; investigate
265
267
  "PERF203", # ignore for now; investigate
268
+ "PD011", # pandas
269
+ "PLR0912",
266
270
  "ISC001",
267
271
  "COM812",
272
+ "CPY001",
273
+ "PGH003",
274
+ "FA100",
275
+ "PLC0415", # import should be at the top of the file
276
+ "PLR0904", # too many public methods
277
+ "PLR0914",
278
+ "PLR0917",
279
+ "PLC2701", # private import
280
+ "S704",
281
+ "S404",
268
282
  ]
269
283
  lint.select = ["ALL"]
270
- # Allow unused variables when underscore-prefixed.
271
- lint.dummy-variable-rgx = "^(_+|(_+[a-zA-Z0-9_]*[a-zA-Z0-9]+?))$"
272
284
  src = ["src/py/litestar_vite", "src/py/tests"]
273
- target-version = "py38"
285
+ target-version = "py39"
274
286
  unsafe-fixes = true
275
-
287
+ lint.extend-safe-fixes = ["TC"]
276
288
 
277
289
  [tool.ruff.lint.pydocstyle]
278
290
  convention = "google"
@@ -311,6 +323,7 @@ max-complexity = 12
311
323
  "UP006",
312
324
  "SLF001",
313
325
  "ERA001",
326
+
314
327
  ]
315
328
  "tools/*.py" = [ "PLR0911"]
316
329
 
@@ -318,8 +331,10 @@ max-complexity = 12
318
331
  known-first-party = ["litestar_vite", "tests"]
319
332
 
320
333
  [tool.pyright]
321
- venvPath = "."
322
334
  disableBytesTypePromotions = true
335
+ reportPrivateImportUsage = "none"
336
+ reportUnknownVariableType = "none"
337
+ reportUnnecessaryContains = "none"
323
338
  exclude = [
324
339
  "docs",
325
340
  "src/py/tests/unit/test_extensions",
@@ -328,9 +343,8 @@ exclude = [
328
343
  "src/py/tests/docker_service_fixtures.py",
329
344
  ]
330
345
  include = ["src/py/litestar_vite"]
331
- pythonVersion = "3.8"
346
+ pythonVersion = "3.9"
332
347
  strict = ["src/py/litestar_vite/**/*"]
333
- venv = ".venv"
334
348
 
335
349
  [tool.mypy]
336
350
  disallow_untyped_defs = false
@@ -350,66 +364,3 @@ module = "tests.*"
350
364
  [tool.codespell]
351
365
  ignore-words-list = "selectin"
352
366
  skip = 'uv.lock,examples/inertia/package-lock.json,examples/inertia/public/assets/*.js'
353
-
354
- [tool.git-cliff.changelog]
355
- body = """
356
- {% if version %}\
357
- `Release [v{{ version | trim_start_matches(pat="v") }}] - {{ timestamp | date(format="%Y-%m-%d") }} <https://github.com/cofin/litestar-vite/releases/tag/v{{ version | trim_start_matches(pat="v") }}>`_
358
- ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
359
- * `See All commits in v{{ version | trim_start_matches(pat="v") }} <https://github.com/cofin/litestar-vite/commits/v{{ version | trim_start_matches(pat="v") }}>`_
360
- {% else %}\
361
- [unreleased]
362
- ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
363
- {% endif %}\
364
- {% if previous %}\
365
- {% if previous.commit_id %}
366
- `{{ previous.commit_id | truncate(length=7, end="") }} <https://github.com/cofin/litestar-vite/commit/{{ previous.commit_id }}>`_ ... \
367
- `{{ commit_id | truncate(length=7, end="") }} <https://github.com/cofin/litestar-vite/commit/{{ commit_id }}>`_ \
368
- | `See diff for {{ version | trim_start_matches(pat="v") }} <https://github.com/cofin/litestar-vite/compare/{{ previous.commit_id }}...{{ commit_id }}>`_
369
- {% endif %}\
370
- {% endif %}\
371
- {% for group, commits in commits | group_by(attribute="group") %}
372
- {{ group | upper_first }}
373
- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
374
- {% for commit in commits %}
375
- * (`{{ commit.id | truncate(length=7, end="") }} <https://github.com/cofin/litestar-vite/commit/{{ commit.id }}>`_) {% if commit.breaking %}[**breaking**] {% endif %} - {{ commit.message | upper_first }} ({{ commit.author.name }})\
376
- {% for footer in commit.footers -%}
377
- , {{ footer.token }}{{ footer.separator }}{{ footer.value }}\
378
- {% endfor %}\
379
- {% endfor %}
380
- {% endfor %}\n
381
- """
382
- footer = """
383
- Litestar vite Changelog
384
- """
385
- header = """
386
- =========
387
- Changelog
388
- =========\n
389
- All commits to this project will be documented in this file.\n
390
- """
391
- trim = true
392
-
393
- [tool.git-cliff.git]
394
- commit_parsers = [
395
- { message = "^feat", group = "Features" },
396
- { message = "^fix", group = "Bug Fixes" },
397
- { message = "^doc", group = "Documentation" },
398
- { message = "^perf", group = "Performance" },
399
- { message = "^refactor", group = "Refactor" },
400
- { message = "^style", group = "Styling" },
401
- { message = "^test", group = "Testing" },
402
- { message = "^chore\\(release\\): prepare for", skip = true },
403
- { message = "^chore", group = "Miscellaneous Tasks" },
404
- { body = ".*security", group = "Security" },
405
- ]
406
- conventional_commits = true
407
- filter_commits = false
408
- filter_unconventional = true
409
- ignore_tags = ""
410
- protect_breaking_commits = false
411
- skip_tags = "v0.1.0-beta.1"
412
- sort_commits = "oldest"
413
- split_commits = false
414
- tag_pattern = "v[0-9]*"
415
- topo_order = false
@@ -3,7 +3,7 @@ import type { AddressInfo } from "node:net"
3
3
  import path from "node:path"
4
4
  import { fileURLToPath } from "node:url"
5
5
  import colors from "picocolors"
6
- import { type ConfigEnv, type Plugin, type PluginOption, type ResolvedConfig, type SSROptions, type UserConfig, loadEnv } from "vite"
6
+ import { type ConfigEnv, type Plugin, type PluginOption, type ResolvedConfig, type SSROptions, type UserConfig, type ViteDevServer, loadEnv } from "vite"
7
7
  import fullReload, { type Config as FullReloadConfig } from "vite-plugin-full-reload"
8
8
 
9
9
  interface PluginConfig {
@@ -101,6 +101,38 @@ export default function litestar(config: string | string[] | PluginConfig): [Lit
101
101
  return [resolveLitestarPlugin(pluginConfig), ...(resolveFullReloadConfig(pluginConfig) as Plugin[])]
102
102
  }
103
103
 
104
+ /**
105
+ * Resolve the index.html path to use for the Vite server.
106
+ */
107
+ async function findIndexHtmlPath(server: ViteDevServer, pluginConfig: Required<PluginConfig>): Promise<string | null> {
108
+ if (!pluginConfig.autoDetectIndex) {
109
+ console.log("Auto-detection disabled.") // Debug log
110
+ return null
111
+ }
112
+
113
+ // Use server.config.root which is the resolved root directory
114
+ const root = server.config.root
115
+ const possiblePaths = [
116
+ path.join(root, "index.html"),
117
+ path.join(root, pluginConfig.resourceDirectory.replace(/^\//, ""), "index.html"), // Ensure resourceDirectory path is relative to root
118
+ path.join(root, "public", "index.html"), // Check public even if publicDir is false, might exist
119
+ ]
120
+ // console.log("Checking paths:", possiblePaths); // Debug log
121
+
122
+ for (const indexPath of possiblePaths) {
123
+ try {
124
+ // Use async access check
125
+ await fs.promises.access(indexPath)
126
+ // console.log("Found index.html at:", indexPath); // Debug log
127
+ return indexPath
128
+ } catch {
129
+ // File doesn't exist at this path, continue checking
130
+ }
131
+ }
132
+ // console.log("index.html not found in checked paths."); // Debug log
133
+ return null
134
+ }
135
+
104
136
  /**
105
137
  * Resolve the Litestar Plugin configuration.
106
138
  */
@@ -108,9 +140,8 @@ function resolveLitestarPlugin(pluginConfig: Required<PluginConfig>): LitestarPl
108
140
  let viteDevServerUrl: DevServerUrl
109
141
  let resolvedConfig: ResolvedConfig
110
142
  let userConfig: UserConfig
111
-
112
143
  const defaultAliases: Record<string, string> = {
113
- "@": pluginConfig.resourceDirectory || "/resources/",
144
+ "@": `/${pluginConfig.resourceDirectory.replace(/^\/+/, "").replace(/\/+$/, "")}/`,
114
145
  }
115
146
 
116
147
  return {
@@ -178,14 +209,30 @@ function resolveLitestarPlugin(pluginConfig: Required<PluginConfig>): LitestarPl
178
209
  ssr: {
179
210
  noExternal: noExternalInertiaHelpers(userConfig),
180
211
  },
212
+ // Explicitly set appType if you know you're serving an SPA index.html
213
+ // appType: 'spa', // Try adding this - might simplify things if appropriate
181
214
  }
182
215
  },
183
216
  configResolved(config) {
184
217
  resolvedConfig = config
218
+ // Ensure base ends with / for dev server if not empty
219
+ if (resolvedConfig.command === "serve" && resolvedConfig.base && !resolvedConfig.base.endsWith("/")) {
220
+ resolvedConfig = {
221
+ ...resolvedConfig,
222
+ base: `${resolvedConfig.base}/`,
223
+ }
224
+ }
225
+ // Debug log resolved config
226
+ // console.log("Resolved Vite Config:", resolvedConfig);
185
227
  },
186
- transform(code: string): string | undefined {
187
- if (resolvedConfig.command === "serve") {
228
+ transform(code: string, id: string): string | undefined {
229
+ // Added 'id' for context
230
+ // Avoid transforming unrelated files during serve if placeholder isn't present
231
+ if (resolvedConfig.command === "serve" && code.includes("__litestar_vite_placeholder__")) {
232
+ // Debug log transformation
233
+ // console.log(`Transforming ${id} with dev server URL: ${viteDevServerUrl}`);
188
234
  const transformedCode = code.replace(/__litestar_vite_placeholder__/g, viteDevServerUrl)
235
+ // Apply user transform *only* if the placeholder was found and replaced
189
236
  return pluginConfig.transformOnServe(transformedCode, viteDevServerUrl)
190
237
  }
191
238
  return undefined
@@ -194,25 +241,8 @@ function resolveLitestarPlugin(pluginConfig: Required<PluginConfig>): LitestarPl
194
241
  const envDir = resolvedConfig.envDir || process.cwd()
195
242
  const appUrl = loadEnv(resolvedConfig.mode, envDir, "APP_URL").APP_URL ?? "undefined"
196
243
 
197
- // Check if we should serve SPA directly
198
- const shouldServeIndex = () => {
199
- if (!pluginConfig.autoDetectIndex) return false
200
-
201
- // Check various common locations for index.html
202
- const possiblePaths = [
203
- path.join(server.config.root, "index.html"),
204
- path.join(server.config.root, pluginConfig.resourceDirectory, "index.html"),
205
- path.join(server.config.root, "public", "index.html"),
206
- ]
207
-
208
- for (const indexPath of possiblePaths) {
209
- try {
210
- fs.accessSync(indexPath)
211
- return true
212
- } catch {}
213
- }
214
- return false
215
- }
244
+ // Find index.html path *once* when server starts for logging purposes
245
+ const initialIndexPath = await findIndexHtmlPath(server, pluginConfig)
216
246
 
217
247
  server.httpServer?.once("listening", () => {
218
248
  const address = server.httpServer?.address()
@@ -223,53 +253,91 @@ function resolveLitestarPlugin(pluginConfig: Required<PluginConfig>): LitestarPl
223
253
  fs.mkdirSync(path.dirname(pluginConfig.hotFile), { recursive: true })
224
254
  fs.writeFileSync(pluginConfig.hotFile, viteDevServerUrl)
225
255
 
226
- const hasIndex = shouldServeIndex()
227
-
228
256
  setTimeout(() => {
229
- server.config.logger.info(`\n ${colors.red(`${colors.bold("LITESTAR")} ${litestarVersion()}`)} ${colors.dim("plugin")} ${colors.bold(`v${pluginVersion()}`)}`)
230
- server.config.logger.info("")
231
- if (hasIndex) {
232
- server.config.logger.info(` ${colors.green("➜")} ${colors.bold("Serve Index")}: Serving application index with Vite`)
233
- server.config.logger.info(` ${colors.green("➜")} ${colors.bold("DEV URL")}: ${colors.cyan(viteDevServerUrl)}`)
234
- server.config.logger.info(` ${colors.green("➜")} ${colors.bold("APP_URL")}: ${colors.cyan(appUrl.replace(/:(\d+)/, (_, port) => `:${colors.bold(port)}`))}`)
257
+ // Use resolvedConfig.logger for consistency
258
+ resolvedConfig.logger.info(`\n ${colors.red(`${colors.bold("LITESTAR")} ${litestarVersion()}`)} ${colors.dim("plugin")} ${colors.bold(`v${pluginVersion()}`)}`)
259
+ resolvedConfig.logger.info("")
260
+ if (initialIndexPath) {
261
+ resolvedConfig.logger.info(
262
+ ` ${colors.green("➜")} ${colors.bold("Index Mode")}: SPA (Serving ${colors.cyan(path.relative(server.config.root, initialIndexPath))} from root)`,
263
+ )
235
264
  } else {
236
- server.config.logger.info(` ${colors.green("➜")} ${colors.bold("Serve Index")}: Serving Litestar index with Vite`)
237
- server.config.logger.info(` ${colors.green("➜")} ${colors.bold("DEV URL")}: ${colors.cyan(viteDevServerUrl)}`)
238
- server.config.logger.info(` ${colors.green("➜")} ${colors.bold("APP_URL")}: ${colors.cyan(appUrl.replace(/:(\d+)/, (_, port) => `:${colors.bold(port)}`))}`)
265
+ resolvedConfig.logger.info(` ${colors.green("➜")} ${colors.bold("Index Mode")}: Litestar (Plugin will serve placeholder for /index.html)`)
239
266
  }
267
+ resolvedConfig.logger.info(` ${colors.green("➜")} ${colors.bold("Dev Server")}: ${colors.cyan(viteDevServerUrl)}`)
268
+ resolvedConfig.logger.info(` ${colors.green("➜")} ${colors.bold("App URL")}: ${colors.cyan(appUrl.replace(/:(\d+)/, (_, port) => `:${colors.bold(port)}`))}`)
269
+ resolvedConfig.logger.info(` ${colors.green("➜")} ${colors.bold("Assets Base")}: ${colors.cyan(resolvedConfig.base)}`) // Log the base path being used
240
270
  }, 100)
241
271
  }
242
272
  })
273
+
274
+ // Clean up hot file
243
275
  if (!exitHandlersBound) {
244
276
  const clean = () => {
245
- if (fs.existsSync(pluginConfig.hotFile)) {
277
+ if (pluginConfig.hotFile && fs.existsSync(pluginConfig.hotFile)) {
278
+ // Check hotFile exists
246
279
  fs.rmSync(pluginConfig.hotFile)
247
280
  }
248
281
  }
249
-
250
282
  process.on("exit", clean)
251
283
  process.on("SIGINT", () => process.exit())
252
284
  process.on("SIGTERM", () => process.exit())
253
285
  process.on("SIGHUP", () => process.exit())
254
-
255
286
  exitHandlersBound = true
256
287
  }
257
288
 
258
- return () =>
259
- server.middlewares.use((req, res, next) => {
260
- if (!shouldServeIndex() && req.url === "/index.html") {
261
- res.statusCode = 404
262
-
263
- res.end(
264
- fs
265
- .readFileSync(path.join(dirname(), "dev-server-index.html"))
266
- .toString()
267
- .replace(/{{ APP_URL }}/g, appUrl),
268
- )
289
+ // *** MODIFIED MIDDLEWARE ***
290
+ return () => {
291
+ // Run middleware early to intercept before Vite's base/HTML handlers
292
+ server.middlewares.use(async (req, res, next) => {
293
+ const indexPath = await findIndexHtmlPath(server, pluginConfig)
294
+
295
+ // Check if index.html exists AND the request is for the root or /index.html
296
+ if (indexPath && (req.url === "/" || req.url === "/index.html")) {
297
+ try {
298
+ const htmlContent = await fs.promises.readFile(indexPath, "utf-8")
299
+ // Transform the HTML using Vite's pipeline
300
+ const transformedHtml = await server.transformIndexHtml(
301
+ "/", // Use '/' as the URL for transformation context to ensure scripts are injected correctly relative to root
302
+ htmlContent,
303
+ req.originalUrl,
304
+ )
305
+ res.statusCode = 200
306
+ res.setHeader("Content-Type", "text/html")
307
+ res.end(transformedHtml)
308
+ // Request handled, stop further processing
309
+ return
310
+ } catch (e) {
311
+ // Log the error and pass it to Vite's error handler
312
+ resolvedConfig.logger.error(`Error serving index.html from ${indexPath}: ${e instanceof Error ? e.message : e}`)
313
+ next(e)
314
+ return
315
+ }
269
316
  }
270
317
 
318
+ // Original logic: If index.html should NOT be served automatically,
319
+ // AND the request is specifically for /index.html, serve the placeholder.
320
+ // Requests for '/' will likely be handled by Litestar in this case.
321
+ if (!indexPath && req.url === "/index.html") {
322
+ try {
323
+ const placeholderPath = path.join(dirname(), "dev-server-index.html")
324
+ const placeholderContent = await fs.promises.readFile(placeholderPath, "utf-8")
325
+ res.statusCode = 200 // Serve placeholder with 200 OK, or 404 if preferred
326
+ res.setHeader("Content-Type", "text/html")
327
+ res.end(placeholderContent.replace(/{{ APP_URL }}/g, appUrl))
328
+ } catch (e) {
329
+ resolvedConfig.logger.error(`Error serving placeholder index.html: ${e instanceof Error ? e.message : e}`)
330
+ res.statusCode = 404
331
+ res.end("Not Found (Error loading placeholder)")
332
+ }
333
+ // Request handled (or error), stop further processing
334
+ return
335
+ }
336
+
337
+ // If none of the above conditions matched, pass the request to the next middleware (Vite's default handlers)
271
338
  next()
272
339
  })
340
+ }
273
341
  },
274
342
  }
275
343
  }
@@ -327,7 +395,7 @@ function resolvePluginConfig(config: string | string[] | PluginConfig): Required
327
395
  throw new Error('litestar-vite-plugin: missing configuration for "input".')
328
396
  }
329
397
  if (typeof resolvedConfig.resourceDirectory === "string") {
330
- resolvedConfig.resourceDirectory = resolvedConfig.resourceDirectory.trim().replace(/^\/+/, "")
398
+ resolvedConfig.resourceDirectory = resolvedConfig.resourceDirectory.trim().replace(/^\/+/, "").replace(/\/+$/, "")
331
399
 
332
400
  if (resolvedConfig.resourceDirectory === "") {
333
401
  throw new Error("litestar-vite-plugin: resourceDirectory must be a subdirectory. E.g. 'resources'.")
@@ -353,8 +421,8 @@ function resolvePluginConfig(config: string | string[] | PluginConfig): Required
353
421
  return {
354
422
  input: resolvedConfig.input,
355
423
  assetUrl: resolvedConfig.assetUrl ?? "static",
356
- resourceDirectory: resolvedConfig.resourceDirectory ?? "/resources/",
357
- bundleDirectory: resolvedConfig.bundleDirectory || (resolvedConfig.bundleDirectory ?? "public"),
424
+ resourceDirectory: resolvedConfig.resourceDirectory ?? "resources",
425
+ bundleDirectory: resolvedConfig.bundleDirectory ?? "public",
358
426
  ssr: resolvedConfig.ssr ?? resolvedConfig.input,
359
427
  ssrOutputDirectory: resolvedConfig.ssrOutputDirectory ?? path.join(resolvedConfig.resourceDirectory ?? "resources", "bootstrap/ssr"),
360
428
  refresh: resolvedConfig.refresh ?? false,
@@ -369,7 +437,12 @@ function resolvePluginConfig(config: string | string[] | PluginConfig): Required
369
437
  * Resolve the Vite base option from the configuration.
370
438
  */
371
439
  function resolveBase(config: Required<PluginConfig>, assetUrl: string): string {
372
- return assetUrl + (assetUrl.endsWith("/") ? "" : "/")
440
+ // In development mode, use the assetUrl directly
441
+ if (process.env.NODE_ENV === "development") {
442
+ return assetUrl
443
+ }
444
+ // In production, use the full assetUrl
445
+ return assetUrl.endsWith("/") ? assetUrl : `${assetUrl}/`
373
446
  }
374
447
 
375
448
  /**
@@ -385,13 +458,15 @@ function resolveInput(config: Required<PluginConfig>, ssr: boolean): string | st
385
458
 
386
459
  /**
387
460
  * Resolve the Vite outDir path from the configuration.
461
+ * Should be relative to the project root for Vite config, Vite resolves it internally.
388
462
  */
389
- function resolveOutDir(config: Required<PluginConfig>, ssr: boolean): string | undefined {
463
+ function resolveOutDir(config: Required<PluginConfig>, ssr: boolean): string {
390
464
  if (ssr) {
391
- return config.ssrOutputDirectory
465
+ // Return path relative to root
466
+ return config.ssrOutputDirectory.replace(/^\/+/, "").replace(/\/+$/, "")
392
467
  }
393
-
394
- return path.join(config.bundleDirectory)
468
+ // Return path relative to root
469
+ return config.bundleDirectory.replace(/^\/+/, "").replace(/\/+$/, "")
395
470
  }
396
471
 
397
472
  function resolveFullReloadConfig({ refresh: config }: Required<PluginConfig>): PluginOption[] {