Skip to content

Commit

Permalink
fix: loading assets when the page is not the home page of the fronten…
Browse files Browse the repository at this point in the history
…d application
  • Loading branch information
zumuta committed Dec 7, 2024
1 parent 0f7ea49 commit 7405e76
Show file tree
Hide file tree
Showing 17 changed files with 85 additions and 107 deletions.
3 changes: 2 additions & 1 deletion backend/src/kwai/core/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@ class SettingsException(Exception):
class FrontendApplicationSettings(BaseModel):
"""Settings for a frontend application."""

base_dev: str | None = None
server: str | None = None
base: str | None = None
entries: list[str] | str


Expand Down
6 changes: 3 additions & 3 deletions backend/src/kwai/frontend/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ async def log(request: Request, call_next):
for router in application_routers:
frontend_app.include_router(router, prefix="/apps")

@frontend_app.get("/news/{path:path}")
@frontend_app.get("/news/{path:path}", name="frontend.news")
def news(path: Path, settings: Annotated[Settings, Depends(get_settings)]):
"""Redirect the news path to the portal application.
Expand All @@ -56,7 +56,7 @@ def news(path: Path, settings: Annotated[Settings, Depends(get_settings)]):
"""
return RedirectResponse(f"/apps/{settings.frontend.root_app}/news/{path}")

@frontend_app.get("/pages/{path:path}")
@frontend_app.get("/pages/{path:path}", name="frontend.pages")
def pages(path: Path, settings: Annotated[Settings, Depends(get_settings)]):
"""Redirect the pages path to the portal application.
Expand All @@ -65,7 +65,7 @@ def pages(path: Path, settings: Annotated[Settings, Depends(get_settings)]):
"""
return RedirectResponse(f"/apps/{settings.frontend.root_app}/pages/{path}")

@frontend_app.get("/")
@frontend_app.get("/", name="frontend.home")
def root(settings: Annotated[Settings, Depends(get_settings)]):
"""Redirect index to the portal application."""
return RedirectResponse(f"/apps/{settings.frontend.root_app}")
Expand Down
6 changes: 5 additions & 1 deletion backend/src/kwai/frontend/apps/_auth.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
_auth_vite_dependency = ViteDependency(APP_NAME)


@router.get("/{path:path}")
@router.get("/{path:path}", name=APP_NAME)
async def get_app(
path: Path,
request: Request,
Expand All @@ -32,6 +32,10 @@ async def get_app(
return templates.TemplateResponse(
"index.jinja2",
{
"application": {
"name": APP_NAME,
"url": str(request.url_for(APP_NAME, path="")),
},
"request": request,
"vite": vite,
},
Expand Down
6 changes: 5 additions & 1 deletion backend/src/kwai/frontend/apps/_author.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
_auth_vite_dependency = ViteDependency(APP_NAME)


@router.get("/{path:path}")
@router.get("/{path:path}", name=APP_NAME)
async def get_app(
path: Path,
request: Request,
Expand All @@ -32,6 +32,10 @@ async def get_app(
return templates.TemplateResponse(
"index.jinja2",
{
"application": {
"name": APP_NAME,
"url": str(request.url_for(APP_NAME, path="")),
},
"request": request,
"vite": vite,
},
Expand Down
6 changes: 5 additions & 1 deletion backend/src/kwai/frontend/apps/_club.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
_club_vite_dependency = ViteDependency(APP_NAME)


@router.get("/{path:path}")
@router.get("/{path:path}", name=APP_NAME)
async def get_app(
path: Path,
request: Request,
Expand All @@ -32,6 +32,10 @@ async def get_app(
return templates.TemplateResponse(
"index.jinja2",
{
"application": {
"name": APP_NAME,
"url": str(request.url_for(APP_NAME, path="")),
},
"request": request,
"vite": vite,
},
Expand Down
6 changes: 5 additions & 1 deletion backend/src/kwai/frontend/apps/_coach.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
_coach_vite_dependency = ViteDependency(APP_NAME)


@router.get("/{path:path}")
@router.get("/{path:path}", name=APP_NAME)
async def get_app(
path: Path,
request: Request,
Expand All @@ -32,6 +32,10 @@ async def get_app(
return templates.TemplateResponse(
"index.jinja2",
{
"application": {
"name": APP_NAME,
"url": str(request.url_for(APP_NAME, path="")),
},
"request": request,
"vite": vite,
},
Expand Down
6 changes: 5 additions & 1 deletion backend/src/kwai/frontend/apps/_portal.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
_portal_vite_dependency = ViteDependency(APP_NAME)


@router.get("/{path:path}")
@router.get("/{path:path}", name=APP_NAME)
async def get_app(
path: Path,
request: Request,
Expand All @@ -32,6 +32,10 @@ async def get_app(
return templates.TemplateResponse(
"index.jinja2",
{
"application": {
"name": APP_NAME,
"url": str(request.url_for(APP_NAME, path="")),
},
"request": request,
"vite": vite,
},
Expand Down
11 changes: 8 additions & 3 deletions backend/src/kwai/frontend/dependencies.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,12 +25,17 @@ def __call__(self, settings: Annotated[Settings, Depends(get_settings)]) -> Vite

app_setting = getattr(settings.frontend.apps, self._application_name)
if settings.frontend.test:
if app_setting.base_dev is None:
if app_setting.server is None:
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
detail=f"Setting base_dev not set for application {self._application_name}",
detail=f"Setting 'server' not set for application {self._application_name}",
)
return DevelopmentVite(app_setting.base_dev)
if app_setting.base is None:
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
detail=f"Setting 'base' not set for application {self._application_name}",
)
return DevelopmentVite(app_setting.server, app_setting.base)

manifest_path = (
Path(settings.frontend.path)
Expand Down
53 changes: 28 additions & 25 deletions backend/src/kwai/frontend/vite.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,18 +15,18 @@ def init(self, *entries: str):
raise NotImplementedError

@abstractmethod
def generate_scripts(self, *entries: str) -> list[str]:
"""Generate the script tags for the given entries."""
def get_scripts(self, base_url: str) -> list[str]:
"""Get the scripts for the given entries."""
raise NotImplementedError

@abstractmethod
def generate_css(self, *entries: str) -> list[str]:
"""Generate the css tags for the given entries."""
def get_css(self, base_url: str) -> list[str]:
"""Get the css files for the given entries."""
raise NotImplementedError

@abstractmethod
def generate_preloads(self, *entries: str) -> list[str]:
"""Generate the preload tags for the given entries."""
def get_preloads(self, base_url: str) -> list[str]:
"""Get the preloads for the given entries."""
raise NotImplementedError

@abstractmethod
Expand All @@ -47,10 +47,11 @@ def get_asset_path(self, asset_path: Path) -> Path | None:
class DevelopmentVite(Vite):
"""Vite implementation for development."""

def __init__(self, base_path: str):
def __init__(self, server_url: str, base_path: str):
"""Initialize the development version of vite.
Args:
server_url: The url for the vite server
base_path: The base path for the development version of vite.
!!! Note
Expand All @@ -59,29 +60,35 @@ def __init__(self, base_path: str):
'/apps/author' and the server is running on localhost with port 3001, then
base_path should be: 'http://localhost:3001/apps/author'.
"""
self._server_url = server_url
self._base_path = base_path
self._entries: list[str] = []

def init(self, *entries: str):
self._entries = entries

def generate_scripts(self) -> list[str]:
scripts = [
f'<script type="module" src="{self._base_path}/@vite/client"></script>'
]
def get_scripts(self, base_url: str) -> list[str]:
scripts = [f"{self._server_url}/@vite/client"]
for entry in self._entries:
scripts.append(
f'<script type="module" src="{self._base_path}/{entry}"></script>'
"/".join(
list(
filter(
lambda item: item,
[self._server_url, self._base_path, entry],
)
)
)
)
return scripts

def generate_css(self) -> list[str]:
def get_css(self, base_url: str) -> list[str]:
return []

def generate_preloads(self) -> list[str]:
def get_preloads(self, base_url: str) -> list[str]:
return []

def get_asset_path(self, path: Path) -> Path | None:
def get_asset_path(self, asset_path: Path) -> Path | None:
return None


Expand All @@ -105,30 +112,28 @@ def init(self, *entries: str):
self._manifest = Manifest.load_from_file(self._manifest_filepath)
self._imported_chunks = self._find_imported_chunks(*entries)

def generate_scripts(self) -> list[str]:
def get_scripts(self, base_url: str) -> list[str]:
scripts = []

for chunk in self._imported_chunks.values():
if chunk.entry:
scripts.append('<script type="module" ' f'src="{chunk.file}"></script>')
scripts.append(base_url + chunk.file)

return scripts

def generate_css(self) -> list[str]:
def get_css(self, base_url: str) -> list[str]:
styles = []
for chunk in self._imported_chunks.values():
for css in chunk.css:
styles.append(f'<link rel="stylesheet" href="{css}">')
styles.append(base_url + css)
return styles

def generate_preloads(self) -> list[str]:
def get_preloads(self, base_url: str) -> list[str]:
preloads = []

for chunk in self._imported_chunks.values():
if chunk.file.endswith(".js") and not chunk.entry:
preloads.append(
f'<link rel="modulepreload" as="script" ' f'href="{chunk.file}">'
)
preloads.append(base_url + chunk.file)

return preloads

Expand Down Expand Up @@ -159,8 +164,6 @@ def _find_imported_chunks(self, *entries: str) -> dict[str, Chunk]:

def get_asset_path(self, path: Path) -> Path | None:
dist_path = self._base_path / "dist"
if len(path.parents) > 0 and str(path.parents[0]) == "public":
path = Path(*path.parts[1:])
asset_file = dist_path / path
if asset_file.is_relative_to(dist_path) and asset_file.is_file():
return asset_file
Expand Down
22 changes: 6 additions & 16 deletions backend/src/tests/frontend/test_development_vite.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
"""Module for testing the development vite class."""

from pathlib import Path

import pytest

from kwai.frontend.vite import DevelopmentVite, Vite
Expand All @@ -10,32 +8,24 @@
@pytest.fixture
def vite() -> Vite:
"""A fixture for vite development."""
vite = DevelopmentVite(Path("http://localhost:5173"))
vite = DevelopmentVite("http://localhost:5173", "")
vite.init("src/index.ts")
return vite


def test_development_vite_scripts(vite: Vite):
"""Test the development version of the Vite class for script tags."""
scripts = vite.generate_scripts()
scripts = vite.get_scripts("")
assert len(scripts) == 2, "There should be 2 script tags"
assert (
scripts[0]
== '<script type="module" src="http:/localhost:5173/@vite/client"></script>'
)
assert (
scripts[1]
== '<script type="module" src="http:/localhost:5173/src/index.ts"></script>'
)
assert scripts[0] == "http://localhost:5173/@vite/client"
assert scripts[1] == "http://localhost:5173/src/index.ts"


def test_development_vite_css(vite: Vite):
"""Test the development version of the Vite class for css tags."""
assert len(vite.generate_css()) == 0, "There should be no css in development"
assert len(vite.get_css("")) == 0, "There should be no css in development"


def test_development_vite_preload(vite: Vite):
"""Test the development version of the Vite class for preload tags."""
assert (
len(vite.generate_preloads()) == 0
), "There should be no preload in development"
assert len(vite.get_preloads("")) == 0, "There should be no preload in development"
20 changes: 7 additions & 13 deletions backend/src/tests/frontend/test_production_vite.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,29 +17,23 @@ def vite(manifest_path: Path, tmp_path: Path) -> Vite:

def test_production_vite_scripts(vite: Vite):
"""Test the production version of the Vite class for script tags."""
scripts = vite.generate_scripts()
scripts = vite.get_scripts("http://localhost:8000/apps/portal/")
assert len(scripts) == 1, "There should be one script tag"
assert (
scripts[0] == '<script type="module" '
'src="assets/index-533fa9ea.js"></script>'
)
assert scripts[0] == "http://localhost:8000/apps/portal/assets/index-533fa9ea.js"


def test_production_vite_css(vite: Vite):
"""Test the production of the Vite class for css tags."""
css = vite.generate_css()
css = vite.get_css("")
assert len(css) == 1, "There should be a css link"
assert css[0] == '<link rel="stylesheet" href="assets/index-ace45c09.css">'
assert css[0] == "assets/index-ace45c09.css"


def test_production_vite_preload(vite: Vite):
"""Test the production version of the Vite class for preload tags."""
preload = vite.generate_preloads()
preload = vite.get_preloads("")
assert len(preload) == 1, "There should be a preload"
assert (
preload[0]
== '<link rel="modulepreload" as="script" href="assets/vendor-97e41b2b.js">'
)
assert preload[0] == "assets/vendor-97e41b2b.js"


def test_production_vite_get_asset_path(vite: Vite, tmp_path: Path):
Expand All @@ -60,7 +54,7 @@ def test_production_vite_get_public_path(vite: Vite, tmp_path: Path):
with open(dist_path / "test_file.txt", "w") as f:
f.write("This is a test file.")

asset_file = vite.get_asset_path(Path("public") / "test_file.txt")
asset_file = vite.get_asset_path(Path("test_file.txt"))
assert asset_file is not None


Expand Down
Loading

0 comments on commit 7405e76

Please sign in to comment.