Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: serve public_dir if it exists #17

Merged
merged 10 commits into from
Mar 16, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ jobs:
run: pdm install

- name: Test
run: pdm run pytest -m "" -n auto
run: pdm run pytest -m ""

build-docs:
needs:
Expand Down
4 changes: 2 additions & 2 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ repos:
- id: mixed-line-ending
- id: trailing-whitespace
- repo: https://github.com/charliermarsh/ruff-pre-commit
rev: "v0.2.2"
rev: "v0.3.3"
hooks:
- id: ruff
args: ["--fix"]
Expand All @@ -27,7 +27,7 @@ repos:
hooks:
- id: codespell
- repo: https://github.com/pre-commit/mirrors-mypy
rev: "v1.8.0"
rev: "v1.9.0"
hooks:
- id: mypy
exclude: "docs"
Expand Down
45 changes: 32 additions & 13 deletions litestar_vite/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,17 @@ def vite_group() -> None:
"""Manage Vite Tasks."""


@vite_group.command( # type: ignore # noqa: PGH003
@vite_group.command(
name="init",
help="Initialize vite for your project.",
)
@option(
"--root-path",
type=ClickPath(dir_okay=True, file_okay=False, path_type=Path),
help="The path for the initial the Vite application. This is the equivalent to the top-level folder in a normal Vue or React application..",
default=None,
required=False,
)
@option(
"--bundle-path",
type=ClickPath(dir_okay=True, file_okay=False, path_type=Path),
Expand All @@ -37,6 +44,13 @@ def vite_group() -> None:
default=None,
required=False,
)
@option(
"--public-path",
type=ClickPath(dir_okay=True, file_okay=False, path_type=Path),
help="The optional path to your public/static JS assets. If this were a standalone Vue or React app, this would point to your `public/` folder.",
default=None,
required=False,
)
@option("--asset-url", type=str, help="Base url to serve assets from.", default=None, required=False)
@option(
"--vite-port",
Expand Down Expand Up @@ -79,8 +93,10 @@ def vite_init(
vite_port: int | None,
enable_ssr: bool | None,
asset_url: str | None,
root_path: Path | None,
bundle_path: Path | None,
resource_path: Path | None,
public_path: Path | None,
overwrite: bool,
verbose: bool,
no_prompt: bool,
Expand All @@ -106,16 +122,18 @@ def vite_init(
ctx.obj.app.debug = True
env: LitestarEnv = ctx.obj
plugin = env.app.plugins.get(VitePlugin)
config = plugin._config # noqa: SLF001
config = plugin._config

console.rule("[yellow]Initializing Vite[/]", align="left")
resource_path = Path(resource_path or config.resource_dir)
public_path = Path(public_path or config.public_dir)
bundle_path = Path(bundle_path or config.bundle_dir)
enable_ssr = enable_ssr or config.ssr_enabled
asset_url = asset_url or config.asset_url
vite_port = vite_port or config.port
hot_file = Path(bundle_path / config.hot_file)
root_path = resource_path.parent
root_path = Path(root_path or config.root_dir or resource_path.parent)

if any(output_path.exists() for output_path in (bundle_path, resource_path)) and not any(
[overwrite, no_prompt],
):
Expand All @@ -125,7 +143,7 @@ def vite_init(
if not confirm_overwrite:
console.print("Skipping Vite initialization")
sys.exit(2)
for output_path in (bundle_path, resource_path):
for output_path in (bundle_path, resource_path, root_path):
output_path.mkdir(parents=True, exist_ok=True)

enable_ssr = (
Expand All @@ -144,6 +162,7 @@ def vite_init(
vite_port=vite_port,
asset_url=asset_url,
resource_path=resource_path,
public_path=public_path,
bundle_path=bundle_path,
hot_file=hot_file,
litestar_port=env.port or 8000,
Expand All @@ -159,14 +178,14 @@ def vite_init(
install_dir = os.environ.get("VIRTUAL_ENV", sys.prefix)
console.rule("[yellow]Starting Nodeenv installation process[/]", align="left")
console.print(f"Installing Node environment into {install_dir}")
execute_command([nodeenv_command, install_dir, "--force", "--quiet"])
execute_command(command_to_run=[nodeenv_command, install_dir, "--force", "--quiet"], cwd=root_path)

console.rule("[yellow]Starting package installation process[/]", align="left")

execute_command(plugin.config.install_command)
execute_command(command_to_run=plugin.config.install_command, cwd=root_path)


@vite_group.command( # type: ignore # noqa: PGH003
@vite_group.command(
name="install",
help="Install frontend packages.",
)
Expand Down Expand Up @@ -197,14 +216,14 @@ def vite_install(app: Litestar, verbose: bool) -> None:
install_dir = os.environ.get("VIRTUAL_ENV", sys.prefix)
console.rule("[yellow]Starting Nodeenv installation process[/]", align="left")
console.print("Installing Node environment to %s:", install_dir)
execute_command([nodeenv_command, install_dir, "--force", "--quiet"])
execute_command(command_to_run=[nodeenv_command, install_dir, "--force", "--quiet"], cwd=plugin.config.root_dir)

console.rule("[yellow]Starting package installation process[/]", align="left")

execute_command(plugin.config.install_command)
execute_command(command_to_run=plugin.config.install_command, cwd=plugin.config.root_dir)


@vite_group.command( # type: ignore # noqa: PGH003
@vite_group.command(
name="build",
help="Building frontend assets with Vite.",
)
Expand All @@ -224,14 +243,14 @@ def vite_build(app: Litestar, verbose: bool) -> None:
plugin = app.plugins.get(VitePlugin)
if plugin.config.set_environment:
set_environment(config=plugin.config)
p = execute_command(plugin.config.build_command)
p = execute_command(command_to_run=plugin.config.build_command, cwd=plugin.config.root_dir)
if p.returncode == 0:
console.print("[bold green] Assets built.[/]")
else:
console.print("[bold red] There was an error building the assets.[/]")


@vite_group.command( # type: ignore # noqa: PGH003
@vite_group.command(
name="serve",
help="Serving frontend assets with Vite.",
)
Expand All @@ -256,5 +275,5 @@ def vite_serve(app: Litestar, verbose: bool) -> None:
else:
console.rule("[yellow]Starting Vite watch and build process[/]", align="left")
command_to_run = plugin.config.run_command if plugin.config.hot_reload else plugin.config.build_watch_command
execute_command(command_to_run)
execute_command(command_to_run=command_to_run, cwd=plugin.config.root_dir)
console.print("[yellow]Vite process stopped.[/]")
11 changes: 8 additions & 3 deletions litestar_vite/commands.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,10 +37,11 @@ def to_json(value: Any) -> str:


def init_vite(
app: Litestar, # noqa: ARG001
app: Litestar,
root_path: Path,
resource_path: Path,
asset_url: str,
public_path: Path,
bundle_path: Path,
enable_ssr: bool,
vite_port: int,
Expand Down Expand Up @@ -81,6 +82,7 @@ def init_vite(
asset_url=asset_url,
root_path=str(root_path.relative_to(Path.cwd().absolute())),
resource_path=str(resource_path.relative_to(root_path)),
public_path=str(public_path.relative_to(root_path)),
bundle_path=str(bundle_path.relative_to(root_path)),
hot_file=str(hot_file.relative_to(Path.cwd().absolute())),
vite_port=str(vite_port),
Expand All @@ -105,6 +107,9 @@ def get_template(
return environment.get_template(name=name, parent=parent, globals=globals)


def execute_command(command_to_run: list[str]) -> subprocess.CompletedProcess[bytes]:
def execute_command(command_to_run: list[str], cwd: str | Path | None = None) -> subprocess.CompletedProcess[bytes]:
"""Run Vite in a subprocess."""
return subprocess.run(command_to_run, check=False, shell=platform.system() == "Windows") # noqa: S603
kwargs = {}
if cwd is not None:
kwargs["cwd"] = Path(cwd)
return subprocess.run(command_to_run, check=False, shell=platform.system() == "Windows", **kwargs) # type: ignore[call-overload]
14 changes: 10 additions & 4 deletions litestar_vite/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,11 @@ class ViteConfig:
In a standalone Vue or React application, this would be equivalent to the ``./src`` directory.
"""
template_dir: Path | str | None = field(default=None)
"""Location of the Jinja2 template file.
"""Location of the Jinja2 template file."""
public_dir: Path | str = field(default="public")
"""The optional public directory Vite serves assets from.

In a standalone Vue or React application, this would be equivalent to the ``./public`` directory.
"""
manifest_name: str = "manifest.json"
"""Name of the manifest file."""
Expand All @@ -63,12 +67,12 @@ class ViteConfig:
root_dir: Path | str | None = None
"""The is the base path to your application.

In a standalone Vue or React application, this would be equivalent to the ``./src`` directory.
In a standalone Vue or React application, this would be equivalent to the top-level project folder containing the ``./src`` directory.

"""
is_react: bool = False
"""Enable React components."""
asset_url: str =field(default_factory=lambda: os.getenv("ASSET_URL", "/static/"))
asset_url: str = field(default_factory=lambda: os.getenv("ASSET_URL", "/static/"))
"""Base URL to generate for static asset references.

This URL will be prepended to anything generated from Vite.
Expand All @@ -91,7 +95,7 @@ class ViteConfig:
default_factory=lambda: os.getenv("VITE_USE_SERVER_LIFESPAN", "False") in {"True", "1", "yes", "Y", "T"},
)
"""Utilize the server lifespan hook to run Vite."""
dev_mode: bool = field(
dev_mode: bool = field(
default_factory=lambda: os.getenv("VITE_DEV_MODE", "False") in {"True", "1", "yes", "Y", "T"},
)
"""When True, Vite will run with HMR or watch build"""
Expand All @@ -112,6 +116,8 @@ def __post_init__(self) -> None:
self.root_dir = Path(self.root_dir)
if self.template_dir is not None and isinstance(self.template_dir, str):
self.template_dir = Path(self.template_dir)
if self.public_dir is not None and isinstance(self.public_dir, str):
self.public_dir = Path(self.public_dir)
if isinstance(self.resource_dir, str):
self.resource_dir = Path(self.resource_dir)
if isinstance(self.bundle_dir, str):
Expand Down
18 changes: 13 additions & 5 deletions litestar_vite/plugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@

import os
from contextlib import contextmanager
from typing import TYPE_CHECKING, Iterator
from pathlib import Path
from typing import TYPE_CHECKING, Iterator, cast

from litestar.plugins import CLIPlugin, InitPluginProtocol
from litestar.static_files import create_static_files_router
Expand Down Expand Up @@ -66,14 +67,19 @@ def on_app_init(self, app_config: AppConfig) -> AppConfig:
)

if self._config.set_static_folders:
static_dirs = [Path(self._config.bundle_dir), Path(self._config.resource_dir)]
if Path(self._config.public_dir).exists() and self._config.public_dir != self._config.bundle_dir:
static_dirs.append(Path(self._config.public_dir))
app_config.route_handlers.append(
create_static_files_router(
directories=[self._config.bundle_dir, self._config.resource_dir]
if self._config.dev_mode
else [self._config.bundle_dir],
directories=cast( # type: ignore[arg-type]
"list[Path]",
static_dirs if self._config.dev_mode else [Path(self._config.bundle_dir)],
),
path=self._config.asset_url,
name="vite",
html_mode=False,
include_in_schema=False,
opt={"exclude_from_auth": True},
),
)
Expand All @@ -96,8 +102,10 @@ def server_lifespan(self, app: Litestar) -> Iterator[None]:
if self._config.set_environment:
set_environment(config=self._config)
vite_thread = threading.Thread(
name="vite",
target=execute_command,
args=[command_to_run],
args=[],
kwargs={"command_to_run": command_to_run, "cwd": self._config.root_dir},
)
try:
vite_thread.start()
Expand Down
5 changes: 4 additions & 1 deletion litestar_vite/templates/vite.config.ts.j2
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,12 @@ export default defineConfig({
base: `${ASSET_URL}`,
{% if root_path and root_path != '.' %} root: "{{ root_path }}",{% endif %}
server: {
host: `${VITE_HOST}`,
host: "0.0.0.0",
port: +`${VITE_PORT}`,
cors: true,
hmr: {
host: `${VITE_HOST}`,
},
},
plugins: [
{% if include_vue %}vue(),{% endif %}
Expand Down
Loading
Loading