litestar-vite 0.13.0__tar.gz → 0.13.2__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.2}/.gitignore +5 -0
  2. {litestar_vite-0.13.0 → litestar_vite-0.13.2}/PKG-INFO +3 -3
  3. {litestar_vite-0.13.0 → litestar_vite-0.13.2}/pyproject.toml +26 -74
  4. {litestar_vite-0.13.0 → litestar_vite-0.13.2}/src/js/src/index.ts +137 -58
  5. {litestar_vite-0.13.0 → litestar_vite-0.13.2}/src/js/tests/index.test.ts +233 -19
  6. {litestar_vite-0.13.0 → litestar_vite-0.13.2}/src/py/litestar_vite/__init__.py +0 -2
  7. {litestar_vite-0.13.0 → litestar_vite-0.13.2}/src/py/litestar_vite/__metadata__.py +0 -2
  8. {litestar_vite-0.13.0 → litestar_vite-0.13.2}/src/py/litestar_vite/cli.py +33 -40
  9. {litestar_vite-0.13.0 → litestar_vite-0.13.2}/src/py/litestar_vite/commands.py +48 -38
  10. {litestar_vite-0.13.0 → litestar_vite-0.13.2}/src/py/litestar_vite/config.py +6 -7
  11. litestar_vite-0.13.2/src/py/litestar_vite/inertia/_utils.py +99 -0
  12. {litestar_vite-0.13.0 → litestar_vite-0.13.2}/src/py/litestar_vite/inertia/config.py +5 -7
  13. {litestar_vite-0.13.0 → litestar_vite-0.13.2}/src/py/litestar_vite/inertia/exception_handler.py +22 -8
  14. {litestar_vite-0.13.0 → litestar_vite-0.13.2}/src/py/litestar_vite/inertia/helpers.py +57 -61
  15. {litestar_vite-0.13.0 → litestar_vite-0.13.2}/src/py/litestar_vite/inertia/middleware.py +4 -6
  16. {litestar_vite-0.13.0 → litestar_vite-0.13.2}/src/py/litestar_vite/inertia/plugin.py +22 -9
  17. {litestar_vite-0.13.0 → litestar_vite-0.13.2}/src/py/litestar_vite/inertia/request.py +58 -20
  18. {litestar_vite-0.13.0 → litestar_vite-0.13.2}/src/py/litestar_vite/inertia/response.py +42 -40
  19. {litestar_vite-0.13.0 → litestar_vite-0.13.2}/src/py/litestar_vite/inertia/routes.py +7 -9
  20. {litestar_vite-0.13.0 → litestar_vite-0.13.2}/src/py/litestar_vite/inertia/types.py +6 -8
  21. {litestar_vite-0.13.0 → litestar_vite-0.13.2}/src/py/litestar_vite/loader.py +95 -29
  22. {litestar_vite-0.13.0 → litestar_vite-0.13.2}/src/py/litestar_vite/plugin.py +42 -38
  23. {litestar_vite-0.13.0 → litestar_vite-0.13.2}/src/py/tests/conftest.py +1 -1
  24. {litestar_vite-0.13.0 → litestar_vite-0.13.2}/src/py/tests/test_asset_loader.py +2 -1
  25. {litestar_vite-0.13.0 → litestar_vite-0.13.2}/src/py/tests/test_cli/conftest.py +2 -1
  26. {litestar_vite-0.13.0 → litestar_vite-0.13.2}/src/py/tests/test_inertia/test_response.py +11 -11
  27. {litestar_vite-0.13.0 → litestar_vite-0.13.2}/tools/sphinx_ext/__init__.py +3 -1
  28. {litestar_vite-0.13.0 → litestar_vite-0.13.2}/tools/sphinx_ext/missing_references.py +3 -3
  29. litestar_vite-0.13.0/src/py/litestar_vite/inertia/_utils.py +0 -63
  30. {litestar_vite-0.13.0 → litestar_vite-0.13.2}/LICENSE +0 -0
  31. {litestar_vite-0.13.0 → litestar_vite-0.13.2}/README.md +0 -0
  32. {litestar_vite-0.13.0 → litestar_vite-0.13.2}/src/js/LICENSE +0 -0
  33. {litestar_vite-0.13.0 → litestar_vite-0.13.2}/src/js/Makefile +0 -0
  34. {litestar_vite-0.13.0 → litestar_vite-0.13.2}/src/js/NOTICE +0 -0
  35. {litestar_vite-0.13.0 → litestar_vite-0.13.2}/src/js/README.md +0 -0
  36. {litestar_vite-0.13.0 → litestar_vite-0.13.2}/src/js/src/dev-server-index.html +0 -0
  37. {litestar_vite-0.13.0 → litestar_vite-0.13.2}/src/js/src/inertia-helpers/index.ts +0 -0
  38. {litestar_vite-0.13.0 → litestar_vite-0.13.2}/src/js/tests/__data__/dummy.ts +0 -0
  39. {litestar_vite-0.13.0 → litestar_vite-0.13.2}/src/js/tsconfig.inertia-helpers.json +0 -0
  40. {litestar_vite-0.13.0 → litestar_vite-0.13.2}/src/js/tsconfig.json +0 -0
  41. {litestar_vite-0.13.0 → litestar_vite-0.13.2}/src/js/vitest.config.ts +0 -0
  42. {litestar_vite-0.13.0 → litestar_vite-0.13.2}/src/js/vitest.workspace.ts +0 -0
  43. {litestar_vite-0.13.0 → litestar_vite-0.13.2}/src/py/litestar_vite/inertia/__init__.py +0 -0
  44. {litestar_vite-0.13.0 → litestar_vite-0.13.2}/src/py/litestar_vite/py.typed +0 -0
  45. {litestar_vite-0.13.0 → litestar_vite-0.13.2}/src/py/litestar_vite/templates/__init__.py +0 -0
  46. {litestar_vite-0.13.0 → litestar_vite-0.13.2}/src/py/litestar_vite/templates/index.html.j2 +0 -0
  47. {litestar_vite-0.13.0 → litestar_vite-0.13.2}/src/py/litestar_vite/templates/main.ts.j2 +0 -0
  48. {litestar_vite-0.13.0 → litestar_vite-0.13.2}/src/py/litestar_vite/templates/package.json.j2 +0 -0
  49. {litestar_vite-0.13.0 → litestar_vite-0.13.2}/src/py/litestar_vite/templates/styles.css.j2 +0 -0
  50. {litestar_vite-0.13.0 → litestar_vite-0.13.2}/src/py/litestar_vite/templates/tsconfig.json.j2 +0 -0
  51. {litestar_vite-0.13.0 → litestar_vite-0.13.2}/src/py/litestar_vite/templates/vite.config.ts.j2 +0 -0
  52. {litestar_vite-0.13.0 → litestar_vite-0.13.2}/src/py/tests/__init__.py +0 -0
  53. {litestar_vite-0.13.0 → litestar_vite-0.13.2}/src/py/tests/py.typed +0 -0
  54. {litestar_vite-0.13.0 → litestar_vite-0.13.2}/src/py/tests/templates/__init__.py +0 -0
  55. {litestar_vite-0.13.0 → litestar_vite-0.13.2}/src/py/tests/templates/index.html.j2 +0 -0
  56. {litestar_vite-0.13.0 → litestar_vite-0.13.2}/src/py/tests/test_app/__init__.py +0 -0
  57. {litestar_vite-0.13.0 → litestar_vite-0.13.2}/src/py/tests/test_app/app.py +0 -0
  58. {litestar_vite-0.13.0 → litestar_vite-0.13.2}/src/py/tests/test_app/web/__init__.py +0 -0
  59. {litestar_vite-0.13.0 → litestar_vite-0.13.2}/src/py/tests/test_app/web/public/.gitkeep +0 -0
  60. {litestar_vite-0.13.0 → litestar_vite-0.13.2}/src/py/tests/test_app/web/public/assets/main-l0sNRNKZ.js +0 -0
  61. {litestar_vite-0.13.0 → litestar_vite-0.13.2}/src/py/tests/test_app/web/public/assets/styles-l0sNRNKZ.js +0 -0
  62. {litestar_vite-0.13.0 → litestar_vite-0.13.2}/src/py/tests/test_app/web/public/manifest.json +0 -0
  63. {litestar_vite-0.13.0 → litestar_vite-0.13.2}/src/py/tests/test_app/web/resources/.gitkeep +0 -0
  64. {litestar_vite-0.13.0 → litestar_vite-0.13.2}/src/py/tests/test_app/web/resources/main.ts +0 -0
  65. {litestar_vite-0.13.0 → litestar_vite-0.13.2}/src/py/tests/test_app/web/resources/styles.css +0 -0
  66. {litestar_vite-0.13.0 → litestar_vite-0.13.2}/src/py/tests/test_app/web/templates/.gitkeep +0 -0
  67. {litestar_vite-0.13.0 → litestar_vite-0.13.2}/src/py/tests/test_app/web/templates/index.html +0 -0
  68. {litestar_vite-0.13.0 → litestar_vite-0.13.2}/src/py/tests/test_cli/__init__.py +0 -0
  69. {litestar_vite-0.13.0 → litestar_vite-0.13.2}/src/py/tests/test_cli/test_init.py +0 -0
  70. {litestar_vite-0.13.0 → litestar_vite-0.13.2}/src/py/tests/test_commands.py +0 -0
  71. {litestar_vite-0.13.0 → litestar_vite-0.13.2}/src/py/tests/test_config.py +0 -0
  72. {litestar_vite-0.13.0 → litestar_vite-0.13.2}/src/py/tests/test_inertia/__init__.py +0 -0
  73. {litestar_vite-0.13.0 → litestar_vite-0.13.2}/src/py/tests/test_inertia/conftest.py +0 -0
  74. {litestar_vite-0.13.0 → litestar_vite-0.13.2}/src/py/tests/test_inertia/templates/index.html.j2 +0 -0
  75. {litestar_vite-0.13.0 → litestar_vite-0.13.2}/src/py/tests/test_inertia/test_request.py +0 -0
  76. {litestar_vite-0.13.0 → litestar_vite-0.13.2}/src/py/tests/test_inertia/test_routes.py +0 -0
  77. {litestar_vite-0.13.0 → litestar_vite-0.13.2}/tools/__init__.py +0 -0
  78. {litestar_vite-0.13.0 → litestar_vite-0.13.2}/tools/build_docs.py +0 -0
  79. {litestar_vite-0.13.0 → litestar_vite-0.13.2}/tools/clean.js +0 -0
  80. {litestar_vite-0.13.0 → litestar_vite-0.13.2}/tools/pypi_readme.py +0 -0
  81. {litestar_vite-0.13.0 → litestar_vite-0.13.2}/tools/sphinx_ext/changelog.py +0 -0
@@ -167,3 +167,8 @@ cython_debug/
167
167
 
168
168
  node_modules
169
169
  .aider*
170
+
171
+ .DS_Store
172
+ *.swo
173
+ *.swp
174
+ .venv
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: litestar-vite
3
- Version: 0.13.0
3
+ Version: 0.13.2
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.2"
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.2"
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,30 @@ 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",
282
+ "PLR6301"
268
283
  ]
269
284
  lint.select = ["ALL"]
270
- # Allow unused variables when underscore-prefixed.
271
- lint.dummy-variable-rgx = "^(_+|(_+[a-zA-Z0-9_]*[a-zA-Z0-9]+?))$"
272
285
  src = ["src/py/litestar_vite", "src/py/tests"]
273
- target-version = "py38"
286
+ target-version = "py39"
274
287
  unsafe-fixes = true
275
-
288
+ lint.extend-safe-fixes = ["TC"]
276
289
 
277
290
  [tool.ruff.lint.pydocstyle]
278
291
  convention = "google"
@@ -311,6 +324,7 @@ max-complexity = 12
311
324
  "UP006",
312
325
  "SLF001",
313
326
  "ERA001",
327
+
314
328
  ]
315
329
  "tools/*.py" = [ "PLR0911"]
316
330
 
@@ -318,8 +332,10 @@ max-complexity = 12
318
332
  known-first-party = ["litestar_vite", "tests"]
319
333
 
320
334
  [tool.pyright]
321
- venvPath = "."
322
335
  disableBytesTypePromotions = true
336
+ reportPrivateImportUsage = "none"
337
+ reportUnknownVariableType = "none"
338
+ reportUnnecessaryContains = "none"
323
339
  exclude = [
324
340
  "docs",
325
341
  "src/py/tests/unit/test_extensions",
@@ -328,9 +344,8 @@ exclude = [
328
344
  "src/py/tests/docker_service_fixtures.py",
329
345
  ]
330
346
  include = ["src/py/litestar_vite"]
331
- pythonVersion = "3.8"
347
+ pythonVersion = "3.9"
332
348
  strict = ["src/py/litestar_vite/**/*"]
333
- venv = ".venv"
334
349
 
335
350
  [tool.mypy]
336
351
  disallow_untyped_defs = false
@@ -350,66 +365,3 @@ module = "tests.*"
350
365
  [tool.codespell]
351
366
  ignore-words-list = "selectin"
352
367
  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,86 @@ 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
+ if (indexPath && (req.url === "/" || req.url === "/index.html")) {
295
+ const currentUrl = req.url
296
+ try {
297
+ const htmlContent = await fs.promises.readFile(indexPath, "utf-8")
298
+ // Transform the HTML using Vite's pipeline
299
+ const transformedHtml = await server.transformIndexHtml(req.originalUrl ?? currentUrl, htmlContent, req.originalUrl)
300
+ res.statusCode = 200
301
+ res.setHeader("Content-Type", "text/html")
302
+ res.end(transformedHtml)
303
+ // Request handled, stop further processing
304
+ return
305
+ } catch (e) {
306
+ // Log the error and pass it to Vite's error handler
307
+ resolvedConfig.logger.error(`Error serving index.html from ${indexPath}: ${e instanceof Error ? e.message : e}`)
308
+ next(e)
309
+ return
310
+ }
311
+ }
312
+
313
+ // Original logic: If index.html should NOT be served automatically,
314
+ // AND the request is specifically for /index.html, serve the placeholder.
315
+ // Requests for '/' will likely be handled by Litestar in this case.
316
+ if (!indexPath && req.url === "/index.html") {
317
+ try {
318
+ const placeholderPath = path.join(dirname(), "dev-server-index.html")
319
+ const placeholderContent = await fs.promises.readFile(placeholderPath, "utf-8")
320
+ res.statusCode = 200 // Serve placeholder with 200 OK, or 404 if preferred
321
+ res.setHeader("Content-Type", "text/html")
322
+ res.end(placeholderContent.replace(/{{ APP_URL }}/g, appUrl))
323
+ } catch (e) {
324
+ resolvedConfig.logger.error(`Error serving placeholder index.html: ${e instanceof Error ? e.message : e}`)
325
+ res.statusCode = 404
326
+ res.end("Not Found (Error loading placeholder)")
327
+ }
328
+ // Request handled (or error), stop further processing
329
+ return
269
330
  }
270
331
 
332
+ // If none of the above conditions matched, pass the request to the next middleware (Vite's default handlers)
271
333
  next()
272
334
  })
335
+ }
273
336
  },
274
337
  }
275
338
  }
@@ -327,7 +390,7 @@ function resolvePluginConfig(config: string | string[] | PluginConfig): Required
327
390
  throw new Error('litestar-vite-plugin: missing configuration for "input".')
328
391
  }
329
392
  if (typeof resolvedConfig.resourceDirectory === "string") {
330
- resolvedConfig.resourceDirectory = resolvedConfig.resourceDirectory.trim().replace(/^\/+/, "")
393
+ resolvedConfig.resourceDirectory = resolvedConfig.resourceDirectory.trim().replace(/^\/+/, "").replace(/\/+$/, "")
331
394
 
332
395
  if (resolvedConfig.resourceDirectory === "") {
333
396
  throw new Error("litestar-vite-plugin: resourceDirectory must be a subdirectory. E.g. 'resources'.")
@@ -353,8 +416,8 @@ function resolvePluginConfig(config: string | string[] | PluginConfig): Required
353
416
  return {
354
417
  input: resolvedConfig.input,
355
418
  assetUrl: resolvedConfig.assetUrl ?? "static",
356
- resourceDirectory: resolvedConfig.resourceDirectory ?? "/resources/",
357
- bundleDirectory: resolvedConfig.bundleDirectory || (resolvedConfig.bundleDirectory ?? "public"),
419
+ resourceDirectory: resolvedConfig.resourceDirectory ?? "resources",
420
+ bundleDirectory: resolvedConfig.bundleDirectory ?? "public",
358
421
  ssr: resolvedConfig.ssr ?? resolvedConfig.input,
359
422
  ssrOutputDirectory: resolvedConfig.ssrOutputDirectory ?? path.join(resolvedConfig.resourceDirectory ?? "resources", "bootstrap/ssr"),
360
423
  refresh: resolvedConfig.refresh ?? false,
@@ -369,7 +432,12 @@ function resolvePluginConfig(config: string | string[] | PluginConfig): Required
369
432
  * Resolve the Vite base option from the configuration.
370
433
  */
371
434
  function resolveBase(config: Required<PluginConfig>, assetUrl: string): string {
372
- return assetUrl + (assetUrl.endsWith("/") ? "" : "/")
435
+ // In development mode, use the assetUrl directly
436
+ if (process.env.NODE_ENV === "development") {
437
+ return assetUrl
438
+ }
439
+ // In production, use the full assetUrl
440
+ return assetUrl.endsWith("/") ? assetUrl : `${assetUrl}/`
373
441
  }
374
442
 
375
443
  /**
@@ -385,13 +453,15 @@ function resolveInput(config: Required<PluginConfig>, ssr: boolean): string | st
385
453
 
386
454
  /**
387
455
  * Resolve the Vite outDir path from the configuration.
456
+ * Should be relative to the project root for Vite config, Vite resolves it internally.
388
457
  */
389
- function resolveOutDir(config: Required<PluginConfig>, ssr: boolean): string | undefined {
458
+ function resolveOutDir(config: Required<PluginConfig>, ssr: boolean): string {
390
459
  if (ssr) {
391
- return config.ssrOutputDirectory
460
+ // Return path relative to root
461
+ return config.ssrOutputDirectory.replace(/^\/+/, "").replace(/\/+$/, "")
392
462
  }
393
-
394
- return path.join(config.bundleDirectory)
463
+ // Return path relative to root
464
+ return config.bundleDirectory.replace(/^\/+/, "").replace(/\/+$/, "")
395
465
  }
396
466
 
397
467
  function resolveFullReloadConfig({ refresh: config }: Required<PluginConfig>): PluginOption[] {
@@ -598,5 +668,14 @@ function resolveDevelopmentEnvironmentTld(configPath: string): string {
598
668
  * The directory of the current file.
599
669
  */
600
670
  function dirname(): string {
601
- return fileURLToPath(new URL(".", import.meta.url))
671
+ // Use path.resolve relative to process.cwd() as a more robust alternative
672
+ // Assumes the script runs from the project root or similar predictable location.
673
+ // Adjust the relative path if necessary based on actual execution context.
674
+ try {
675
+ // Attempt original method first
676
+ return fileURLToPath(new URL(".", import.meta.url))
677
+ } catch {
678
+ // Fallback for environments where import.meta.url is problematic (like some test runners)
679
+ return path.resolve(process.cwd(), "src/js/src")
680
+ }
602
681
  }