JS in AMP
See original GitHub issueMotivation
AMP offers the ability to easily author web pages with good performance and UX characteristics. One of the tradeoffs of AMP has made to guarantee good performance is the restriction on executing custom JS—this avoids the problems of heavy, slow JS but also prevents reasonable JS use cases. Features like amp-bind
help but, compared to non-AMP pages, it’s still more difficult for page authors to write dynamic and interactive widgets and often impossible to reuse existing JS code.
Our goal is to allow custom JS to run in a constrained environment for the purpose of building dynamic and interactive UI components. For example, this feature would support rendering a React component as a UI element on an AMP page.
Requirements
- Allow AMP publishers to author custom JS that renders a UI component
- Preserve AMP’s UX invariants of instant-loading and no-page-jumping
- Follow AMP’s design principles i.e. “user experience > developer experience” and “graceful degradation”
- Maintain strong security and privacy characteristics
Proposed design
We propose to allow 3P (custom) JS to run on a web worker that receives user gesture events from the page and sends mutation requests to the page over postMessage. The 3P JS will be run inside a custom-built sandbox and virtual DOM environment in the worker. The “worker DOM” offers DOM mutation APIs like setAttribute() and appendChild(), and forwards these as mutation requests to the page. The page then runs these mutation requests through a sanitizer—for security and to preserve AMP’s UX invariants—and performs these mutations on the real DOM. This functionality will be offered in a new AMP extension: <amp-script>
.
To preserve AMP’s instant-loading behavior, <amp-script>
will support “ahead-of-time” rendering. Similar to server-side rendering, the HTML markup for the initial render state of the 3P JS will be inlined as children of <amp-script>
and hydrated at runtime. This ensures that the latency of creating the web worker and running the 3P JS doesn’t impact time to first contentful paint.
To preserve AMP’s “no-page-jumping” invariant, mutation requests received from the worker will only be honored within a small window after a user gesture.
Proposed syntax:
<script async custom-element="amp-script"
src="https://cdn.ampproject.org/v0/amp-script-0.1.js"></script>
<!-- amp-script supports all defined-size layout types. -->
<amp-script src=”https://pub.com/my_custom_component.js” layout=responsive>
<!-- The children are the “ahead-of-time” render. -->
<div>...</div>
</amp-script>
3P JS can be provided either as an <script type=javascript/worker>
element or as an https://
source URL. If the URL is specified, the file will be versioned and cached on an AMP Cache (for pages served from Cache). This avoids skew between the AMP page HTML and 3P JS. Similar to AMP’s existing 50KB CSS size constraint, the 3P script will have a reasonable max file size that will be enforced (actual size TBD).
Issue Analytics
- State:
- Created 6 years ago
- Reactions:102
- Comments:42 (12 by maintainers)
You do understand that this is just another step in the direction of forking the web as-is and making a whole new version?
From a technical perspective this is a very exciting challenge, but the end result is that any company with a web presence must now create a regular HTML page and also create a separate AMP-specific version with increasingly divergent code base.
Basically, everything needs to be built twice. So… where does AMP end and the web begin now? The game appears to be forking the web and re-inventing the web browser.
We’re hoping for sometime Q2 next year. 😃