Skip to content

[WIP] Bento Auto-Envelope#30275

Closed
jridgewell wants to merge 5 commits intoampproject:mainfrom
jridgewell:auto-envelope
Closed

[WIP] Bento Auto-Envelope#30275
jridgewell wants to merge 5 commits intoampproject:mainfrom
jridgewell:auto-envelope

Conversation

@jridgewell
Copy link
Copy Markdown
Contributor

This is a WIP PR to add Bento mode (HTML page not managed by v0 Runtime) support to our Bento components. This requires several pieces:

  1. A minimal BaseElement implementation
  2. A minimal CustomElement implementation to wrap the BaseElement
  3. A "auto-detect" binary wrapper
    • Which registers the Bento component with AMP Runtime if available (or we suspect it's included but not loaded)
    • Or which registers the non-managed minimal implementations

@amp-owners-bot
Copy link
Copy Markdown

Hey @erwinmombay! These files were changed:

build-system/babel-plugins/babel-plugin-transform-amp-extension-call/index.js
build-system/babel-plugins/babel-plugin-transform-amp-extension-call/test/fixtures/transform-call/transform-simple-body/input.js
build-system/babel-plugins/babel-plugin-transform-amp-extension-call/test/fixtures/transform-call/transform-simple-body/output.js
build-system/eslint-rules/restrict-this-access.js
build-system/eslint-rules/unused-private-field.js

@google-cla google-cla bot added the cla: yes label Sep 17, 2020
@jridgewell
Copy link
Copy Markdown
Contributor Author

I'm currently re-using the PreactBaseElement implementation in Bento mode, but I'm not 100% sure this is the right approach. The alternative is to take the PreactBaseElement.Component and have the CustomElement directly wrap that.

I couldn't decide one way or the other. It seems like PreactBaseElement is minimal enough, and provides useful helpers for translating from the actual element in HTML to the props the Component uses. However, the PreactBaseElement may make devs too comfortable and unintentionally use AMP APIs. I tried restricting this by adding a new lint restriction on this.FOO accesses.

@samouri samouri self-requested a review September 18, 2020 06:10
'getProp',
'mutateElement',
'mutateProps',
'registerAction',
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: do we want registerAction? my impression is that we'd only ever want the api interface

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Minimally, yes, we only need to proxy api() object. But I think Justin is trying to say here that the PreactBaseElement still has to serve both worlds so moth sets of APIs are still required.

Copy link
Copy Markdown
Contributor

@dvoytenko dvoytenko left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks like taking a clear shape! I'd still like a however-minimal design doc. Some important items:

  1. Boilerplate needs to change for Bento. Not clear how to do it "cleanly" yet. But we need to call it out in the doc as an open problem.
  2. There are some very clear and "cheap" actions we can take now and split the work that would make this whole thing a lot easier. Namely, we just need to devirtualize CustomElement and BaseElement APIs. Anything from applyFillContent to getRealChildren can and should just become static export function somewhere.
  3. Some of the critical decisions we'd have to make are thing like: do we have separate binaries for amp-carousel-0.1.js?bento? Or just one binary would suffice. This is something that design doc could highlight pretty well, including an estimate of the envelope's binary size.
  4. We need to come up with an "easy" way to proxy PreactBaseElement.api() on the element.

'getProp',
'mutateElement',
'mutateProps',
'registerAction',
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Minimally, yes, we only need to proxy api() object. But I think Justin is trying to say here that the PreactBaseElement still has to serve both worlds so moth sets of APIs are still required.

<link rel="canonical" href="amps.html">
<meta name="viewport" content="width=device-width,minimum-scale=1,initial-scale=1">
<!-- <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> -->
<style amp-boilerplate>
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So, this is a good point. We essentially want a different boilerplate ideally. Not sure yet how we can reconcile this with AMP mode. Ideally delta is somewhat small...

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you explain this?

In Bento mode wouldn't we not want any boilerplate.
For regular AMP mode, why do the boilerplate requirements change?

Admittedly I don't know much about our boilerplate except that we have visibility:hidden until the page has loaded to prevent FOUC

} else {
const container = doc.createElement('i-amphtml-c');
this.container_ = container;
this.applyFillContent(container);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok. This is a good track item: we really want to hollow out CustomEleemnt and BaseElement APIs. Sort of - everything that can become a static util - we should just make a static util, e.g. in a dom.js or a similar package.

* @param {function():undefined} cb
*/
mutateElement(cb) {
Promise.resolve().then(cb);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This would probably be best to be done via setTimeout(0). That way the ordering of a mutation is still predictable. Vs a microtask ordering is completely random from the caller's point of view. Also, I think we might have more problems from overloading microtasks then tasks.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

just to confirm: while this fn is necessary while we still need useResourcesNotify, ideally we can rm this fn right?

@CLAassistant
Copy link
Copy Markdown

CLAassistant commented Oct 8, 2020

CLA assistant check
All committers have signed the CLA.

const payload = extensionPayload(name);

return (
`(function(p){self.AMP?self.AMP.push(p):` +
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a bit tough for me to read. Is there any way for us to write this with standard-looking JS and then minify/turn into a string separately? Or at a minimum include a comment explaining what happens here.

My take:

  1. Check if its a page with Runtime present (via v0 presence in the head or if self.AMP is already initialized)
    2a. If yes, then add this extension to the AMP init array (or create it)
    2b. Otherwise, define the CE immediately

Did I get that right?

<link rel="canonical" href="amps.html">
<meta name="viewport" content="width=device-width,minimum-scale=1,initial-scale=1">
<!-- <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> -->
<style amp-boilerplate>
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you explain this?

In Bento mode wouldn't we not want any boilerplate.
For regular AMP mode, why do the boilerplate requirements change?

Admittedly I don't know much about our boilerplate except that we have visibility:hidden until the page has loaded to prevent FOUC

super();

/** @const {!CeBaseElement} */
this.implementation = new BaseElement(this);
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should the BE implementation be initialized in the CE ctor, or in connectedCallback? I know you had intended on deferring construction to connectedCallback for AMP mode so that we can ensure the document and services are available, but updating all the unit tests was a gargantuan task

* @param {function():undefined} cb
*/
mutateElement(cb) {
Promise.resolve().then(cb);
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

just to confirm: while this fn is necessary while we still need useResourcesNotify, ideally we can rm this fn right?

if (typeof AMP !== 'undefined' && AMP.BaseElement) {
BaseElement = AMP.BaseElement;
} else {
class CeBaseElement {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Did you experiment with trying to only have a CustomElement definition instead of a separate BaseElement as well? Do you think Bento components rely on helpers and utilities that would break without continuing the split

@powerivq
Copy link
Copy Markdown
Contributor

powerivq commented Sep 6, 2024

Batch closing Bento PRs.

@powerivq powerivq closed this Sep 6, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants