diff --git a/homeassistant/components/frontend/__init__.py b/homeassistant/components/frontend/__init__.py index b152b2d65d8..f274a2dd4da 100644 --- a/homeassistant/components/frontend/__init__.py +++ b/homeassistant/components/frontend/__init__.py @@ -341,6 +341,11 @@ async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool: is_dev = repo_path is not None root_path = _frontend_root(repo_path) + if is_dev: + from .dev import async_setup_frontend_dev + + async_setup_frontend_dev(hass) + for path, should_cache in ( ("service_worker.js", False), ("robots.txt", False), diff --git a/homeassistant/components/frontend/dev.py b/homeassistant/components/frontend/dev.py new file mode 100644 index 00000000000..c5aa25315b6 --- /dev/null +++ b/homeassistant/components/frontend/dev.py @@ -0,0 +1,60 @@ +"""Development helpers for the frontend.""" +import aiohttp +from aiohttp import hdrs, web + +from homeassistant.components.http.view import HomeAssistantView +from homeassistant.core import HomeAssistant, callback +from homeassistant.helpers import aiohttp_client + + +@callback +def async_setup_frontend_dev(hass: HomeAssistant) -> None: + """Set up frontend dev views.""" + hass.http.register_view( # type: ignore + FrontendDevView( + "http://localhost:8000", aiohttp_client.async_get_clientsession(hass) + ) + ) + + +FILTER_RESPONSE_HEADERS = {hdrs.CONTENT_LENGTH, hdrs.CONTENT_ENCODING} + + +class FrontendDevView(HomeAssistantView): + """Frontend dev view.""" + + name = "_dev:frontend" + url = "/_dev_frontend/{path:.*}" + requires_auth = False + extra_urls = ["/__web-dev-server__/{path:.*}"] + + def __init__(self, forward_base: str, websession: aiohttp.ClientSession): + """Initialize a Hass.io ingress view.""" + self._forward_base = forward_base + self._websession = websession + + async def get(self, request: web.Request, path: str) -> web.Response: + """Frontend routing.""" + # To deal with: import * as commonjsHelpers from '/__web-dev-server__/rollup/commonjsHelpers.js + if request.path.startswith("/__web-dev-server__/"): + path = f"__web-dev-server__/{path}" + + url = f"{self._forward_base}/{path}" + + if request.query_string: + url += f"?{request.query_string}" + + async with self._websession.get( + url, + headers=request.headers, + allow_redirects=False, + ) as result: + return web.Response( + headers={ + hdr: val + for hdr, val in result.headers.items() + if hdr not in FILTER_RESPONSE_HEADERS + }, + status=result.status, + body=await result.read(), + )