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 9, 2021
1 parent 6025d6f commit 19d969c
Show file tree
Hide file tree
Showing 7 changed files with 830 additions and 80 deletions.
41 changes: 41 additions & 0 deletions builtins/amp-img.js
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,16 @@ const ATTRIBUTES_TO_PROPAGATE = [
];

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

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

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

if (AmpImg.V2() && !this.img_.complete) {
this.onReadyState('loading');
}
}
}

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

/** @override */
buildCallback() {
if (AmpImg.V2()) {
this.onReadyState('loading');
this.initialize_();
const img = dev().assertElement(this.img_);
if (img.complete) {
this.onReadyState('complete');
this.hideFallbackImg_();
}
listen(img, 'load', () => {
this.onReadyState('complete');
this.hideFallbackImg_();
});
listen(img, 'error', (reason) => {
this.onReadyState('error', reason);
this.onImgLoadingError_();
});
}
}

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

/** @override */
layoutCallback() {
this.initialize_();
Expand Down
94 changes: 94 additions & 0 deletions examples/loader-bento.amp.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>Lorem Ipsum | PublisherName</title>
<link rel="canonical" href="https://medium.com/p/cb7f223fad86" >
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
<script>
(self.AMP = self.AMP || []).push(function(AMP) {
AMP.toggleExperiment('bento', true, true);
});
</script>
<script async src="https://cdn.ampproject.org/v0.js"></script>
<script async custom-element="amp-carousel" src="https://cdn.ampproject.org/v0/amp-carousel-0.1.js"></script>
<script async custom-element="amp-video" src="https://cdn.ampproject.org/v0/amp-video-1.0.js"></script>
<script async custom-element="amp-instagram" src="https://cdn.ampproject.org/v0/amp-instagram-1.0.js"></script>

<style amp-custom>
body {
margin: 0;
font-family: 'Georgia', Serif;
background: white;
}

</style>
<link href='https://fonts.googleapis.com/css?family=Georgia|Open+Sans|Roboto' rel='stylesheet' type='text/css'>
</head>
<body>
<!--
<div style="height: 500vh">scroll</div>
-->

<!--
-->
<amp-img id="hero-img"
src="img/hero@1x.jpg"
srcset="img/hero@1x.jpg 1x, img/hero@2x.jpg 2x"
layout="responsive" width="360"
height="216"
noprerender>
<script>
//debugger;//QQQQQQ
</script>
</amp-img>

<!--
<amp-video id="video1"
src="https://commondatastorage.googleapis.com/gtv-videos-bucket/sample/ForBiggerJoyrides.mp4"
width="358"
height="204"
layout="responsive"
controls>
<script>
//debugger;//QQQQQQ
</script>
</amp-video>
-->

<!--
<amp-iframe id="iframe1"
width=300 height=300
sandbox="allow-scripts allow-same-origin allow-popups allow-popups-to-escape-sandbox"
layout="responsive"
frameborder="0"
src="http://ads.localhost:8000/extensions/amp-iframe/0.1/storybook/iframe.html">
<div placeholder></div>
</amp-iframe>
-->

<!--
<amp-carousel id="carousel1" width=400 height=300 layout=fixed type=slides>
<amp-img id="hero-img"
src="img/hero@1x.jpg"
srcset="img/hero@1x.jpg 1x, img/hero@2x.jpg 2x"
layout="responsive" width="360"
height="216">
</amp-img>
<amp-video id="video1"
src="https://commondatastorage.googleapis.com/gtv-videos-bucket/sample/ForBiggerJoyrides.mp4"
width="358"
height="204"
layout="responsive"
controls></amp-video>
<amp-instagram id="insta1"
width=300 height=300
layout="responsive"
data-shortcode="B8QaZW4AQY_">
</amp-instagram>
</amp-carousel>
-->

<div style="height: 2000vh">scroll</div>
</body>
</html>
97 changes: 97 additions & 0 deletions examples/loader.amp.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
<!doctype html>
<html >
<head>
<meta charset="utf-8">
<title>Lorem Ipsum | PublisherName</title>
<link rel="canonical" href="https://medium.com/p/cb7f223fad86" >
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
<script async src="https://cdn.ampproject.org/v0.js"></script>
<script async custom-element="amp-carousel" src="https://cdn.ampproject.org/v0/amp-carousel-0.1.js"></script>
<script async custom-element="amp-video" src="https://cdn.ampproject.org/v0/amp-video-0.1.js"></script>
<script async custom-element="amp-iframe" src="https://cdn.ampproject.org/v0/amp-iframe-0.1.js"></script>

<style amp-custom>
body {
margin: 0;
font-family: 'Georgia', Serif;
background: white;
}

</style>
<link href='https://fonts.googleapis.com/css?family=Georgia|Open+Sans|Roboto' rel='stylesheet' type='text/css'>
<style amp-boilerplate>body{-webkit-animation:-amp-start 8s steps(1,end) 0s 1 normal both;-moz-animation:-amp-start 8s steps(1,end) 0s 1 normal both;-ms-animation:-amp-start 8s steps(1,end) 0s 1 normal both;animation:-amp-start 8s steps(1,end) 0s 1 normal both}@-webkit-keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}@-moz-keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}@-ms-keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}@-o-keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}@keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}</style><noscript><style amp-boilerplate>body{-webkit-animation:none;-moz-animation:none;-ms-animation:none;animation:none}</style></noscript>
</head>
<body>
<!--
<div style="height: 500vh">scroll</div>
-->

<!--
-->
<amp-img id="hero-img"
src="img/hero@1x.jpg"
srcset="img/hero@1x.jpg 1x, img/hero@2x.jpg 2x"
layout="responsive" width="360"
height="216"
noprerender_>
<script>
//debugger;//QQQQQQ
</script>
</amp-img>

<!--
<amp-video id="video1"
src="https://commondatastorage.googleapis.com/gtv-videos-bucket/sample/ForBiggerJoyrides.mp4"
width="358"
height="204"
layout="responsive"
controls>
<script>
//debugger;//QQQQQQ
</script>
</amp-video>
-->

<!--
<amp-iframe id="iframe1"
width=300 height=100
sandbox="allow-scripts allow-same-origin allow-popups allow-popups-to-escape-sandbox"
layout="responsive"
frameborder="0"
src="http://ads.localhost:8000/extensions/amp-iframe/0.1/storybook/iframe.html"
resizable>
<div placeholder></div>
<div overflow>overflow</div>
</amp-iframe>
-->

<!--
<amp-carousel id="carousel1" width=400 height=300 layout=fixed type=slides>
<amp-img id="hero-img"
src="img/hero@1x.jpg"
srcset="img/hero@1x.jpg 1x, img/hero@2x.jpg 2x"
layout="responsive" width="360"
height="216">
</amp-img>
<amp-video id="video1"
src="https://commondatastorage.googleapis.com/gtv-videos-bucket/sample/ForBiggerJoyrides.mp4"
width="358"
height="204"
layout="responsive"
controls></amp-video>
<amp-iframe id="iframe1"
width=300 height=300
sandbox="allow-scripts allow-same-origin allow-popups allow-popups-to-escape-sandbox"
layout="responsive"
frameborder="0"
src="http://ads.localhost:8000/extensions/amp-iframe/0.1/storybook/iframe.html">
<div placeholder></div>
</amp-iframe>
</amp-carousel>
-->

<!--
-->
<div style="height: 2000vh">scroll</div>
</body>
</html>
57 changes: 57 additions & 0 deletions src/base-element.js
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,49 @@ 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 can defer its build until later. See `deferredBuild`.
* 3. The construction of the element is delayed until build.
*
* @return {boolean}
* @nocollapse
*/
static V2() {
return false;
}

/**
* Whether this element supports mutations. This means that build can be
* done immediately, even before the element has been fully parsed, and
* it will be able to apply additional markup when it's parsed. Otherwise,
* the runtime must await the complete parse to complete before it can
* build the element.
*
* @return {boolean}
* @nocollapse
*/
static mutable() {
return false;
}

/**
* Whether this element supports deferred-build mode. In this mode, the custom
* element is not upgraded roughly based on the `content-visibility: auto`
* rules. The `BaseElement` instance is not created and the `buildCallback`
* is not called. At the same time, the `layoutCallback` is called
* automatically.
*
* @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 +457,20 @@ export class BaseElement {
return false;
}

/** Ensure that the element is being eagerly loaded. */
ensureLoaded() {}

/**
* Update the current `readyState`.
*
* @param {!LoadingState} 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 19d969c

Please sign in to comment.