dbeam | f02a25aa | 2017-01-24 01:58:38 | [diff] [blame] | 1 | # Optimizing Chrome Web UIs |
| 2 | |
| 3 | ## How do I do it? |
| 4 | |
| 5 | In order to build with a fast configuration, try setting these options in your |
| 6 | GN args: |
| 7 | |
| 8 | ``` |
dpapad | d0ef1a9 | 2017-09-18 19:32:12 | [diff] [blame^] | 9 | optimize_webui = true |
dbeam | f02a25aa | 2017-01-24 01:58:38 | [diff] [blame] | 10 | is_debug = false |
| 11 | ``` |
| 12 | |
dbeam | f02a25aa | 2017-01-24 01:58:38 | [diff] [blame] | 13 | ## How is the code optimized? |
| 14 | |
| 15 | ### Resource combination |
| 16 | |
| 17 | [HTML imports](https://www.html5rocks.com/en/tutorials/webcomponents/imports/) |
| 18 | are a swell technology, but can be used is slow ways. Each import may also |
| 19 | contain additional imports, which must be satisfied before certain things can |
| 20 | continue (i.e. script execution may be paused). |
| 21 | |
| 22 | ```html |
| 23 | <!-- If a.html contains more imports... --> |
| 24 | <link rel="import" href="a.html"> |
| 25 | <!-- This script is blocked until done. --> |
| 26 | <script> startThePageUp(); </script> |
| 27 | ``` |
| 28 | |
| 29 | To reduce this latency, Chrome uses a tool created by the Polymer project named |
dpapad | 1e6a87f5 | 2017-07-22 00:22:25 | [diff] [blame] | 30 | [polymer-bundler](https://github.com/Polymer/polymer-bundler). It processes |
dbeam | f02a25aa | 2017-01-24 01:58:38 | [diff] [blame] | 31 | a page starting from a URL entry point and inlines resources the first time |
| 32 | they're encountered. This greatly decreases latency due to HTML imports. |
| 33 | |
| 34 | ```html |
| 35 | <!-- Contents of a.html and all its dependencies. --> |
| 36 | <script> startThePageUp(); </script> |
| 37 | ``` |
| 38 | |
| 39 | ### CSS @apply to --var transformation |
| 40 | |
| 41 | We also use |
| 42 | [polymer-css-build](https://github.com/PolymerLabs/polymer-css-build) to |
| 43 | transform CSS @apply mixins (which are not yet natively supported) into faster |
| 44 | --css-variables. This turns something like this: |
| 45 | |
| 46 | ```css |
| 47 | :host { |
| 48 | --mixin-name: { |
| 49 | color: red; |
| 50 | display: block; |
| 51 | }; |
| 52 | } |
| 53 | /* In a different place */ |
| 54 | .red-thing { |
| 55 | @apply(--mixin-name); |
| 56 | } |
| 57 | ``` |
| 58 | |
| 59 | into the more performant: |
| 60 | |
| 61 | ```css |
| 62 | :host { |
| 63 | --mixin-name_-_color: red; |
| 64 | --mixin-name_-_display: block; |
| 65 | } |
| 66 | /* In a different place */ |
| 67 | .red-thing { |
| 68 | color: var(--mixin-name_-_color); |
| 69 | display: var(--mixin-name_-_display); |
| 70 | } |
| 71 | ``` |
| 72 | |
| 73 | ### JavaScript Minification |
| 74 | |
| 75 | In order to minimize disk size, we run |
| 76 | [uglifyjs](https://github.com/mishoo/UglifyJS2) on all combined JavaScript. This |
| 77 | reduces installer and the size of resources required to load to show a UI. |
| 78 | |
| 79 | Code like this: |
| 80 | |
| 81 | ```js |
| 82 | function fizzBuzz() { |
| 83 | for (var i = 1; i <= 100; i++) { |
| 84 | var fizz = i % 3 == 0 ? 'fizz' : ''; |
| 85 | var buzz = i % 5 == 0 ? 'buzz' : ''; |
| 86 | console.log(fizz + buzz || i); |
| 87 | } |
| 88 | } |
| 89 | fizzBuzz(); |
| 90 | ``` |
| 91 | |
| 92 | would be minified to: |
| 93 | |
| 94 | ```js |
| 95 | function fizzBuzz(){for(var z=1;100>=z;z++){var f=z%3==0?"fizz":"",o=z%5==0?"buzz":"";console.log(f+o||z)}}fizzBuzz(); |
| 96 | ``` |
| 97 | |
| 98 | If you'd like to more easily debug minified code, click the "{}" prettify button |
| 99 | in Chrome's developer tools, which will beautify the code and allow setting |
| 100 | breakpoints on the un-minified version. |
| 101 | |
| 102 | ### Gzip compression of web resources |
| 103 | |
| 104 | In certain cases, it might be preferable to leave web resources compressed on |
| 105 | disk and inflate them when needed (i.e. when a user wants to see a page). |
| 106 | |
| 107 | In this case, you can run `gzip --rsyncable` on a resource before it's put into |
| 108 | a .pak file via GRIT with this syntax: |
| 109 | |
| 110 | ```xml |
| 111 | <include name="IDR_MY_PAGE" file="my/page.html" type="BINDATA" compress="gzip" /> |
| 112 | ``` |
| 113 | |
| 114 | Gzip is currently set up to apply to a whole WebUI's data source, though it's |
| 115 | possible to exclude specific paths for things like dynamically generated content |
| 116 | (i.e. many pages load translations dynamically from a path named "strings.js"). |
| 117 | |
| 118 | To mark a WebUI's resources compressed, you'll need to do something like: |
| 119 | |
| 120 | ```c++ |
| 121 | WebUIDataSource* data_source = WebUIDataSource::Create(...); |
| 122 | data_source->SetDefaultResource(IDR_MY_PAGE); |
Peter Kasting | cd14904 | 2017-09-13 18:55:21 | [diff] [blame] | 123 | data_source->UseGzip({"strings.js", ...}); // Omit arg to compress everything |
dbeam | f02a25aa | 2017-01-24 01:58:38 | [diff] [blame] | 124 | ``` |