Skip to content

Commit f3cca09

Browse files
authored
fix: write bridge before asset build codegen (#319)
## Summary - Write `.litestar.json` at the start of the `litestar assets build` / deploy build preparation path, before route export, pre-build code generators, JS typegen, or Vite itself can read the bridge. - Add a regression test that asserts the bridge file and `LITESTAR_VITE_CONFIG_PATH` are available before `TypeGenConfig.extra_commands` run. - Document the updated bridge timing ## Root Cause `assets generate-types` already wrote `.litestar.json`, and `assets serve` wrote it before launching the frontend process. The build path did not: `_prepare_and_build()` only called `set_environment()` after route export, extra commands, and JS typegen. Generators such as TanStack Router's `tsr generate` could therefore run before the Python-to-JS bridge existed.
1 parent 1754b31 commit f3cca09

9 files changed

Lines changed: 186 additions & 174 deletions

File tree

docs/changelog.rst

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,11 @@ Notable changes to this project are documented in this file.
77
Litestar Vite Changelog
88
^^^^^^^^^^^^^^^^^^^^^^^
99

10+
0.26.1 - 2026-07-06
11+
-------------------
12+
13+
- Fixed ``litestar assets build`` so ``.litestar.json`` is written before pre-build code generators and the JS typegen CLI read the Vite bridge.
14+
1015
0.26.0 - 2026-07-05
1116
-------------------
1217

docs/usage/types.rst

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -148,13 +148,14 @@ Generate all types with a single command:
148148
149149
This runs the full pipeline:
150150

151-
1. Exports OpenAPI schema to ``src/generated/openapi.json``
152-
2. Exports route metadata to ``src/generated/routes.json`` and ``routes.ts`` (if enabled)
153-
3. Runs any ``extra_commands`` (e.g., ``tsr generate`` for TanStack Router)
154-
4. Runs ``litestar-vite-typegen`` (invokes ``@hey-api/openapi-ts`` and generates ``schemas.ts`` / page props types)
155-
156-
The command also writes/updates ``.litestar.json`` and reports whether it was
157-
updated or unchanged, matching the output style for other generated files.
151+
1. Writes or refreshes ``.litestar.json`` so JS-side generators can read the Python config
152+
2. Exports OpenAPI schema to ``src/generated/openapi.json``
153+
3. Exports route metadata to ``src/generated/routes.json`` and ``routes.ts`` (if enabled)
154+
4. Runs any ``extra_commands`` (e.g., ``tsr generate`` for TanStack Router)
155+
5. Runs ``litestar-vite-typegen`` (invokes ``@hey-api/openapi-ts`` and generates ``schemas.ts`` / page props types)
156+
157+
The command reports whether ``.litestar.json`` was updated or unchanged,
158+
matching the output style for other generated files.
158159

159160
You can also export routes separately:
160161

docs/usage/vite.rst

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,8 @@ Runtime Bridge File (``.litestar.json``)
129129

130130
Litestar writes a deterministic ``.litestar.json`` file from your Python config.
131131
The Vite plugin reads it to avoid duplicating configuration values on the JS side.
132-
The file is created or updated on app startup and when running
132+
The file is created or updated during app startup and before these commands use
133+
the frontend bridge: ``litestar assets serve``, ``litestar assets build``, and
133134
``litestar assets generate-types``.
134135

135136
Python Configuration (`ViteConfig`)

package-lock.json

Lines changed: 55 additions & 55 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "litestar-vite-plugin",
3-
"version": "0.26.0",
3+
"version": "0.26.1",
44
"type": "module",
55
"description": "Litestar plugin for Vite.",
66
"keywords": [

pyproject.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ license = { text = "MIT" }
3030
name = "litestar-vite"
3131
readme = "README.md"
3232
requires-python = ">=3.10"
33-
version = "0.26.0"
33+
version = "0.26.1"
3434

3535
[project.urls]
3636
Changelog = "https://litestar-org.github.io/litestar-vite/latest/changelog"
@@ -102,7 +102,7 @@ test = [
102102
allow_dirty = true
103103
commit = false
104104
commit_args = "--no-verify"
105-
current_version = "0.26.0"
105+
current_version = "0.26.1"
106106
ignore_missing_files = false
107107
ignore_missing_version = false
108108
message = "chore(release): bump to `v{new_version}`"

src/py/litestar_vite/cli.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -216,6 +216,9 @@ def _build_deploy_config(
216216

217217
def _prepare_and_build(config: ViteConfig, root_dir: Path, console: Any, app: "Litestar | None", verbose: bool) -> None:
218218
"""Export metadata, run typegen, and execute the configured frontend build."""
219+
if config.set_environment:
220+
set_environment(config=config)
221+
219222
generated_assets = _generate_schema_and_routes(app, config, console) if app is not None else False
220223

221224
if not (root_dir / "node_modules").exists():
@@ -228,8 +231,6 @@ def _prepare_and_build(config: ViteConfig, root_dir: Path, console: Any, app: "L
228231
if not extra_commands_ok:
229232
raise SystemExit(1)
230233

231-
if config.set_environment:
232-
set_environment(config=config)
233234
os.environ.setdefault("VITE_BASE_URL", config.base_url or "/")
234235

235236
env_manager = (

src/py/tests/unit/test_cli.py

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -244,6 +244,28 @@ def test_cli_run_vite_build_executes(tmp_path: Path) -> None:
244244
assert fake_executor.executes
245245

246246

247+
def test_cli_prepare_and_build_writes_bridge_before_extra_commands(tmp_path: Path) -> None:
248+
app = _make_app(tmp_path, types=True)
249+
config = app.plugins.get(VitePlugin).config
250+
fake_executor = FakeExecutor()
251+
config._executor_instance = fake_executor
252+
(tmp_path / "node_modules").mkdir()
253+
254+
def assert_bridge_exists(config_arg: ViteConfig, verbose: bool) -> bool:
255+
del verbose
256+
assert config_arg is config
257+
assert (tmp_path / ".litestar.json").exists()
258+
assert os.environ["LITESTAR_VITE_CONFIG_PATH"] == str(tmp_path / ".litestar.json")
259+
return True
260+
261+
with (
262+
patch("litestar_vite.cli._generate_schema_and_routes", return_value=True),
263+
patch("litestar_vite.cli._run_extra_commands", side_effect=assert_bridge_exists),
264+
patch("litestar_vite.cli._invoke_typegen_cli"),
265+
):
266+
_run_vite_build(config, tmp_path, Mock(), no_build=False, app=app)
267+
268+
247269
def test_cli_run_vite_build_skips_js_build_typegen_after_cli_typegen(tmp_path: Path) -> None:
248270
app = _make_app(tmp_path, types=True)
249271
config = app.plugins.get(VitePlugin).config

0 commit comments

Comments
 (0)