Site updated at 2016-11-13 11:57:21 UTC

This commit is contained in:
Travis CI 2016-11-13 11:57:21 +00:00
parent 3bab881d0a
commit 18a1a7981c
1303 changed files with 223057 additions and 226 deletions

View file

@ -4,7 +4,7 @@
<title><![CDATA[Category: Technology | Home Assistant]]></title>
<link href="https://home-assistant.io/blog/categories/technology/atom.xml" rel="self"/>
<link href="https://home-assistant.io/"/>
<updated>2016-11-13T11:27:15+00:00</updated>
<updated>2016-11-13T11:55:22+00:00</updated>
<id>https://home-assistant.io/</id>
<author>
<name><![CDATA[Home Assistant]]></name>
@ -28,7 +28,7 @@ To get started, check out the installation instructions in [the getting started
<iframe width="560" height="315" src="https://www.youtube.com/embed/iIz6XqDwHEk" frameborder="0" allowfullscreen></iframe>
</div>
### {% linkable_title Under the hood %}
### <a class='title-link' name='under-the-hood' href='#under-the-hood'></a> Under the hood
It's based on Raspbian Lite and generated with a fork of the same [script](https://github.com/home-assistant/pi-gen) that builds the [official Raspbian images](https://raspberrypi.org/downloads/raspbian/). For installation of HASS it follows the same install instructions as the [Manual installation](/getting-started/installation-raspberry-pi/). Please note that this project has no association with the Raspberry Pi foundation or their projects.
@ -81,11 +81,11 @@ Although the app takes 6500 milliseconds to load on my phone, it would perform w
<!--more-->
## {% linkable_title Technology %}
## <a class='title-link' name='technology' href='#technology'></a> Technology
The Home Assistant front end consists of two parts. There is [Home Assistant JS][hajs], which controls all data and interaction between JavaScript and the server. It is a Flux architecture using [NuclearJS] and [ImmutableJS]. The UI is implemented by [Home Assistant Polymer][hap] using [Polymer] and web components.
# {% linkable_title Dont hack the framework %}
# <a class='title-link' name='dont-hack-the-framework' href='#dont-hack-the-framework'></a> Dont hack the framework
I thought to be smart. I split out the JavaScript part of all web components and bundled them separately using Webpack so that I could use ES2015 via BabelJS ([architecture][es2015-arch]). This is not how Polymer components are written and it meant that I was unable to use any of the tooling that is available in the community or easily split up the bundle (more on this later).
@ -101,7 +101,7 @@ As you can see in the timelines, we were able to get rid of most of the blocking
alt='Timeline of loading the front end before and after the optimization' />
</p>
# {% linkable_title Separate responsibilities %}
# <a class='title-link' name='separate-responsibilities' href='#separate-responsibilities'></a> Separate responsibilities
Whenever you learn a new technology, you feel like youve learned a new superpower. Wow, I can do all this with only 2 lines?! I had the same with bundling.
@ -119,11 +119,11 @@ To accomplish this I extracted the application core out of the main bundle. In t
When the data does come back before the UI is done loading, we can process it before we start rendering the UI because of all the web components being processed individually. This means that we don't have to show a loading screen the first time our components render we can just render the components with the data they require.
# {% linkable_title Ship less %}
# <a class='title-link' name='ship-less' href='#ship-less'></a> Ship less
The theory behind this one is simple: if we manage to ship less code, the browser has to process less code and it will start faster.
## {% linkable_title Only include the components for the page that you will show %}
## <a class='title-link' name='only-include-the-components-for-the-page-that-you-will-show' href='#only-include-the-components-for-the-page-that-you-will-show'></a> Only include the components for the page that you will show
The Home Assistant mobile web application has 10 different panels (pages). Besides that, it also has a dialog for each type of device to show more info. Thats a lot of components and screens of which only a very small set is needed at the start. That means that we are shipping a lot of unnecessary data that the browser has to process before our initial render!
@ -145,22 +145,22 @@ Because the browser tracks your web components, creating standalone bundles for
The [build script][build-html] that bundles and minifies the main bundle and panel bundles is <100 lines.
## {% linkable_title Change the JavaScript bundler to Rollup %}
## <a class='title-link' name='change-the-javascript-bundler-to-rollup' href='#change-the-javascript-bundler-to-rollup'></a> Change the JavaScript bundler to Rollup
Core.js is still pure JavaScript and requires bundling. In my journey to get a smaller bundle, I went from [Webpack] to Webpack 2 to [Rollup]. At each step the bundle got smaller. Rollup is the big winner here because it doesnt wrap all your modules in function calls but instead concatenates all files with minimal changes to make it work. This not only reduces the file size but also the loading speed. This is because the JavaScript engine will no longer have to invoke a function to resolve each import, its doing less work. This might not mean much for a computer but on a phone, everything counts.
## {% linkable_title Scrutinize dependencies %}
## <a class='title-link' name='scrutinize-dependencies' href='#scrutinize-dependencies'></a> Scrutinize dependencies
If the goal is to ship less, its time to take a good look at dependencies. Its so often that we decide to fall back to yet another NPM package that makes our life a little easier but comes at the cost of size size usually taken up by functionality that you might never need.
### {% linkable_title Remove Lodash %}
### <a class='title-link' name='remove-lodash' href='#remove-lodash'></a> Remove Lodash
I realized that I only used a few methods of lodash. Lodash (and previously underscore) used to be one of the dependencies that would always be one of the first things that I would add to any project I start. But I could no longer justify it in the case of Home Assistant. Even with dead tree shaking it was not worth including it. Yes, they support a lot of edge cases but those were not relevant to my use case. And standalone lodash packages are [still huge][lodash.range]. The only thing that I couldnt replace with a few lines of my own code was debounce. However I found [a 40 line replacement][debounce].
### {% linkable_title Replace moment.js with Fecha %}
### <a class='title-link' name='replace-momentjs-with-fecha' href='#replace-momentjs-with-fecha'></a> Replace moment.js with Fecha
Moment.js is one of those power libraries. It is able to handle any date problem that you can throw at it. But this obviously comes at the cost of size. [Fecha] is a date formatting library at ~8% the size of moment.js (only 4.7kb pre-gzip). The only thing that it does not contain is date manipulation, which was something that was not being used.
# {% linkable_title Use Service worker to instantly load the app %}
# <a class='title-link' name='use-service-worker-to-instantly-load-the-app' href='#use-service-worker-to-instantly-load-the-app'></a> Use Service worker to instantly load the app
Using a service worker were able to store all app components and core javascript in the browser. This means that after their first visit, the browser will only have to go to the network to fetch the latest data from the server.
@ -170,7 +170,7 @@ When a browser does not support service workers, Home Assistant will serve finge
Using fingerprinting with sw-precache required jumping through a few hoops. [The final build script can be found here.][build-sw]
# {% linkable_title Make it feel fast %}
# <a class='title-link' name='make-it-feel-fast' href='#make-it-feel-fast'></a> Make it feel fast
This one is more psychological: no one likes staring at a white screen because white screens are ambiguous: are we loading something, is there a crappy connection or maybe even a script error? Thats why it is very important to render something on the screen to show that the rest is being loaded, and as quickly as possible.
@ -178,7 +178,7 @@ The Home Assistant landing page contains just enough CSS and HTML to render the
Now that the app is fast enough, I might swap out moving from a lite loading screen to drawing an empty toolbar. This makes it look like the UI is almost there.
# {% linkable_title Using a framework build on web standards %}
# <a class='title-link' name='using-a-framework-build-on-web-standards' href='#using-a-framework-build-on-web-standards'></a> Using a framework build on web standards
_I left this to the end of the list, mainly because I had no influence on this. Polymer just happened to ship an update while I was optimizing the application which gave a big boost to the loading time._
@ -186,7 +186,7 @@ By using Polymer we have the ability to use tomorrows web standards today. Th
Polymer 1.6 was introduced at the end of June and allowed the app to take advantage of native [CSS variables][css-vars] in Chrome and Firefox. It also introduced lazy registration. Both greatly sped up our loading times.
# {% linkable_title Future optimizations %}
# <a class='title-link' name='future-optimizations' href='#future-optimizations'></a> Future optimizations
A lot of optimizations have been applied but this journey will never be over. There are still a lot of opportunities to make things even faster. Some ideas that are on my list to explore: