mirror of
https://github.com/home-assistant/frontend.git
synced 2025-07-14 12:56:37 +00:00
Pre-construct frontend index.html (#609)
* Pre-construct frontend index.html * Only preload things that matter * Fix entry point in dev mode * Template Service worker url * Update referenced service worker
This commit is contained in:
parent
f106767eae
commit
3701683d4b
8
gulp/common/md5.js
Normal file
8
gulp/common/md5.js
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
const fs = require('fs');
|
||||||
|
const crypto = require('crypto');
|
||||||
|
|
||||||
|
module.exports = function md5(filename) {
|
||||||
|
return crypto.createHash('md5')
|
||||||
|
.update(fs.readFileSync(filename)).digest('hex');
|
||||||
|
};
|
||||||
|
|
@ -1,7 +1,8 @@
|
|||||||
var path = require('path');
|
var path = require('path');
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
static_dir: path.resolve(__dirname, '../..'),
|
|
||||||
polymer_dir: path.resolve(__dirname, '..'),
|
polymer_dir: path.resolve(__dirname, '..'),
|
||||||
build_dir: path.resolve(__dirname, '../build'),
|
build_dir: path.resolve(__dirname, '../build'),
|
||||||
|
output: path.resolve(__dirname, '../hass_frontend'),
|
||||||
|
output_es5: path.resolve(__dirname, '../hass_frontend_es5'),
|
||||||
};
|
};
|
||||||
|
44
gulp/tasks/gen-index-html.js
Normal file
44
gulp/tasks/gen-index-html.js
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
const gulp = require('gulp');
|
||||||
|
const replace = require('gulp-batch-replace');
|
||||||
|
const path = require('path');
|
||||||
|
const url = require('url');
|
||||||
|
const config = require('../config');
|
||||||
|
const md5 = require('../common/md5.js');
|
||||||
|
|
||||||
|
const buildReplaces = {
|
||||||
|
'/home-assistant-polymer/build/core.js': 'core.js',
|
||||||
|
'/home-assistant-polymer/src/home-assistant.html': 'frontend.html',
|
||||||
|
};
|
||||||
|
|
||||||
|
function generateIndex(es6) {
|
||||||
|
const targetPath = es6 ? config.output : config.output_es5;
|
||||||
|
const targetUrl = es6 ? '/frontend_latest/' : '/frontend_es5/';
|
||||||
|
|
||||||
|
const toReplace = [
|
||||||
|
['/home-assistant-polymer/hass_frontend/mdi.html',
|
||||||
|
`/static/mdi-${md5(path.resolve(config.output, 'mdi.html'))}.html`],
|
||||||
|
['/home-assistant-polymer/build-temp/compatibility.js',
|
||||||
|
`/static/compatibility-${md5(path.resolve(config.output_es5, 'compatibility.js'))}.js`],
|
||||||
|
];
|
||||||
|
|
||||||
|
if (!es6) {
|
||||||
|
toReplace.push([
|
||||||
|
'/service_worker.js', '/service_worker_es5.js'
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const [replaceSearch, filename] of Object.entries(buildReplaces)) {
|
||||||
|
const parsed = path.parse(filename);
|
||||||
|
const hash = md5(path.resolve(targetPath, filename));
|
||||||
|
toReplace.push([
|
||||||
|
replaceSearch,
|
||||||
|
url.resolve(targetUrl, `${parsed.name}-${hash}${parsed.ext}`)]);
|
||||||
|
}
|
||||||
|
|
||||||
|
gulp.src(path.resolve(config.polymer_dir, 'index.html'))
|
||||||
|
.pipe(replace(toReplace))
|
||||||
|
.pipe(gulp.dest(targetPath));
|
||||||
|
}
|
||||||
|
|
||||||
|
gulp.task('gen-index-html-es5', generateIndex.bind(null, /* es6= */ false));
|
||||||
|
gulp.task('gen-index-html', generateIndex.bind(null, /* es6= */ true));
|
@ -12,11 +12,11 @@ TODO:
|
|||||||
- Fix minifying the stream
|
- Fix minifying the stream
|
||||||
*/
|
*/
|
||||||
const gulp = require('gulp');
|
const gulp = require('gulp');
|
||||||
const crypto = require('crypto');
|
|
||||||
const file = require('gulp-file');
|
const file = require('gulp-file');
|
||||||
const fs = require('fs');
|
const fs = require('fs');
|
||||||
const path = require('path');
|
const path = require('path');
|
||||||
const swPrecache = require('sw-precache');
|
const swPrecache = require('sw-precache');
|
||||||
|
const md5 = require('../common/md5.js');
|
||||||
|
|
||||||
const DEV = !!JSON.parse(process.env.BUILD_DEV || 'true');
|
const DEV = !!JSON.parse(process.env.BUILD_DEV || 'true');
|
||||||
|
|
||||||
@ -45,11 +45,6 @@ const panelsFingerprinted = [
|
|||||||
'dev-mqtt', 'kiosk',
|
'dev-mqtt', 'kiosk',
|
||||||
];
|
];
|
||||||
|
|
||||||
function md5(filename) {
|
|
||||||
return crypto.createHash('md5')
|
|
||||||
.update(fs.readFileSync(filename)).digest('hex');
|
|
||||||
}
|
|
||||||
|
|
||||||
function processStatic(fn, rootDir, urlDir) {
|
function processStatic(fn, rootDir, urlDir) {
|
||||||
const parts = path.parse(fn);
|
const parts = path.parse(fn);
|
||||||
const base = parts.dir.length > 0 ? parts.dir + '/' + parts.name : parts.name;
|
const base = parts.dir.length > 0 ? parts.dir + '/' + parts.name : parts.name;
|
||||||
@ -117,7 +112,7 @@ function generateServiceWorker(es6) {
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
stripPrefix: baseRootDir,
|
stripPrefix: baseRootDir,
|
||||||
replacePrefix: 'static',
|
replacePrefix: '/static',
|
||||||
verbose: true,
|
verbose: true,
|
||||||
// Allow our users to refresh to get latest version.
|
// Allow our users to refresh to get latest version.
|
||||||
clientsClaim: true,
|
clientsClaim: true,
|
||||||
|
121
index.html
Normal file
121
index.html
Normal file
@ -0,0 +1,121 @@
|
|||||||
|
<!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">
|
||||||
|
<link rel='preload' href='/home-assistant-polymer/build/core.js' as='script'/>
|
||||||
|
<link rel='preload' href='/static/fonts/roboto/Roboto-Regular.ttf' as='font' crossorigin />
|
||||||
|
<link rel='preload' href='/static/fonts/roboto/Roboto-Medium.ttf' as='font' crossorigin />
|
||||||
|
<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='/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 = '/home-assistant-polymer/build-temp/compatibility.js';
|
||||||
|
document.head.appendChild(e);
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
{% endif -%}
|
||||||
|
<script src='/home-assistant-polymer/build/core.js'></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.js');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<link rel='import' href='/home-assistant-polymer/src/home-assistant.html' onerror='initError()'>
|
||||||
|
{% if panel_url -%}
|
||||||
|
<link rel='import' href='{{ panel_url }}' onerror='initError()' async>
|
||||||
|
{% endif -%}
|
||||||
|
<link rel='import' href='/home-assistant-polymer/hass_frontend/mdi.html' async>
|
||||||
|
{% for extra_url in extra_urls -%}
|
||||||
|
<link rel='import' href='{{ extra_url }}' async>
|
||||||
|
{% endfor -%}
|
||||||
|
</body>
|
||||||
|
</html>
|
@ -38,6 +38,7 @@
|
|||||||
"eslint-plugin-react": "^7.0.0",
|
"eslint-plugin-react": "^7.0.0",
|
||||||
"gulp": "^3.9.1",
|
"gulp": "^3.9.1",
|
||||||
"gulp-babel": "^7.0.0",
|
"gulp-babel": "^7.0.0",
|
||||||
|
"gulp-batch-replace": "^0.0.0",
|
||||||
"gulp-file": "^0.3.0",
|
"gulp-file": "^0.3.0",
|
||||||
"gulp-filter": "^5.0.1",
|
"gulp-filter": "^5.0.1",
|
||||||
"gulp-foreach": "^0.1.0",
|
"gulp-foreach": "^0.1.0",
|
||||||
|
@ -79,3 +79,5 @@ echo "CREATED_AT = `date +%s`" >> $OUTPUT_DIR_ES5/__init__.py
|
|||||||
# Generate the MD5 hash of the new frontend
|
# Generate the MD5 hash of the new frontend
|
||||||
script/fingerprint_frontend.py --base_dir $OUTPUT_DIR
|
script/fingerprint_frontend.py --base_dir $OUTPUT_DIR
|
||||||
script/fingerprint_frontend.py --base_dir $OUTPUT_DIR_ES5
|
script/fingerprint_frontend.py --base_dir $OUTPUT_DIR_ES5
|
||||||
|
gulp gen-index-html
|
||||||
|
gulp gen-index-html-es5
|
||||||
|
@ -7,28 +7,26 @@ import hashlib
|
|||||||
import json
|
import json
|
||||||
import argparse
|
import argparse
|
||||||
from os import path
|
from os import path
|
||||||
|
import re
|
||||||
|
|
||||||
parser = argparse.ArgumentParser(description='Generate fingerprints of frontend files.')
|
parser = argparse.ArgumentParser(description='Generate fingerprints of frontend files.')
|
||||||
parser.add_argument('--base_dir', type=str, help='Base dir to look for files.', default='hass_frontend')
|
parser.add_argument('--base_dir', type=str, help='Base dir to look for files.', default='hass_frontend')
|
||||||
args = parser.parse_args()
|
args = parser.parse_args()
|
||||||
base_dir = args.base_dir + '/'
|
base_dir = args.base_dir + '/'
|
||||||
fingerprint_file = path.join(base_dir, '__init__.py')
|
fingerprint_file = path.join(base_dir, '__init__.py')
|
||||||
|
panel_match = re.compile(r'ha-panel-((\w|-)+)\.html')
|
||||||
|
|
||||||
|
|
||||||
def fingerprint():
|
def fingerprint():
|
||||||
"""Fingerprint the frontend files."""
|
"""Fingerprint the panels."""
|
||||||
files = (glob.glob(base_dir + '**/*.html') +
|
files = glob.glob(base_dir + 'panels/*.html')
|
||||||
glob.glob(base_dir + '*.html') +
|
|
||||||
glob.glob(base_dir + 'core.js') +
|
|
||||||
glob.glob(base_dir + 'compatibility.js'))
|
|
||||||
|
|
||||||
md5s = OrderedDict()
|
md5s = OrderedDict()
|
||||||
|
|
||||||
for fil in sorted(files):
|
for fil in sorted(files):
|
||||||
name = fil[len(base_dir):]
|
panel = panel_match.search(fil).groups(0)[0]
|
||||||
with open(fil) as fp:
|
with open(fil) as fp:
|
||||||
md5 = hashlib.md5(fp.read().encode('utf-8')).hexdigest()
|
md5 = hashlib.md5(fp.read().encode('utf-8')).hexdigest()
|
||||||
md5s[name] = md5
|
md5s[panel] = md5
|
||||||
|
|
||||||
template = "FINGERPRINTS = {}\n"
|
template = "FINGERPRINTS = {}\n"
|
||||||
result = template.format(json.dumps(md5s, indent=4))
|
result = template.format(json.dumps(md5s, indent=4))
|
||||||
|
@ -2874,7 +2874,7 @@ etag@~1.8.1:
|
|||||||
version "1.8.1"
|
version "1.8.1"
|
||||||
resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887"
|
resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887"
|
||||||
|
|
||||||
event-stream@^3.0.20, event-stream@^3.3.1:
|
event-stream@^3.0.20, event-stream@^3.3.1, event-stream@latest:
|
||||||
version "3.3.4"
|
version "3.3.4"
|
||||||
resolved "https://registry.yarnpkg.com/event-stream/-/event-stream-3.3.4.tgz#4ab4c9a0f5a54db9338b4c34d86bfce8f4b35571"
|
resolved "https://registry.yarnpkg.com/event-stream/-/event-stream-3.3.4.tgz#4ab4c9a0f5a54db9338b4c34d86bfce8f4b35571"
|
||||||
dependencies:
|
dependencies:
|
||||||
@ -3657,6 +3657,12 @@ gulp-babel@^7.0.0:
|
|||||||
through2 "^2.0.0"
|
through2 "^2.0.0"
|
||||||
vinyl-sourcemaps-apply "^0.2.0"
|
vinyl-sourcemaps-apply "^0.2.0"
|
||||||
|
|
||||||
|
gulp-batch-replace@^0.0.0:
|
||||||
|
version "0.0.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/gulp-batch-replace/-/gulp-batch-replace-0.0.0.tgz#7e9826ad928862722c1eacb4421b4127bffd643e"
|
||||||
|
dependencies:
|
||||||
|
event-stream latest
|
||||||
|
|
||||||
gulp-file@^0.3.0:
|
gulp-file@^0.3.0:
|
||||||
version "0.3.0"
|
version "0.3.0"
|
||||||
resolved "https://registry.yarnpkg.com/gulp-file/-/gulp-file-0.3.0.tgz#e8c4d763f126fb3332fc416e3d1ef46ed67d8d0d"
|
resolved "https://registry.yarnpkg.com/gulp-file/-/gulp-file-0.3.0.tgz#e8c4d763f126fb3332fc416e3d1ef46ed67d8d0d"
|
||||||
|
Loading…
x
Reference in New Issue
Block a user