ampproject / ampproject/amp-toolbox
SSR: Transforming of nodes with attribute 'heights' fails, if value contains multiple media queries
- Dominant language
- HTML
- Stars
- 459
- Forks
- 242
- PR merge metrics
- No merged PRs in 30d
Description
# Issue
A node fails transforming, if it has 'heights'-attribute which contains more than one media query.
Also the attribute got **removed** on rendering, if it had failed on transforming.
## For example
```html
[...]
```
Will be rendered by amp framework, without any validation errors and with correct media queries. But on SSR with amp optimizer i get following error and the 'heights'-attribute will be removed on rendered amp page:
```javascript
AMP Optimizer ServerSideRendering Cannot remove boilerplate. Failed transforming heights="(min-width:768px) 56.25%, (min-width:576px) and (max-width:767px) 100%, 133%". Error: Invalid sizes definition '(min-width:768px) 56.25%, (min-width:576px) and (max-width:767px) 100%, 133%'
at parseSizes (/.../node_modules/@ampproject/toolbox-optimizer/lib/parseSizes.js:63:15)
at HeightsTransformer.transform (/.../node_modules/@ampproject/toolbox-optimizer/lib/transformers/ApplyCommonAttributes.js:127:21)
at ApplyCommonAttributes.apply (/.../node_modules/@ampproject/toolbox-optimizer/lib/transformers/ApplyCommonAttributes.js:207:76)
at ServerSideRendering.transform (/.../node_modules/@ampproject/toolbox-optimizer/lib/transformers/ServerSideRendering.js:105:27)
at /.../node_modules/@ampproject/toolbox-optimizer/lib/DomTransformer.js:208:61
at DomTransformer.doProfile (/.../node_modules/@ampproject/toolbox-optimizer/lib/DomTransformer.js:188:14)
at DomTransformer.transformTree (/.../node_modules/@ampproject/toolbox-optimizer/lib/DomTransformer.js:208:18)
at processTicksAndRejections (node:internal/process/task_queues:96:5)
at async DomTransformer.transform (/.../node_modules/@ampproject/toolbox-optimizer/lib/DomTransformer.js:178:7)
at async DomTransformer.transformHtml (/.../node_modules/@ampproject/toolbox-optimizer/lib/DomTransformer.js:183:12)
```
# Reason
`parseSizes(string)` throws an error for strings which has more than one ')' and trailing characters.
https://github.com/ampproject/amp-toolbox/blob/b367a2db78e1934e5c3e72727777e7c29d6a3b35/packages/optimizer/lib/parseSizes.js#L61-L64
When function `transform(node, id)` of `HeightsTransformer` gets called on nodes with 'height'-attributes, which contain a value with multiple media queries, `parseSizes(string)` will throw an error and `ApplyCommonAttributes` will catch that error and logs them.
https://github.com/ampproject/amp-toolbox/blob/b367a2db78e1934e5c3e72727777e7c29d6a3b35/packages/optimizer/lib/transformers/ApplyCommonAttributes.js#L206-L214
In function `applyToCustomStyles(head, customStyles)` of `ApplyCommonAttributes` the attributes 'heights', 'media' and 'sizes' will be removed on nodes which are in array `nodesToTransform` and my own value in 'heights'-attribute (which could not be transformed) will be removed. So the result is, the rendered amp component has no 'heights' attribute at all.
https://github.com/ampproject/amp-toolbox/blob/b367a2db78e1934e5c3e72727777e7c29d6a3b35/packages/optimizer/lib/transformers/ApplyCommonAttributes.js#L246-L250
# Solutions
## First possible solution
One possible solution would be, that nodes which could not be transformed should be removed from array `nodesToTransform`, so the values could stay if transformation fails.
This could be done with following code:
```javascript
this.nodesToTransform = this.nodesToTransform.filter(
(nodeToTransform) => nodeToTransform !== node
);
```
In context it would look like that:
```javascript
try {
nodeHasBeenTransformed = nodeHasBeenTransformed || transformer.transform(node, id);
} catch (e) {
this.log.debug(
`Cannot remove boilerplate. Failed transforming ${attribute}="${node.attribs[attribute]}".`,
e
);
this.nodesToTransform = this.nodesToTransform.filter(
(nodeToTransform) => nodeToTransform !== node
);
this.canRemoveBoilerplate = false;
}
```
## Second possible solution
An other solution would be, that function `parseSize(string)` would accept all values which amp framework does.
Maybe for the second solution it would make sense, to ignore all nodes where parseSizes(string) could not parse values, too.
# PR
I've created a PR with a fix described in first solution: https://github.com/ampproject/amp-toolbox/pull/1305
Contributor guide
Research direction
Start with packages/optimizer/lib/parseSizes.js and the HeightsTransformer and ApplyCommonAttributes paths named in the stack trace. Reproduce the AMP carousel case with multiple media queries, then inspect the existing PR #1305 and verify that a failed transformation does not remove the original heights attribute while valid values still transform correctly.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- javascript
- Domain
- backend, tooling
- Issue type
- Bug
- Difficulty
- 2/5
- Estimated time
- 1-3 hours
- Activity status
- Stale
- Clarity
- Clearly specified
- Newbie friendliness
- 25/100