Skip to content

Commit

Permalink
Deferred build API and builder
Browse files Browse the repository at this point in the history
  • Loading branch information
Dima Voytenko committed Feb 10, 2021
1 parent 6025d6f commit 6c385ba
Show file tree
Hide file tree
Showing 8 changed files with 733 additions and 84 deletions.
1 change: 1 addition & 0 deletions build-system/global-configs/experiments-const.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
{
"BENTO_AUTO_UPGRADE": false,
"INI_LOAD_INOB": false,
"V2_IMG_VIDEO": false,
"WITHIN_VIEWPORT_INOB": false
}
4 changes: 4 additions & 0 deletions build-system/tasks/presubmit-checks.js
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,10 @@ const forbiddenTerms = {
],
},
// Service factories that should only be installed once.
'getBuilderForDoc': {
message: 'can only be used by the runtime',
allowlist: ['src/custom-element.js'],
},
'installActionServiceForDoc': {
message: privateServiceFactory,
allowlist: [
Expand Down
45 changes: 45 additions & 0 deletions builtins/amp-img.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

import {BaseElement} from '../src/base-element';
import {Layout, isLayoutSizeDefined} from '../src/layout';
import {ReadyState} from '../src/ready-state';
import {Services} from '../src/services';
import {dev} from '../src/log';
import {guaranteeSrcForSrcsetUnsupportedBrowsers} from '../src/utils/img';
Expand Down Expand Up @@ -45,6 +46,16 @@ const ATTRIBUTES_TO_PROPAGATE = [
];

export class AmpImg extends BaseElement {
/** @override @nocollapse */
static V2() {
return V2_IMG_VIDEO;
}

/** @override @nocollapse */
static deferredBuild() {
return true;
}

/** @override @nocollapse */
static prerenderAllowed() {
return true;
Expand Down Expand Up @@ -106,6 +117,10 @@ export class AmpImg extends BaseElement {
if (!IS_ESM) {
guaranteeSrcForSrcsetUnsupportedBrowsers(this.img_);
}

if (AmpImg.V2() && !this.img_.complete) {
this.onReadyState(ReadyState.LOADING);
}
}
}

Expand Down Expand Up @@ -255,6 +270,36 @@ export class AmpImg extends BaseElement {
return false;
}

/** @override */
buildCallback() {
if (!AmpImg.V2()) {
return;
}

// A V2 amp-img loads and reloads automatically.
this.onReadyState(ReadyState.LOADING);
this.initialize_();
const img = dev().assertElement(this.img_);
if (img.complete) {
this.onReadyState(ReadyState.COMPLETE);
this.hideFallbackImg_();
}
listen(img, 'load', () => {
this.onReadyState(ReadyState.COMPLETE);
this.hideFallbackImg_();
});
listen(img, 'error', (reason) => {
this.onReadyState(ReadyState.ERROR, reason);
this.onImgLoadingError_();
});
}

/** @override */
ensureLoaded() {
const img = dev().assertElement(this.img_);
img.loading = 'eager';
}

/** @override */
layoutCallback() {
this.initialize_();
Expand Down
71 changes: 71 additions & 0 deletions src/base-element.js
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,57 @@ import {isArray, toWin} from './types';
* @implements {BaseElementInterface}
*/
export class BaseElement {
/**
* Whether this element supports V2 protocol, which includes:
* 1. Layout/unlayout are not managed by the runtime, but instead are
* implemented by the element as needed.
* 2. The element will wait until it's fully parsed before building, unless
* it's mutable. See `mutable`.
* 3. The element can defer its build until later. See `deferredBuild`.
* 4. The construction of the element is delayed until build.
*
* Notice, in this mode `layoutCallback`, `pauseCallback`, `onLayoutMeasure`,
* `getLayoutSize`, and other methods are deprecated. The element must
* independently handle each of these states internally.
*
* @return {boolean}
* @nocollapse
*/
static V2() {
return false;
}

/**
* Whether this element supports mutations. A mutable elementcan be built
* immediately, even before the element has been fully parsed, thus it should
* be able to apply additional markup when it's parsed. Normally, however,
* the element will wait until it's fully parsed before building to save
* resources.
*
* Only used for V2 elements.
*
* @return {boolean}
* @nocollapse
*/
static mutable() {
return false;
}

/**
* Whether this element supports deferred-build mode. In this mode, the
* element's build will be deferred roughly based on the
* `content-visibility: auto` rules.
*
* Only used for V2 elements.
*
* @param {!AmpElement} unusedElement
* @return {boolean}
* @nocollapse
*/
static deferredBuild(unusedElement) {
return false;
}

/**
* Subclasses can override this method to opt-in into being called to
* prerender when document itself is not yet visible (pre-render mode).
Expand Down Expand Up @@ -414,6 +465,26 @@ export class BaseElement {
return false;
}

/**
* Ensure that the element is being eagerly loaded.
*
* Only used for V2 elements.
*/
ensureLoaded() {}

/**
* Update the current `readyState`.
*
* Only used for V2 elements.
*
* @param {!./ready-state.ReadyState} state
* @param {*=} opt_failure
* @final
*/
onReadyState(state, opt_failure) {
this.element.onReadyStateInternal(state, opt_failure);
}

/**
* Subclasses can override this method to opt-in into receiving additional
* {@link layoutCallback} calls. Note that this method is not consulted for
Expand Down
Loading

0 comments on commit 6c385ba

Please sign in to comment.