Pre-construct frontend index.html (#10520)

* Pre-construct frontend index.html

* Cache templates

* Update frontend to 20171111.0

* Fix iframe panel test
This commit is contained in:
Paulus Schoutsen 2017-11-11 15:22:05 -08:00 committed by GitHub
parent 96e7944fa8
commit c8648fbfb8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 42 additions and 183 deletions

View File

@ -13,6 +13,7 @@ from urllib.parse import urlparse
from aiohttp import web
import voluptuous as vol
import jinja2
import homeassistant.helpers.config_validation as cv
from homeassistant.components.http import HomeAssistantView
@ -22,7 +23,7 @@ from homeassistant.const import CONF_NAME, EVENT_THEMES_UPDATED
from homeassistant.core import callback
from homeassistant.loader import bind_hass
REQUIREMENTS = ['home-assistant-frontend==20171110.0']
REQUIREMENTS = ['home-assistant-frontend==20171111.0']
DOMAIN = 'frontend'
DEPENDENCIES = ['api', 'websocket_api', 'http']
@ -171,8 +172,6 @@ class BuiltInPanel(AbstractPanel):
If frontend_repository_path is set, will be prepended to path of
built-in components.
"""
panel_path = 'panels/ha-panel-{}.html'.format(self.component_name)
if frontend_repository_path is None:
import hass_frontend
import hass_frontend_es5
@ -180,11 +179,11 @@ class BuiltInPanel(AbstractPanel):
self.webcomponent_url_latest = \
'/frontend_latest/panels/ha-panel-{}-{}.html'.format(
self.component_name,
hass_frontend.FINGERPRINTS[panel_path])
hass_frontend.FINGERPRINTS[self.component_name])
self.webcomponent_url_es5 = \
'/frontend_es5/panels/ha-panel-{}-{}.html'.format(
self.component_name,
hass_frontend_es5.FINGERPRINTS[panel_path])
hass_frontend_es5.FINGERPRINTS[self.component_name])
else:
# Dev mode
self.webcomponent_url_es5 = self.webcomponent_url_latest = \
@ -335,7 +334,7 @@ def async_setup(hass, config):
if os.path.isdir(local):
hass.http.register_static_path("/local", local, not is_dev)
index_view = IndexView(is_dev, js_version)
index_view = IndexView(repo_path, js_version)
hass.http.register_view(index_view)
@asyncio.coroutine
@ -435,50 +434,40 @@ class IndexView(HomeAssistantView):
requires_auth = False
extra_urls = ['/states', '/states/{extra}']
def __init__(self, use_repo, js_option):
def __init__(self, repo_path, js_option):
"""Initialize the frontend view."""
from jinja2 import FileSystemLoader, Environment
self.use_repo = use_repo
self.templates = Environment(
autoescape=True,
loader=FileSystemLoader(
os.path.join(os.path.dirname(__file__), 'templates/')
)
)
self.repo_path = repo_path
self.js_option = js_option
self._template_cache = {}
def get_template(self, latest):
"""Get template."""
if self.repo_path is not None:
root = self.repo_path
elif latest:
import hass_frontend
root = hass_frontend.where()
else:
import hass_frontend_es5
root = hass_frontend_es5.where()
tpl = self._template_cache.get(root)
if tpl is None:
with open(os.path.join(root, 'index.html')) as file:
tpl = jinja2.Template(file.read())
# Cache template if not running from repository
if self.repo_path is None:
self._template_cache[root] = tpl
return tpl
@asyncio.coroutine
def get(self, request, extra=None):
"""Serve the index view."""
hass = request.app['hass']
latest = _is_latest(self.js_option, request)
compatibility_url = None
if self.use_repo:
core_url = '/home-assistant-polymer/{}/core.js'.format(
'build' if latest else 'build-es5')
ui_url = '/home-assistant-polymer/src/home-assistant.html'
icons_fp = ''
icons_url = '/static/mdi.html'
else:
if latest:
import hass_frontend
core_url = '/frontend_latest/core-{}.js'.format(
hass_frontend.FINGERPRINTS['core.js'])
ui_url = '/frontend_latest/frontend-{}.html'.format(
hass_frontend.FINGERPRINTS['frontend.html'])
else:
import hass_frontend_es5
core_url = '/frontend_es5/core-{}.js'.format(
hass_frontend_es5.FINGERPRINTS['core.js'])
compatibility_url = '/frontend_es5/compatibility-{}.js'.format(
hass_frontend_es5.FINGERPRINTS['compatibility.js'])
ui_url = '/frontend_es5/frontend-{}.html'.format(
hass_frontend_es5.FINGERPRINTS['frontend.html'])
import hass_frontend
icons_fp = '-{}'.format(hass_frontend.FINGERPRINTS['mdi.html'])
icons_url = '/static/mdi{}.html'.format(icons_fp)
if request.path == '/':
panel = 'states'
@ -497,23 +486,17 @@ class IndexView(HomeAssistantView):
# do not try to auto connect on load
no_auth = 'false'
template = yield from hass.async_add_job(
self.templates.get_template, 'index.html')
template = yield from hass.async_add_job(self.get_template, latest)
# pylint is wrong
# pylint: disable=no-member
# This is a jinja2 template, not a HA template so we call 'render'.
resp = template.render(
core_url=core_url, ui_url=ui_url,
compatibility_url=compatibility_url, no_auth=no_auth,
icons_url=icons_url, icons=icons_fp,
panel_url=panel_url, panels=hass.data[DATA_PANELS],
dev_mode=self.use_repo,
no_auth=no_auth,
panel_url=panel_url,
panels=hass.data[DATA_PANELS],
dev_mode=self.repo_path is not None,
theme_color=MANIFEST_JSON['theme_color'],
extra_urls=hass.data[DATA_EXTRA_HTML_URL],
latest=latest,
service_worker_name='/service_worker.js' if latest else
'/service_worker_es5.js')
)
return web.Response(text=resp, content_type='text/html')
@ -528,8 +511,8 @@ class ManifestJSONView(HomeAssistantView):
@asyncio.coroutine
def get(self, request): # pylint: disable=no-self-use
"""Return the manifest.json."""
msg = json.dumps(MANIFEST_JSON, sort_keys=True).encode('UTF-8')
return web.Response(body=msg, content_type="application/manifest+json")
msg = json.dumps(MANIFEST_JSON, sort_keys=True)
return web.Response(text=msg, content_type="application/manifest+json")
class ThemesView(HomeAssistantView):

View File

@ -1,124 +0,0 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Home Assistant</title>
<link rel='manifest' href='/manifest.json'>
<link rel='icon' href='/static/icons/favicon.ico'>
<link rel='apple-touch-icon' sizes='180x180'
href='/static/icons/favicon-apple-180x180.png'>
<link rel="mask-icon" href="/static/icons/mask-icon.svg" color="#3fbbf4">
{% if not dev_mode %}
<link rel='preload' href='{{ core_url }}' as='script'/>
{% for panel in panels.values() -%}
<link rel='prefetch' href='{{ panel.webcomponent_url }}'>
{% endfor -%}
{% endif %}
<meta name='apple-mobile-web-app-capable' content='yes'>
<meta name="msapplication-square70x70logo" content="/static/icons/tile-win-70x70.png"/>
<meta name="msapplication-square150x150logo" content="/static/icons/tile-win-150x150.png"/>
<meta name="msapplication-wide310x150logo" content="/static/icons/tile-win-310x150.png"/>
<meta name="msapplication-square310x310logo" content="/static/icons/tile-win-310x310.png"/>
<meta name="msapplication-TileColor" content="#3fbbf4ff"/>
<meta name='mobile-web-app-capable' content='yes'>
<meta name='viewport' content='width=device-width, user-scalable=no'>
<meta name='theme-color' content='{{ theme_color }}'>
<style>
body {
font-family: 'Roboto', 'Noto', sans-serif;
font-weight: 400;
-webkit-font-smoothing: antialiased;
text-rendering: optimizeLegibility;
margin: 0;
padding: 0;
}
#ha-init-skeleton::before {
display: block;
content: "";
height: 48px;
background-color: {{ theme_color }};
}
#ha-init-skeleton .message {
transition: font-size 2s;
font-size: 0;
padding: 24px;
}
#ha-init-skeleton.error .message {
font-size: 16px;
}
#ha-init-skeleton a {
color: {{ theme_color }};
text-decoration: none;
font-weight: bold;
}
</style>
<script>
function initError() {
document.getElementById('ha-init-skeleton').classList.add('error');
};
window.noAuth = {{ no_auth }};
window.Polymer = {
lazyRegister: true,
useNativeCSSProperties: true,
dom: 'shadow',
suppressTemplateNotifications: true,
suppressBindingNotifications: true,
};
</script>
</head>
<body>
<div id='ha-init-skeleton'>
<div class='message'>
Home Assistant had trouble<br>connecting to the server.<br><br>
<a href='/'>TRY AGAIN</a>
</div>
</div>
<home-assistant></home-assistant>
{# <script src='/static/home-assistant-polymer/build/_demo_data_compiled.js'></script> -#}
{% if not latest -%}
<script>
var compatibilityRequired = (typeof Object.assign != 'function');
if (compatibilityRequired) {
var e = document.createElement('script');
e.onerror = initError;
e.src = '{{ compatibility_url }}';
document.head.appendChild(e);
}
</script>
{% endif -%}
<script src='{{ core_url }}'></script>
{% if not dev_mode and not latest -%}
<script src='/frontend_es5/custom-elements-es5-adapter.js'></script>
{% endif -%}
<script>
var webComponentsSupported = (
'customElements' in window &&
'import' in document.createElement('link') &&
'content' in document.createElement('template'));
if (!webComponentsSupported) {
var e = document.createElement('script');
e.onerror = initError;
e.src = '/static/webcomponents-lite.js';
document.head.appendChild(e);
}
if ('serviceWorker' in navigator) {
window.addEventListener('load', function () {
navigator.serviceWorker.register('{{ service_worker_name }}');
});
}
</script>
<link rel='import' href='{{ ui_url }}' onerror='initError()'>
{% if panel_url -%}
<link rel='import' href='{{ panel_url }}' onerror='initError()' async>
{% endif -%}
<link rel='import' href='{{ icons_url }}' async>
{% for extra_url in extra_urls -%}
<link rel='import' href='{{ extra_url }}' async>
{% endfor -%}
</body>
</html>

View File

@ -331,7 +331,7 @@ hipnotify==1.0.8
holidays==0.8.1
# homeassistant.components.frontend
home-assistant-frontend==20171110.0
home-assistant-frontend==20171111.0
# homeassistant.components.camera.onvif
http://github.com/tgaugry/suds-passworddigest-py3/archive/86fc50e39b4d2b8997481967d6a7fe1c57118999.zip#suds-passworddigest-py3==0.1.2a

View File

@ -74,7 +74,7 @@ hbmqtt==0.8
holidays==0.8.1
# homeassistant.components.frontend
home-assistant-frontend==20171110.0
home-assistant-frontend==20171111.0
# homeassistant.components.influxdb
# homeassistant.components.sensor.influxdb

View File

@ -34,7 +34,7 @@ class TestPanelIframe(unittest.TestCase):
})
@patch.dict('hass_frontend_es5.FINGERPRINTS',
{'panels/ha-panel-iframe.html': 'md5md5'})
{'iframe': 'md5md5'})
def test_correct_config(self):
"""Test correct config."""
assert setup.setup_component(