Commit 31f3b633 authored by dpapad's avatar dpapad Committed by Commit Bot

WebUI NTP: Split to main and lazy bundles to optimize load time.

In order to optimize the initial load time of the NTP, move
non-essential UI elements to a "lazy" loaded module. This
significantly reduces the amount of code that needs to load before
the initial paint. Specifically:

Before:
312K new_tab_page.rollup.js

After:
97K  new_tab_page.rollup.js
97K  shared.rollup.js
122K lazy_load.rollup.js

which means that there is a ~38% reduction (312 -> 97 + 97 = 194K),
in the size of the code that is loaded on startup.

Bug: None
Change-Id: I8f9d0e41047538015f3c41cac0ac3ba5fb1fffdd
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2425330
Commit-Queue: dpapad <dpapad@chromium.org>
Reviewed-by: default avatarTibor Goldschwendt <tiborg@chromium.org>
Reviewed-by: default avatarMoe Ahmadi <mahmadi@chromium.org>
Cr-Commit-Position: refs/heads/master@{#821880}
parent 9f582f34
......@@ -20,6 +20,7 @@ js_type_check("closure_compile") {
":doodle_share_dialog",
":fakebox",
":iframe",
":lazy_load",
":logo",
":new_tab_page",
":one_google_bar_api",
......@@ -43,11 +44,19 @@ js_library("new_tab_page") {
":app",
":background_manager",
":browser_proxy",
":customize_dialog",
":promo_browser_command_proxy",
":utils",
"modules:module_descriptor",
"modules:module_registry",
]
}
js_library("lazy_load") {
deps = [
":customize_dialog",
":middle_slot_promo",
":most_visited",
":voice_search_overlay",
"modules/dummy:module",
"modules/kaleidoscope:module",
]
......@@ -67,8 +76,7 @@ js_library("app") {
deps = [
":background_manager",
":browser_proxy",
":middle_slot_promo",
":most_visited",
":customize_dialog_types",
":one_google_bar_api",
":promo_browser_command_proxy",
"modules:module_wrapper",
......@@ -77,6 +85,7 @@ js_library("app") {
"//ui/webui/resources/cr_elements/cr_toast:cr_toast.m",
"//ui/webui/resources/js:event_tracker.m",
"//ui/webui/resources/js:load_time_data.m",
"//ui/webui/resources/js/cr/ui:focus_outline_manager.m",
]
}
......@@ -111,6 +120,7 @@ js_library("most_visited") {
js_library("customize_dialog") {
deps = [
":customize_backgrounds",
":customize_dialog_types",
":customize_shortcuts",
":utils",
"//third_party/polymer/v3_0/components-chromium/polymer:polymer_bundled",
......@@ -120,8 +130,13 @@ js_library("customize_dialog") {
]
}
js_library("customize_dialog_types") {
}
js_library("customize_backgrounds") {
deps = [
":browser_proxy",
":customize_dialog_types",
"//third_party/polymer/v3_0/components-chromium/polymer:polymer_bundled",
]
}
......@@ -275,13 +290,15 @@ if (optimize_webui) {
in_folder = "./"
out_folder = "$target_gen_dir/$preprocess_folder"
in_files = [
"background_manager.js",
"browser_proxy.js",
"img.js",
"lazy_load.js",
"customize_dialog_types.js",
"new_tab_page.js",
"one_google_bar_api.js",
"promo_browser_command_proxy.js",
"img.js",
"browser_proxy.js",
"utils.js",
"background_manager.js",
]
}
......@@ -322,8 +339,15 @@ if (optimize_webui) {
"modules:preprocess",
"modules:preprocess_gen",
]
js_module_in_files = [ "new_tab_page.js" ]
js_out_files = [ "new_tab_page.rollup.js" ]
js_module_in_files = [
"new_tab_page.js",
"lazy_load.js",
]
js_out_files = [
"new_tab_page.rollup.js",
"lazy_load.rollup.js",
"shared.rollup.js",
]
excludes = [
"chrome://resources/js/cr.m.js",
"chrome://resources/mojo/mojo/public/js/mojo_bindings_lite.js",
......
......@@ -281,12 +281,12 @@
theme="[[theme_.searchBox]]" shown$="[[realboxShown_]]"
hidden$="[[!realboxEnabled_]]">
</ntp-realbox>
<ntp-most-visited id="mostVisited" dark$="[[theme_.isDark]]"
use-white-add-icon$="[[theme_.shortcutUseWhiteAddIcon]]"
use-title-pill$="[[theme_.shortcutUseTitlePill]]">
</ntp-most-visited>
<dom-if if="[[lazyRender_]]" on-dom-change="onLazyRendered_">
<template>
<ntp-most-visited id="mostVisited" dark$="[[theme_.isDark]]"
use-white-add-icon$="[[theme_.shortcutUseWhiteAddIcon]]"
use-title-pill$="[[theme_.shortcutUseTitlePill]]">
</ntp-most-visited>
<ntp-middle-slot-promo
on-ntp-middle-slot-promo-loaded="onMiddleSlotPromoLoaded_" hidden>
</ntp-middle-slot-promo>
......
......@@ -3,10 +3,6 @@
// found in the LICENSE file.
import './strings.m.js';
import './middle_slot_promo.js';
import './most_visited.js';
import './customize_dialog.js';
import './voice_search_overlay.js';
import './iframe.js';
import './fakebox.js';
import './realbox.js';
......@@ -26,7 +22,7 @@ import {html, PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/poly
import {BackgroundManager} from './background_manager.js';
import {BrowserProxy} from './browser_proxy.js';
import {BackgroundSelection, BackgroundSelectionType} from './customize_dialog.js';
import {BackgroundSelection, BackgroundSelectionType} from './customize_dialog_types.js';
import {ModuleDescriptor} from './modules/module_descriptor.js';
import {ModuleRegistry} from './modules/module_registry.js';
import {oneGoogleBarApi} from './one_google_bar_api.js';
......@@ -41,6 +37,14 @@ import {$$} from './utils.js';
*/
let CommandData;
// Adds a <script> tag that holds the lazy loaded code.
function ensureLazyLoaded() {
const script = document.createElement('script');
script.type = 'module';
script.src = './lazy_load.js';
document.body.appendChild(script);
}
class AppElement extends PolymerElement {
static get is() {
return 'ntp-app';
......@@ -349,6 +353,7 @@ class AppElement extends PolymerElement {
super.ready();
// Let the browser breath and then render remaining elements.
BrowserProxy.getInstance().waitForLazyRender().then(() => {
ensureLazyLoaded();
this.lazyRender_ = true;
});
this.printPerformance_();
......@@ -834,7 +839,8 @@ class AppElement extends PolymerElement {
}
const onResize = () => {
const promoElement = $$(this, 'ntp-middle-slot-promo');
const hidePromo = this.$.mostVisited.getBoundingClientRect().bottom >=
const hidePromo =
$$(this, '#mostVisited').getBoundingClientRect().bottom >=
promoElement.offsetTop;
promoElement.style.visibility = hidePromo ? 'hidden' : 'visible';
};
......
......@@ -85,7 +85,7 @@ export class BrowserProxy {
*/
waitForLazyRender() {
return new Promise((resolve, reject) => {
setTimeout(resolve, 50);
requestIdleCallback(resolve);
});
}
......
......@@ -11,7 +11,7 @@ import {loadTimeData} from 'chrome://resources/js/load_time_data.m.js';
import {html, PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
import {BrowserProxy} from './browser_proxy.js';
import {BackgroundSelection, BackgroundSelectionType} from './customize_dialog.js';
import {BackgroundSelection, BackgroundSelectionType} from './customize_dialog_types.js';
/** Element that lets the user configure the background. */
class CustomizeBackgroundsElement extends PolymerElement {
......
......@@ -18,28 +18,9 @@ import {loadTimeData} from 'chrome://resources/js/load_time_data.m.js';
import {html, PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
import {BrowserProxy} from './browser_proxy.js';
import {BackgroundSelection, BackgroundSelectionType} from './customize_dialog_types.js';
import {createScrollBorders} from './utils.js';
/** @enum {number} */
export const BackgroundSelectionType = {
NO_SELECTION: 0,
NO_BACKGROUND: 1,
IMAGE: 2,
DAILY_REFRESH: 3,
};
/**
* A user can make three types of background selections: no background, image
* or daily refresh for a selected collection. The selection is tracked an
* object of this type.
* @typedef {{
* type: !BackgroundSelectionType,
* image: (!newTabPage.mojom.CollectionImage|undefined),
* dailyRefreshCollectionId: (string|undefined),
* }}
*/
export let BackgroundSelection;
/**
* Dialog that lets the user customize the NTP such as the background color or
* image.
......
// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
/** @enum {number} */
export const BackgroundSelectionType = {
NO_SELECTION: 0,
NO_BACKGROUND: 1,
IMAGE: 2,
DAILY_REFRESH: 3,
};
/**
* A user can make three types of background selections: no background, image
* or daily refresh for a selected collection. The selection is tracked an
* object of this type.
* @typedef {{
* type: !BackgroundSelectionType,
* image: (!newTabPage.mojom.CollectionImage|undefined),
* dailyRefreshCollectionId: (string|undefined),
* }}
*/
export let BackgroundSelection;
// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
/**
* @fileoverview This file holds dependencies that are deliberately excluded
* from the main app.js module, to force them to load after other app.js
* dependencies. This is done to improve performance of initial rendering of
* core elements of the landing page, by delaying loading of non-core
* elements (either not visible by default or not as performance critical).
*/
import './customize_dialog.js';
import './middle_slot_promo.js';
import './most_visited.js';
import './voice_search_overlay.js';
......@@ -5,6 +5,7 @@
import 'chrome://resources/cr_elements/cr_grid/cr_grid.js';
import '../../img.js';
import '../../strings.m.js';
import {loadTimeData} from 'chrome://resources/js/load_time_data.m.js';
import {html, PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
......
......@@ -14,7 +14,7 @@ import './app.js';
export {BackgroundManager} from './background_manager.js';
export {BrowserProxy} from './browser_proxy.js';
export {BackgroundSelectionType} from './customize_dialog.js';
export {BackgroundSelectionType} from './customize_dialog_types.js';
export {ImgElement} from './img.js';
// <if expr="not is_official_build">
export {FooProxy} from './modules/dummy/foo_proxy.js';
......
......@@ -13,7 +13,9 @@
<release seq="1">
<includes>
<include name="IDR_NEW_TAB_PAGE_NEW_TAB_PAGE_JS"
file="new_tab_page.js" type="BINDATA" compress="false" preprocess="true"/>
file="new_tab_page.js" type="BINDATA" compress="false" />
<include name="IDR_NEW_TAB_PAGE_LAZY_LOAD_JS"
file="lazy_load.js" type="BINDATA" compress="false" preprocess="true"/>
<include name="IDR_NEW_TAB_PAGE_APP_JS"
file="${root_gen_dir}/chrome/browser/resources/new_tab_page/app.js"
use_base_dir="false" type="BINDATA" compress="false"
......@@ -27,6 +29,8 @@
<include name="IDR_NEW_TAB_PAGE_CUSTOMIZE_DIALOG_JS"
file="${root_gen_dir}/chrome/browser/resources/new_tab_page/customize_dialog.js"
use_base_dir="false" type="BINDATA" compress="false" />
<include name="IDR_NEW_TAB_PAGE_CUSTOMIZE_DIALOG_TYPES_JS"
file="customize_dialog_types.js" type="BINDATA" compress="false" />
<include name="IDR_NEW_TAB_PAGE_VOICE_SEARCH_OVERLAY_JS"
file="${root_gen_dir}/chrome/browser/resources/new_tab_page/voice_search_overlay.js"
use_base_dir="false" type="BINDATA" compress="false" />
......
......@@ -12,9 +12,15 @@
</outputs>
<release seq="1">
<includes>
<include name="IDR_NEW_TAB_PAGE_NEW_TAB_PAGE_JS"
<include name="IDR_NEW_TAB_PAGE_NEW_TAB_PAGE_ROLLUP_JS"
file="${root_gen_dir}/chrome/browser/resources/new_tab_page/new_tab_page.rollup.js"
use_base_dir="false" type="BINDATA" />
<include name="IDR_NEW_TAB_PAGE_LAZY_LOAD_ROLLUP_JS"
file="${root_gen_dir}\chrome\browser\resources\new_tab_page\lazy_load.rollup.js"
type="BINDATA" use_base_dir="false" />
<include name="IDR_NEW_TAB_PAGE_SHARED_ROLLUP_JS"
file="${root_gen_dir}\chrome\browser\resources\new_tab_page\shared.rollup.js"
type="BINDATA" use_base_dir="false" />
<part file="new_tab_page_resources_common.grdp" />
</includes>
</release>
......
......@@ -5,6 +5,7 @@
import './strings.m.js';
import './realbox_button.js';
import './realbox_match.js';
import 'chrome://resources/polymer/v3_0/iron-selector/iron-selector.js';
import {assert} from 'chrome://resources/js/assert.m.js';
import {skColorToRgba} from 'chrome://resources/js/color_utils.js';
......
......@@ -261,7 +261,11 @@ content::WebUIDataSource* CreateNewTabPageUiHtmlSource(Profile* profile) {
IDR_NEW_TAB_PAGE_FOO_MOJO_LITE_JS);
#endif
#if BUILDFLAG(OPTIMIZE_WEBUI)
source->AddResourcePath("new_tab_page.js", IDR_NEW_TAB_PAGE_NEW_TAB_PAGE_JS);
source->AddResourcePath("new_tab_page.js",
IDR_NEW_TAB_PAGE_NEW_TAB_PAGE_ROLLUP_JS);
source->AddResourcePath("shared.rollup.js",
IDR_NEW_TAB_PAGE_SHARED_ROLLUP_JS);
source->AddResourcePath("lazy_load.js", IDR_NEW_TAB_PAGE_LAZY_LOAD_ROLLUP_JS);
#endif // BUILDFLAG(OPTIMIZE_WEBUI)
webui::SetupWebUIDataSource(
source, base::make_span(kNewTabPageResources, kNewTabPageResourcesSize),
......
......@@ -382,18 +382,20 @@ suite('NewTabPageAppTest', () => {
const theme = createTheme();
theme.shortcutUseWhiteAddIcon = true;
testProxy.callbackRouterRemote.setTheme(theme);
assertFalse(app.$.mostVisited.hasAttribute('use-white-add-icon'));
const mostVisited = $$(app, '#mostVisited');
assertFalse(mostVisited.hasAttribute('use-white-add-icon'));
await testProxy.callbackRouterRemote.$.flushForTesting();
assertTrue(app.$.mostVisited.hasAttribute('use-white-add-icon'));
assertTrue(mostVisited.hasAttribute('use-white-add-icon'));
});
test('theme updates use title pill', async () => {
const theme = createTheme();
theme.shortcutUseTitlePill = true;
testProxy.callbackRouterRemote.setTheme(theme);
assertFalse(app.$.mostVisited.hasAttribute('use-title-pill'));
const mostVisited = $$(app, '#mostVisited');
assertFalse(mostVisited.hasAttribute('use-title-pill'));
await testProxy.callbackRouterRemote.$.flushForTesting();
assertTrue(app.$.mostVisited.hasAttribute('use-title-pill'));
assertTrue(mostVisited.hasAttribute('use-title-pill'));
});
test('executes promo browser command', async () => {
......
......@@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'chrome://new-tab-page/lazy_load.js';
import {BackgroundSelectionType, BrowserProxy} from 'chrome://new-tab-page/new_tab_page.js';
import {assertNotStyle, assertStyle, createTestProxy} from 'chrome://test/new_tab_page/test_support.js';
import {eventToPromise, flushTasks, isVisible} from 'chrome://test/test_util.m.js';
......
......@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'chrome://new-tab-page/new_tab_page.js';
import 'chrome://new-tab-page/lazy_load.js';
import {keydown} from 'chrome://test/new_tab_page/test_support.js';
import {flushTasks} from 'chrome://test/test_util.m.js';
......
......@@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'chrome://new-tab-page/lazy_load.js';
import {BackgroundSelectionType, BrowserProxy} from 'chrome://new-tab-page/new_tab_page.js';
import {createTestProxy} from 'chrome://test/new_tab_page/test_support.js';
import {flushTasks, isVisible, waitAfterNextRender} from 'chrome://test/test_util.m.js';
......
......@@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'chrome://new-tab-page/lazy_load.js';
import {BrowserProxy} from 'chrome://new-tab-page/new_tab_page.js';
import {createTestProxy} from 'chrome://test/new_tab_page/test_support.js';
......
......@@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'chrome://new-tab-page/lazy_load.js';
import {BrowserProxy} from 'chrome://new-tab-page/new_tab_page.js';
import {createTestProxy} from 'chrome://test/new_tab_page/test_support.js';
......
......@@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'chrome://new-tab-page/lazy_load.js';
import {BrowserProxy, PromoBrowserCommandProxy} from 'chrome://new-tab-page/new_tab_page.js';
import {createTestProxy} from 'chrome://test/new_tab_page/test_support.js';
import {TestBrowserProxy} from 'chrome://test/test_browser_proxy.m.js';
......
......@@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'chrome://new-tab-page/lazy_load.js';
import {BrowserProxy} from 'chrome://new-tab-page/new_tab_page.js';
import {assertFocus, createTestProxy, keydown} from 'chrome://test/new_tab_page/test_support.js';
import {eventToPromise} from 'chrome://test/test_util.m.js';
......
......@@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'chrome://new-tab-page/lazy_load.js';
import {$$, BrowserProxy} from 'chrome://new-tab-page/new_tab_page.js';
import {isMac} from 'chrome://resources/js/cr.m.js';
import {assertNotStyle, assertStyle, createTestProxy, keydown} from 'chrome://test/new_tab_page/test_support.js';
......
......@@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'chrome://new-tab-page/lazy_load.js';
import {$$, BrowserProxy} from 'chrome://new-tab-page/new_tab_page.js';
import {loadTimeData} from 'chrome://resources/js/load_time_data.m.js';
import {flushTasks, isVisible} from 'chrome://test/test_util.m.js';
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment