mirror of
https://github.com/home-assistant/frontend.git
synced 2025-07-14 04:46:34 +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');
|
||||
|
||||
module.exports = {
|
||||
static_dir: path.resolve(__dirname, '../..'),
|
||||
polymer_dir: path.resolve(__dirname, '..'),
|
||||
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
|
||||
*/
|
||||
const gulp = require('gulp');
|
||||
const crypto = require('crypto');
|
||||
const file = require('gulp-file');
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const swPrecache = require('sw-precache');
|
||||
const md5 = require('../common/md5.js');
|
||||
|
||||
const DEV = !!JSON.parse(process.env.BUILD_DEV || 'true');
|
||||
|
||||
@ -45,11 +45,6 @@ const panelsFingerprinted = [
|
||||
'dev-mqtt', 'kiosk',
|
||||
];
|
||||
|
||||
function md5(filename) {
|
||||
return crypto.createHash('md5')
|
||||
.update(fs.readFileSync(filename)).digest('hex');
|
||||
}
|
||||
|
||||
function processStatic(fn, rootDir, urlDir) {
|
||||
const parts = path.parse(fn);
|
||||
const base = parts.dir.length > 0 ? parts.dir + '/' + parts.name : parts.name;
|
||||
@ -117,7 +112,7 @@ function generateServiceWorker(es6) {
|
||||
}
|
||||
],
|
||||
stripPrefix: baseRootDir,
|
||||
replacePrefix: 'static',
|
||||
replacePrefix: '/static',
|
||||
verbose: true,
|
||||
// Allow our users to refresh to get latest version.
|
||||
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",
|
||||
"gulp": "^3.9.1",
|
||||
"gulp-babel": "^7.0.0",
|
||||
"gulp-batch-replace": "^0.0.0",
|
||||
"gulp-file": "^0.3.0",
|
||||
"gulp-filter": "^5.0.1",
|
||||
"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
|
||||
script/fingerprint_frontend.py --base_dir $OUTPUT_DIR
|
||||
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 argparse
|
||||
from os import path
|
||||
import re
|
||||
|
||||
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')
|
||||
args = parser.parse_args()
|
||||
base_dir = args.base_dir + '/'
|
||||
fingerprint_file = path.join(base_dir, '__init__.py')
|
||||
panel_match = re.compile(r'ha-panel-((\w|-)+)\.html')
|
||||
|
||||
|
||||
def fingerprint():
|
||||
"""Fingerprint the frontend files."""
|
||||
files = (glob.glob(base_dir + '**/*.html') +
|
||||
glob.glob(base_dir + '*.html') +
|
||||
glob.glob(base_dir + 'core.js') +
|
||||
glob.glob(base_dir + 'compatibility.js'))
|
||||
|
||||
"""Fingerprint the panels."""
|
||||
files = glob.glob(base_dir + 'panels/*.html')
|
||||
md5s = OrderedDict()
|
||||
|
||||
for fil in sorted(files):
|
||||
name = fil[len(base_dir):]
|
||||
panel = panel_match.search(fil).groups(0)[0]
|
||||
with open(fil) as fp:
|
||||
md5 = hashlib.md5(fp.read().encode('utf-8')).hexdigest()
|
||||
md5s[name] = md5
|
||||
md5s[panel] = md5
|
||||
|
||||
template = "FINGERPRINTS = {}\n"
|
||||
result = template.format(json.dumps(md5s, indent=4))
|
||||
|
@ -2874,7 +2874,7 @@ etag@~1.8.1:
|
||||
version "1.8.1"
|
||||
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"
|
||||
resolved "https://registry.yarnpkg.com/event-stream/-/event-stream-3.3.4.tgz#4ab4c9a0f5a54db9338b4c34d86bfce8f4b35571"
|
||||
dependencies:
|
||||
@ -3657,6 +3657,12 @@ gulp-babel@^7.0.0:
|
||||
through2 "^2.0.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:
|
||||
version "0.3.0"
|
||||
resolved "https://registry.yarnpkg.com/gulp-file/-/gulp-file-0.3.0.tgz#e8c4d763f126fb3332fc416e3d1ef46ed67d8d0d"
|
||||
|
Loading…
x
Reference in New Issue
Block a user