Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We鈥檒l occasionally send you account related emails.

Already on GitHub? Sign in to your account

馃摉 Fix amp-script doc #29582

Merged
merged 4 commits into from
Jul 30, 2020
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
39 changes: 21 additions & 18 deletions extensions/amp-script/amp-script.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ formats:
- websites
teaser:
text: Runs custom JavaScript in a Web Worker.
experimental: true
---

<!---
Expand Down Expand Up @@ -32,7 +31,7 @@ An `amp-script` element can load JavaScript in two ways:
- remotely, from a URL
- locally, from a `<script>` element on the page

#### Load JavaScript from a remote URL
### Load JavaScript from a remote URL
Copy link
Contributor

Choose a reason for hiding this comment

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

Thanks for fixing these! This was also on my to-do list. Now I don't have to :)


Use the `src` attribute to load JavaScript from a URL:

Expand All @@ -42,7 +41,7 @@ Use the `src` attribute to load JavaScript from a URL:
</amp-script>
```

#### Load JavaScript from a local element
### Load JavaScript from a local element

You can also include your JavaScript inline, in a `script` tag. You must:

Expand Down Expand Up @@ -78,7 +77,7 @@ You can also include your JavaScript inline, in a `script` tag. You must:
For security reasons, `amp-script` elements with a `script` or cross-origin `src` attribute require a [script hash](#script-hash) in a `<meta name="amp-script-src" content="...">` tag. Also, same-origin `src` files must have [`Content-Type`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Type): `application/javascript` or `text/javascript`.
[/tip]

### How does it work?
## How does it work?

`amp-script` runs your custom JavaScript in a [Web Worker](https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Using_web_workers) that has access to a virtual DOM. When your JavaScript code modifies this virtual DOM, `amp-script` forwards these changes to the main thread and applies them to the `amp-script` element subtree.

Expand All @@ -101,7 +100,7 @@ Will be reflected on the page as a new child of the `amp-script` element:

Under the hood, `amp-script` uses [@ampproject/worker-dom](https://github.com/ampproject/worker-dom/). For design details, see the ["Intent to Implement" issue](https://github.com/ampproject/amphtml/issues/13471).

### State manipulation
## State manipulation

`amp-script` supports getting and setting [`amp-state`](https://amp.dev/documentation/components/amp-bind/#initializing-state-with-amp-state) JSON via JavaScript.

Expand All @@ -126,7 +125,7 @@ AMP.setState(json) {}
AMP.getState(expr) {}
```

##### Example with WebSocket and AMP.setState()
### Example with WebSocket and AMP.setState()

```html
<amp-script width="1" height="1" script="webSocketDemo"> </amp-script>
Expand All @@ -143,22 +142,22 @@ AMP.getState(expr) {}
</script>
```

### Restrictions
## Restrictions

#### Allowed APIs
### Allowed APIs

Currently, most DOM elements and their properties are supported. DOM query APIs like `querySelector` have partial support. Browser APIs like `History` are not implemented yet. See the [API compatibility table](https://github.com/ampproject/worker-dom/blob/master/web_compat_table.md) for details.

If there's an API you'd like to see supported, please [file an issue](https://github.com/ampproject/amphtml/issues/new) and mention `@choumx` and `@kristoferbaxter`.

#### Size of JavaScript code <a name="size-of-javascript-code"></a>
### Size of JavaScript code <a name="size-of-javascript-code"></a>

`amp-script` has the following restrictions on JavaScript file size:

- Maximum of 10,000 bytes per `amp-script` element that uses a local script via `script[type=text/plain][target=amp-script]`.
- Maximum total of 150,000 bytes for all `amp-script` elements on the page.

#### User gestures <a name="user-gestures"></a>
### User gestures <a name="user-gestures"></a>

In some cases, `amp-script` requires a user gesture to apply changes triggered by your JavaScript code (we call these "mutations") to the `amp-script`'s DOM children. This helps avoid poor user experience from unexpected content jumping.

Expand All @@ -167,11 +166,11 @@ The rules for mutations are as follows:
1. For `amp-script` elements with [non-container layout](https://amp.dev/documentation/guides-and-tutorials/develop/style_and_layout/control_layout#supported-values-for-the-layout-attribute), mutations are always allowed.
2. For `amp-script` elements with container layout, mutations are allowed for five seconds following a user gesture. This five second window is extended once if a `fetch()` is triggered.

#### Creating AMP elements
### Creating AMP elements

With regard to dynamic creation of AMP elements (e.g. via `document.createElement()`), only `amp-img` and `amp-layout` are currently allowed. Please upvote or comment on {{'[% raw %]'}}[#{{'{% endraw %}'}}25344](https://github.com/ampproject/amphtml/issues/25344) with your use case.
With regard to dynamic creation of AMP elements (e.g. via `document.createElement()`), only `amp-img` and `amp-layout` are currently allowed. Please upvote or comment on [&#35;25344](https://github.com/ampproject/amphtml/issues/25344) with your use case.

### Calculating the script hash <a name="script-hash"></a>
## Calculating the script hash <a name="script-hash"></a>

Since custom JS run in `amp-script` is not subject to normal [Content Security Policy](https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP), you need to add this script hash:

Expand All @@ -188,11 +187,13 @@ Include the script hash in a `meta[name=amp-script-src]` element in the document
2. base64url-encode the result.
3. Prefix that with `sha384-`.

Here's you might build the hash in node.js:
Here's how you calculate the hash in Node.js:

```js
const crypto = require('crypto');
const hash = crypto.createHash('sha384');

function generateCSPHash(script) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Good idea to suggest that people do this by importing the toolbox. Especially as then they'll be up-to-date if somehow we ever change the way this is calculated. I did also change the docs to mention the toolbox earlier.

That said, I think people should also know how to do this themselves - and providing the sample code is more explicit than the instructions I gave.

Why don't we include both methods?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Developers should use the toolbox library instead of implementing it on their own. This gives us an easier upgrade path if we'd decide to change the implementation in the future. If they want to see the implementation they can look at the source code of the NPM module.

const hash = crypto.createHash('sha384');
const data = hash.update(script, 'utf-8');
return (
'sha384-' +
Expand All @@ -205,6 +206,8 @@ function generateCSPHash(script) {
}
```

There is also a node module available which does it for you: [@ampproject/toolbox-script-csp](https://www.npmjs.com/package/@ampproject/toolbox-script-csp).

This example shows how to use the script hash in HTML:

```html
Expand Down Expand Up @@ -291,14 +294,14 @@ This element includes [common attributes](https://amp.dev/documentation/guides-a

There are several types of runtime errors that may be encountered when using `amp-script`.

#### "Maximum total script size exceeded (...)"
### "Maximum total script size exceeded (...)"

`amp-script` limits the size of the JS source that may be used. See [Size of JavaScript code](#size-of-javascript-code) above.

#### "Script hash not found."
### "Script hash not found."

For local scripts and cross-origin scripts, you need to add a [script hash](#script-hash) for security.

#### "amp-script... was terminated due to illegal mutation"
### "amp-script... was terminated due to illegal mutation"

To avoid unexpected content jumping, `amp-script` generally requires user gestures for DOM changes. See [User gestures](#user-gestures) above.