Skip to content

Commit

Permalink
optimizer: Make dynamic component URL rewrites optional (ampproject#518)
Browse files Browse the repository at this point in the history
Not everyone who self-hosts the AMP runtime has the infrastructure to
support dynamic components like amp-geo, ref:
https://github.com/ampproject/amphtml/blob/master/spec/amp-cache-guidelines.md#guidelines-adding-a-new-cache-to-the-amp-ecosystem

Introduce option rewriteDynamicComponents that prevents modification of
dynamic component URLs that would otherwise have ampUrlPrefix
substituted.

Two relevant tests added:
 rewrites_host_but_not_dynamic_components_with_rtv
 rewrites_host_but_not_dynamic_components_without_rtv
  • Loading branch information
mattwomple authored and sebastianbenz committed Oct 9, 2019
1 parent 9e7533c commit 81e525d
Show file tree
Hide file tree
Showing 7 changed files with 123 additions and 9 deletions.
21 changes: 18 additions & 3 deletions packages/optimizer/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,8 @@ It's possible to rewrite the AMP framework and component imports to a different

**Notice:** The behavior of `ampUrlPrefix` when used in conjunction with `ampRuntimeVersion` changed beginning with version 1.1.2. Prior to 1.1.2, `rtv/{rtv}/` was automatically appended to `ampUrlPrefix` when `ampRuntimeVersion` was specified. Since version 1.1.2, `ampUrlPrefix` is not modified when `ampRuntimeVersion` is also specified.

- `rewriteDynamicComponents`: When used in conjunction with `ampUrlPrefix`, this option can be set to `false` to prevent [dynamic AMP components](https://github.com/ampproject/amphtml/blob/master/spec/amp-cache-guidelines.md#guidelines-adding-a-new-cache-to-the-amp-ecosystem) from having their URLs rewritten.

Examples:
```
const ampOptimizer = require('@ampproject/toolbox-optimizer');
Expand All @@ -204,14 +206,27 @@ const originalHtml = `
...
`
// this will rewrite https://cdn.ampproject.org/v0.js to /amp/v0.js
// this will rewrite https://cdn.ampproject.org/v0.js to /amp/v0.js and will
// rewrite dynamic component https://cdn.ampproject.org/v0/amp-geo-0.1.js to
// /amp/v0/amp-geo-0.1.js
const optimizedHtmlA = await ampOptimizer.transformHtml(originalHtml, {
ampUrlPrefix: '/amp'
});
// this will rewrite https://cdn.ampproject.org/v0.js to /amp/v0.js
// this will rewrite https://cdn.ampproject.org/v0.js to /amp/v0.js and will
// not rewrite dynamic component https://cdn.ampproject.org/v0/amp-geo-0.1.js
const optimizedHtmlB = await ampOptimizer.transformHtml(originalHtml, {
ampUrlPrefix: '/amp',
rewriteDynamicComponents: false
});
// this will rewrite https://cdn.ampproject.org/v0.js to
// /amp/001515617716922/v0.js and will rewrite dynamic component
// https://cdn.ampproject.org/v0/amp-geo-0.1.js to
// https://cdn.ampproject.org/v0/rtv/001515617716922/amp-geo-0.1.js
const optimizedHtmlC = await ampOptimizer.transformHtml(originalHtml, {
ampRuntimeVersion: '001515617716922',
ampUrlPrefix: '/amp'
ampUrlPrefix: '/amp/001515617716922',
rewriteDynamicComponents: false
});
```
6 changes: 6 additions & 0 deletions packages/optimizer/lib/AmpConstants.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,5 +18,11 @@
module.exports = {
AMP_TAGS: ['amp', '⚡', '⚡4ads'],
AMP_CACHE_HOST: 'https://cdn.ampproject.org',
// Should be kept up to date with dynamic components listed here:
// https://github.com/ampproject/amphtml/blob/master/spec/amp-cache-guidelines.md#guidelines-adding-a-new-cache-to-the-amp-ecosystem
AMP_DYNAMIC_COMPONENTS: {
'custom-element': ['amp-geo'],
'custom-template': [],
},
appendRuntimeVersion: (prefix, version) => prefix + '/rtv/' + version,
};
40 changes: 34 additions & 6 deletions packages/optimizer/lib/transformers/RewriteAmpUrls.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,17 @@
*/
'use strict';

const {AMP_CACHE_HOST, appendRuntimeVersion} = require('../AmpConstants.js');
const {
AMP_CACHE_HOST,
AMP_DYNAMIC_COMPONENTS,
appendRuntimeVersion,
} = require('../AmpConstants.js');
const {findMetaViewport} = require('../HtmlDomHelper');

/**
* RewriteAmpUrls - rewrites AMP runtime URLs.
*
* This transformer supports two parameters:
* This transformer supports several parameters:
*
* * `ampRuntimeVersion`: specifies a
* [specific version](https://github.com/ampproject/amp-toolbox/tree/master/runtime-version")
Expand All @@ -35,9 +39,14 @@ const {findMetaViewport} = require('../HtmlDomHelper');
* URLs being re-written from `https://cdn.ampproject.org/v0.js` to
* `/amp/v0.js`. This option is experimental and not recommended.
*
* Both parameters are optional. If no option is provided, runtime URLs won't be
* re-written. You can combine both parameters to rewrite AMP runtime URLs
* to versioned URLs on a different origin.
* * `rewriteDynamicComponents`: optionally disable rewriting of
* [dynamically generated components](https://github.com/ampproject/amphtml/blob/master/spec/amp-cache-guidelines.md#guidelines-adding-a-new-cache-to-the-amp-ecosystem).
* For example: `https://cdn.ampproject.org/v0/amp-geo-0.1.js` returns
* different content depending on the country from which the request was made.
*
* All parameters are optional. If no option is provided, runtime URLs won't be
* re-written. You can combine `ampRuntimeVersion` and `ampUrlPrefix` to rewrite
* AMP runtime URLs to versioned URLs on a different origin.
*
* This transformer also adds a preload header for the AMP runtime (v0.js) to trigger HTTP/2
* push for CDNs (see https://www.w3.org/TR/preload/#server-push-(http/2)).
Expand All @@ -52,13 +61,22 @@ class RewriteAmpUrls {
if (params.ampRuntimeVersion && !params.ampUrlPrefix) {
ampUrlPrefix = appendRuntimeVersion(ampUrlPrefix, params.ampRuntimeVersion);
}
let dynamicAmpUrlPrefix = ampUrlPrefix;
if (params.rewriteDynamicComponents === false) {
dynamicAmpUrlPrefix = AMP_CACHE_HOST;
if (params.ampRuntimeVersion) {
dynamicAmpUrlPrefix = appendRuntimeVersion(dynamicAmpUrlPrefix, params.ampRuntimeVersion);
}
}

let node = head.firstChild;
let referenceNode = findMetaViewport(head);

while (node) {
if (node.tagName === 'script' && this._usesAmpCacheUrl(node.attribs.src)) {
node.attribs.src = this._replaceUrl(node.attribs.src, ampUrlPrefix);
const isDynamicComponent = this._isDynamicComponent(node);
node.attribs.src = this._replaceUrl(node.attribs.src,
isDynamicComponent ? dynamicAmpUrlPrefix : ampUrlPrefix);
referenceNode = this._addPreload(tree, head, referenceNode, node.attribs.src, 'script');
} else if (node.tagName === 'link' &&
node.attribs.rel === 'stylesheet' &&
Expand Down Expand Up @@ -94,6 +112,16 @@ class RewriteAmpUrls {
parent.insertAfter(preload, node);
return preload;
}

_isDynamicComponent(script) {
if (!script || !script.attribs || script.tagName !== 'script') {
return false;
}

return Object.keys(AMP_DYNAMIC_COMPONENTS).some((type) => {
return script.attribs[type] && AMP_DYNAMIC_COMPONENTS[type].includes(script.attribs[type]);
});
}
}

module.exports = RewriteAmpUrls;
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<!doctype html>
<html >
<head>
<link rel="preload" href="/amp/v0.js" as="script">
<link rel="preload" href="/amp/v0.css" as="style">
<script async custom-element=amp-experiment src=/amp/v0/amp-experiment-0.1.js></script>
<script async custom-element=amp-geo src=https://cdn.ampproject.org/rtv/001515617716922/v0/amp-geo-0.1.js></script>
<script async src="/amp/v0.js"></script>
<link rel=stylesheet href=/amp/v0.css>
<link href=https://fonts.googleapis.com/css?foobar rel=stylesheet type=text/css>
<link href=https://example.com/favicon.ico rel=icon>
</head>
<body></body>
</html>
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<!--
{
"ampUrlPrefix": "/amp",
"ampRuntimeVersion": "001515617716922",
"rewriteDynamicComponents": false
}
-->
<!doctype html>
<html >
<head>
<script async custom-element=amp-experiment src=https://cdn.ampproject.org/v0/amp-experiment-0.1.js></script>
<script async custom-element=amp-geo src=https://cdn.ampproject.org/v0/amp-geo-0.1.js></script>
<script async src="https://cdn.ampproject.org/v0.js"></script>
<link rel=stylesheet href=https://cdn.ampproject.org/v0.css>
<link href=https://fonts.googleapis.com/css?foobar rel=stylesheet type=text/css>
<link href=https://example.com/favicon.ico rel=icon>
</head>
<body></body>
</html>
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<!doctype html>
<html >
<head>
<link rel="preload" href="/amp/v0.js" as="script">
<link rel="preload" href="/amp/v0.css" as="style">
<script async custom-element=amp-experiment src=/amp/v0/amp-experiment-0.1.js></script>
<script async custom-element=amp-geo src=https://cdn.ampproject.org/v0/amp-geo-0.1.js></script>
<script async src="/amp/v0.js"></script>
<link rel=stylesheet href=/amp/v0.css>
<link href=https://fonts.googleapis.com/css?foobar rel=stylesheet type=text/css>
<link href=https://example.com/favicon.ico rel=icon>
</head>
<body></body>
</html>
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<!--
{
"ampUrlPrefix": "/amp",
"rewriteDynamicComponents": false
}
-->
<!doctype html>
<html >
<head>
<script async custom-element=amp-experiment src=https://cdn.ampproject.org/v0/amp-experiment-0.1.js></script>
<script async custom-element=amp-geo src=https://cdn.ampproject.org/v0/amp-geo-0.1.js></script>
<script async src="https://cdn.ampproject.org/v0.js"></script>
<link rel=stylesheet href=https://cdn.ampproject.org/v0.css>
<link href=https://fonts.googleapis.com/css?foobar rel=stylesheet type=text/css>
<link href=https://example.com/favicon.ico rel=icon>
</head>
<body></body>
</html>

0 comments on commit 81e525d

Please sign in to comment.