diff --git a/packages/optimizer/lib/AmpConstants.js b/packages/optimizer/lib/AmpConstants.js index e8fd740bc..b8de0b61d 100644 --- a/packages/optimizer/lib/AmpConstants.js +++ b/packages/optimizer/lib/AmpConstants.js @@ -21,7 +21,8 @@ const AMP_STORY_DVH_POLYFILL_ATTR = 'amp-story-dvh-polyfill'; module.exports = { AMP_TAGS: ['amp', '⚡', '⚡4ads', 'amp4ads', '⚡4email', 'amp4email'], - AMP_CACHE_HOST: 'https://cdn.ampproject.org', + AMP_CACHE_HOSTS: ['https://cdn.ampproject.org', 'https://ampjs.org'], + DEFAULT_AMP_CACHE_HOST: 'https://cdn.ampproject.org', AMP_VALIDATION_RULES_URL: 'https://cdn.ampproject.org/v0/validator.json', AMP_FORMATS: ['AMP', 'AMP4EMAIL', 'AMP4ADS'], AMP_RUNTIME_CSS_PATH: '/v0.css', diff --git a/packages/optimizer/lib/RuntimeHostHelper.js b/packages/optimizer/lib/RuntimeHostHelper.js index 75e6998bc..96c18d4b9 100644 --- a/packages/optimizer/lib/RuntimeHostHelper.js +++ b/packages/optimizer/lib/RuntimeHostHelper.js @@ -15,10 +15,10 @@ */ 'use strict'; -const {AMP_CACHE_HOST, appendRuntimeVersion} = require('./AmpConstants.js'); +const {DEFAULT_AMP_CACHE_HOST, appendRuntimeVersion} = require('./AmpConstants.js'); function calculateHost({ - ampUrlPrefix = AMP_CACHE_HOST, + ampUrlPrefix = DEFAULT_AMP_CACHE_HOST, ampRuntimeVersion, lts = false, rtv = false, diff --git a/packages/optimizer/lib/fetchRuntimeParameters.js b/packages/optimizer/lib/fetchRuntimeParameters.js index 770fecbbf..b99b8c1ff 100644 --- a/packages/optimizer/lib/fetchRuntimeParameters.js +++ b/packages/optimizer/lib/fetchRuntimeParameters.js @@ -29,10 +29,11 @@ try { } const { - AMP_CACHE_HOST, + AMP_CACHE_HOSTS, AMP_RUNTIME_CSS_PATH, AMP_VALIDATION_RULES_URL, appendRuntimeVersion, + DEFAULT_AMP_CACHE_HOST, } = require('./AmpConstants.js'); const KEY_VALIDATOR_RULES = 'validator-rules'; @@ -214,12 +215,12 @@ async function fetchLatestRuntimeData_({config, ampUrlPrefix, lts}, versionKey = version: await config.runtimeVersion.currentVersion({ampUrlPrefix, lts}), maxAge: MaxAge.create(AMP_RUNTIME_MAX_AGE).toObject(), }; - if (!ampRuntimeData.version && ampUrlPrefix && ampUrlPrefix !== AMP_CACHE_HOST) { + if (!ampRuntimeData.version && ampUrlPrefix && !AMP_CACHE_HOSTS.includes(ampUrlPrefix)) { config.log.error( - `Could not download runtime version from ${ampUrlPrefix}. Falling back to ${AMP_CACHE_HOST}` + `Could not download runtime version from ${ampUrlPrefix}. Falling back to ${DEFAULT_AMP_CACHE_HOST}` ); ampRuntimeData = await fetchLatestRuntimeData_( - {config, ampUrlPrefix: AMP_CACHE_HOST, lts}, + {config, ampUrlPrefix: DEFAULT_AMP_CACHE_HOST, lts}, versionKey ); } else if (!ampRuntimeData.version) { @@ -240,15 +241,16 @@ async function fetchLatestRuntimeData_({config, ampUrlPrefix, lts}, versionKey = async function fetchAmpRuntimeStyles_(config, ampUrlPrefix, ampRuntimeVersion) { if (ampUrlPrefix && !isAbsoluteUrl_(ampUrlPrefix)) { config.log.warn( - `AMP runtime styles cannot be fetched from relative ampUrlPrefix, please use the 'ampRuntimeStyles' parameter to provide the correct runtime style. Falling back to latest v0.css on ${AMP_CACHE_HOST}` + `AMP runtime styles cannot be fetched from relative ampUrlPrefix, please use the 'ampRuntimeStyles' parameter to provide the correct runtime style. Falling back to latest v0.css on ${DEFAULT_AMP_CACHE_HOST}` ); // Gracefully fallback to latest runtime version - ampUrlPrefix = AMP_CACHE_HOST; + ampUrlPrefix = DEFAULT_AMP_CACHE_HOST; ampRuntimeVersion = ampRuntimeVersion || (await config.runtimeVersion.currentVersion()); } // Construct the AMP runtime CSS download URL, the default is: https://cdn.ampproject.org/rtv/${ampRuntimeVersion}/v0.css const runtimeCssUrl = - appendRuntimeVersion(ampUrlPrefix || AMP_CACHE_HOST, ampRuntimeVersion) + AMP_RUNTIME_CSS_PATH; + appendRuntimeVersion(ampUrlPrefix || DEFAULT_AMP_CACHE_HOST, ampRuntimeVersion) + + AMP_RUNTIME_CSS_PATH; // Fetch runtime styles const styles = await downloadAmpRuntimeStyles_(config, runtimeCssUrl); if (!styles) { @@ -257,7 +259,7 @@ async function fetchAmpRuntimeStyles_(config, ampUrlPrefix, ampRuntimeVersion) { // Try to download latest from cdn.ampproject.org instead return fetchAmpRuntimeStyles_( config, - AMP_CACHE_HOST, + DEFAULT_AMP_CACHE_HOST, await config.runtimeVersion.currentVersion() ); } else { diff --git a/packages/optimizer/lib/transformers/AddMandatoryTags.js b/packages/optimizer/lib/transformers/AddMandatoryTags.js index 372115030..e493f3441 100644 --- a/packages/optimizer/lib/transformers/AddMandatoryTags.js +++ b/packages/optimizer/lib/transformers/AddMandatoryTags.js @@ -24,117 +24,11 @@ const { createElement, firstChildByTag, } = require('../NodeUtils'); -const {AMP_FORMATS, AMP_TAGS} = require('../AmpConstants'); +const {AMP_FORMATS, AMP_TAGS, DEFAULT_AMP_CACHE_HOST} = require('../AmpConstants'); const DEFAULT_FORMAT = 'AMP'; const AUTO_GENERATED_MARKER = 'data-auto'; -const BOILERPLATES = { - AMP: [ - { - matcher: { - tagName: 'meta', - attribs: { - charset: 'utf-8', - }, - }, - node: { - tagName: 'meta', - attribs: { - charset: 'utf-8', - }, - }, - }, - { - matcher: { - tagName: 'meta', - attribs: { - name: 'viewport', - }, - }, - node: { - tagName: 'meta', - attribs: { - name: 'viewport', - content: 'width=device-width,minimum-scale=1,initial-scale=1', - }, - }, - }, - { - matcher: { - tagName: 'noscript', - }, - node: { - tagName: 'noscript', - children: [ - { - tagName: 'style', - attribs: { - 'amp-boilerplate': '', - }, - // eslint-disable-next-line max-len - text: - 'body{-webkit-animation:none;-moz-animation:none;-ms-animation:none;animation:none}', - }, - ], - }, - }, - { - matcher: { - tagName: 'style', - attribs: { - 'amp-boilerplate': '', - }, - }, - node: { - tagName: 'style', - attribs: { - 'amp-boilerplate': '', - }, - // eslint-disable-next-line max-len - text: - '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}}', - }, - }, - { - matcher: { - tagName: 'script', - attribs: { - src: /^https:\/\/.+\/v0\.js$/, - }, - }, - node: { - tagName: 'script', - attribs: { - async: '', - src: 'https://cdn.ampproject.org/v0.js', - }, - }, - }, - { - matcher: { - tagName: 'link', - attribs: { - rel: 'canonical', - }, - }, - node: { - tagName: 'link', - attribs: { - rel: 'canonical', - href: (params, log) => { - if (!params.canonical) { - log.warn('No canonical param is given. Setting canonical href to `.`'); - params.canonical = '.'; - } - return params.canonical; - }, - }, - }, - }, - ], -}; - /** * AddMandatoryTags - this transformer will automatically add all missing tags required by a valid AMP document. * @@ -164,8 +58,114 @@ class AddMandatoryTags { return; } + const boilerplates = { + AMP: [ + { + matcher: { + tagName: 'meta', + attribs: { + charset: 'utf-8', + }, + }, + node: { + tagName: 'meta', + attribs: { + charset: 'utf-8', + }, + }, + }, + { + matcher: { + tagName: 'meta', + attribs: { + name: 'viewport', + }, + }, + node: { + tagName: 'meta', + attribs: { + name: 'viewport', + content: 'width=device-width,minimum-scale=1,initial-scale=1', + }, + }, + }, + { + matcher: { + tagName: 'noscript', + }, + node: { + tagName: 'noscript', + children: [ + { + tagName: 'style', + attribs: { + 'amp-boilerplate': '', + }, + // eslint-disable-next-line max-len + text: + 'body{-webkit-animation:none;-moz-animation:none;-ms-animation:none;animation:none}', + }, + ], + }, + }, + { + matcher: { + tagName: 'style', + attribs: { + 'amp-boilerplate': '', + }, + }, + node: { + tagName: 'style', + attribs: { + 'amp-boilerplate': '', + }, + // eslint-disable-next-line max-len + text: + '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}}', + }, + }, + { + matcher: { + tagName: 'script', + attribs: { + src: /^https:\/\/.+\/v0\.js$/, + }, + }, + node: { + tagName: 'script', + attribs: { + async: '', + src: (params.ampUrlPrefix || DEFAULT_AMP_CACHE_HOST) + '/v0.js', + }, + }, + }, + { + matcher: { + tagName: 'link', + attribs: { + rel: 'canonical', + }, + }, + node: { + tagName: 'link', + attribs: { + rel: 'canonical', + href: (params, log) => { + if (!params.canonical) { + log.warn('No canonical param is given. Setting canonical href to `.`'); + params.canonical = '.'; + } + return params.canonical; + }, + }, + }, + }, + ], + }; + // Only supports AMP for websites - const boilerplateSpec = BOILERPLATES[this.format]; + const boilerplateSpec = boilerplates[this.format]; if (!boilerplateSpec) { this.log_.info('Unsupported AMP format', this.format); return; diff --git a/packages/optimizer/lib/transformers/AmpStoryCssTransformer.js b/packages/optimizer/lib/transformers/AmpStoryCssTransformer.js index c2c51d4a6..757f9e2fc 100644 --- a/packages/optimizer/lib/transformers/AmpStoryCssTransformer.js +++ b/packages/optimizer/lib/transformers/AmpStoryCssTransformer.js @@ -13,7 +13,7 @@ const { firstChildByTag, appendChild, } = require('../NodeUtils'); -const {AMP_CACHE_HOST} = require('../AmpConstants.js'); +const {DEFAULT_AMP_CACHE_HOST} = require('../AmpConstants.js'); // This string should not be modified, even slightly. This string is strictly // checked by the validator. @@ -139,7 +139,7 @@ function appendAmpStoryCssLink(head) { 'amp-extension': 'amp-story', // We rely on the `RewriteAmpUrls` transformer to modify this to // the correct LTS or correct rtv path. - 'href': `${AMP_CACHE_HOST}/v0/amp-story-1.0.css`, + 'href': `${DEFAULT_AMP_CACHE_HOST}/v0/amp-story-1.0.css`, }); appendChild(head, ampStoryCssLink); } diff --git a/packages/optimizer/lib/transformers/AutoExtensionImporter.js b/packages/optimizer/lib/transformers/AutoExtensionImporter.js index 30805829e..84d4a4228 100644 --- a/packages/optimizer/lib/transformers/AutoExtensionImporter.js +++ b/packages/optimizer/lib/transformers/AutoExtensionImporter.js @@ -23,7 +23,7 @@ const { hasAttribute, } = require('../NodeUtils'); const {findMetaViewport, findRuntimeScript} = require('../HtmlDomHelper'); -const {AMP_FORMATS, AMP_CACHE_HOST} = require('../AmpConstants'); +const {AMP_FORMATS, DEFAULT_AMP_CACHE_HOST} = require('../AmpConstants'); const BIND_SHORT_FORM_PREFIX = 'bind'; const AMP_BIND_DATA_ATTRIBUTE_PREFIX = 'data-amp-bind-'; @@ -188,7 +188,7 @@ class AutoExtensionImporter { } // Use cdn.ampproject.org as default, RewriteUrlTransformer will change this in case of self-hosting - const host = AMP_CACHE_HOST; + const host = DEFAULT_AMP_CACHE_HOST; for (const extensionName of extensionsToImport) { if (existingImports.has(extensionName)) { continue; diff --git a/packages/optimizer/lib/transformers/ReorderHeadTransformer.js b/packages/optimizer/lib/transformers/ReorderHeadTransformer.js index 41be15925..3a5754815 100644 --- a/packages/optimizer/lib/transformers/ReorderHeadTransformer.js +++ b/packages/optimizer/lib/transformers/ReorderHeadTransformer.js @@ -191,7 +191,7 @@ class HeadNodes { rel === 'prefetch' || rel === 'dns-prefetch' || rel === 'preconnect' || - rel == 'modulepreload' + rel === 'modulepreload' ) { this._resourceHintLinks.push(node); return; diff --git a/packages/optimizer/lib/transformers/RewriteAmpUrls.js b/packages/optimizer/lib/transformers/RewriteAmpUrls.js index 8b1109571..debfef6bd 100644 --- a/packages/optimizer/lib/transformers/RewriteAmpUrls.js +++ b/packages/optimizer/lib/transformers/RewriteAmpUrls.js @@ -23,7 +23,7 @@ const { insertBefore, remove, } = require('../NodeUtils'); -const {AMP_CACHE_HOST} = require('../AmpConstants.js'); +const {AMP_CACHE_HOSTS} = require('../AmpConstants.js'); const {findMetaViewport} = require('../HtmlDomHelper'); const {calculateHost} = require('../RuntimeHostHelper'); @@ -141,13 +141,15 @@ class RewriteAmpUrls { _usesAmpCacheUrl(url) { if (!url) { - return; + return false; } - return url.startsWith(AMP_CACHE_HOST); + // check if url starts with one of string array + return AMP_CACHE_HOSTS.some((host) => url.startsWith(host)); } _replaceUrl(url, host) { - return host + url.substring(AMP_CACHE_HOST.length); + const existingHost = AMP_CACHE_HOSTS.find((ampCacheHost) => url.startsWith(ampCacheHost)); + return host + url.substring(existingHost.length); } _addEsm(scriptNode, preloadEnabled) { diff --git a/packages/optimizer/spec/helpers/validatorInstance.js b/packages/optimizer/spec/helpers/validatorInstance.js index e93fa05af..b4a797c77 100644 --- a/packages/optimizer/spec/helpers/validatorInstance.js +++ b/packages/optimizer/spec/helpers/validatorInstance.js @@ -6,6 +6,7 @@ let instance = null; module.exports = { get: () => { if (!instance) { + console.error('Validator instance created: ' + path.join(__dirname, 'validator.js')); instance = validator.getInstance(path.join(__dirname, 'validator.js')); } return instance; diff --git a/packages/optimizer/spec/transformers/valid/AddMandatoryTags/keep-existing-tags-ampjs/expected_output.html b/packages/optimizer/spec/transformers/valid/AddMandatoryTags/keep-existing-tags-ampjs/expected_output.html new file mode 100644 index 000000000..168f7e570 --- /dev/null +++ b/packages/optimizer/spec/transformers/valid/AddMandatoryTags/keep-existing-tags-ampjs/expected_output.html @@ -0,0 +1,13 @@ + + + + My AMP Page + + + + + + +

hello world

+ + \ No newline at end of file diff --git a/packages/optimizer/spec/transformers/valid/AddMandatoryTags/keep-existing-tags-ampjs/input.html b/packages/optimizer/spec/transformers/valid/AddMandatoryTags/keep-existing-tags-ampjs/input.html new file mode 100644 index 000000000..801dd6079 --- /dev/null +++ b/packages/optimizer/spec/transformers/valid/AddMandatoryTags/keep-existing-tags-ampjs/input.html @@ -0,0 +1,10 @@ + + + My AMP Page + + + + +

hello world

+ + diff --git a/packages/optimizer/spec/transformers/valid/RewriteAmpUrls/adds_lts_ampjs/expected_output.html b/packages/optimizer/spec/transformers/valid/RewriteAmpUrls/adds_lts_ampjs/expected_output.html new file mode 100644 index 000000000..aa570f4cf --- /dev/null +++ b/packages/optimizer/spec/transformers/valid/RewriteAmpUrls/adds_lts_ampjs/expected_output.html @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/packages/optimizer/spec/transformers/valid/RewriteAmpUrls/adds_lts_ampjs/input.html b/packages/optimizer/spec/transformers/valid/RewriteAmpUrls/adds_lts_ampjs/input.html new file mode 100644 index 000000000..3e5da0cf2 --- /dev/null +++ b/packages/optimizer/spec/transformers/valid/RewriteAmpUrls/adds_lts_ampjs/input.html @@ -0,0 +1,16 @@ + + + + + + + + + + + + diff --git a/packages/optimizer/spec/transformers/valid/RewriteAmpUrls/adds_preloads_ampjs/expected_output.html b/packages/optimizer/spec/transformers/valid/RewriteAmpUrls/adds_preloads_ampjs/expected_output.html new file mode 100644 index 000000000..4a160fd16 --- /dev/null +++ b/packages/optimizer/spec/transformers/valid/RewriteAmpUrls/adds_preloads_ampjs/expected_output.html @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/packages/optimizer/spec/transformers/valid/RewriteAmpUrls/adds_preloads_ampjs/input.html b/packages/optimizer/spec/transformers/valid/RewriteAmpUrls/adds_preloads_ampjs/input.html new file mode 100644 index 000000000..cf97424d6 --- /dev/null +++ b/packages/optimizer/spec/transformers/valid/RewriteAmpUrls/adds_preloads_ampjs/input.html @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/packages/runtime-version/lib/RuntimeVersion.js b/packages/runtime-version/lib/RuntimeVersion.js index 3084e7b4b..4e514e6f1 100644 --- a/packages/runtime-version/lib/RuntimeVersion.js +++ b/packages/runtime-version/lib/RuntimeVersion.js @@ -15,9 +15,10 @@ */ 'use strict'; +const {DEFAULT_AMP_CACHE_HOST} = require('../../optimizer/lib/AmpConstants'); + const log = require('@ampproject/toolbox-core').log.tag('AMP Runtime Version'); -const AMP_CACHE_HOST = 'https://cdn.ampproject.org'; const RUNTIME_METADATA_PATH = '/rtv/metadata'; const VERSION_TXT_PATH = '/version.txt'; @@ -96,7 +97,9 @@ class RuntimeVersion { releaseType = ReleaseType.lts; } - const host = options.ampUrlPrefix ? options.ampUrlPrefix.replace(/\/$/, '') : AMP_CACHE_HOST; + const host = options.ampUrlPrefix + ? options.ampUrlPrefix.replace(/\/$/, '') + : DEFAULT_AMP_CACHE_HOST; let rtv = await this.getVersionFromRuntimeMetadata_(host, releaseType); if (!rtv && releaseType === ReleaseType.prod) {