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’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

🐛 compiler.js buildDoms: ensure behavior matches browser #37671

Merged
merged 5 commits into from Feb 15, 2022

Conversation

samouri
Copy link
Member

@samouri samouri commented Feb 14, 2022

summary
While testing server-side transforms, I noticed a bug in worker-dom. Specifically, setting keys of the style prop on a node does not reflect in attributes properly. Instead style.setProperty has to be used to trigger the "PropertyBackedAttribute" flow.

Separately, if we actually need JS in setStyles to dynamically figure out vendor-specific prop names, that of course won't work either.

This PR does a few things:

  1. Swaps applications of a few known style props (width, height, order) to be set with setProperty. I scanned the relevant components we plan on server-rendering and I believe this covers it.
  2. Creates a new test helper, getDeterministicOuterHTML that behaves similarly to el.outerHTML except sorts the attributes. Note that this doesn't deterministically print tokens within style= attr, but that hasn't been an issue yet and can be added later.
  3. Adds a new test to each of amp-carousel, amp-fit-text, and amp-layout to ensure WorkerDOM behavior matches browser. Also adds a similar test to the builder wrapper, which for now mostly means checking applyStaticLayout.
  4. Updates compiler-hydration.html with the results of actually running the "client render" HTML through compiler.js.

@samouri samouri changed the title compiler.js buildDoms: ensure behavior matches browser 🐛 compiler.js buildDoms: ensure behavior matches browser Feb 14, 2022
@samouri samouri self-assigned this Feb 14, 2022
@samouri samouri marked this pull request as ready for review February 14, 2022 15:32
@amp-owners-bot
Copy link

amp-owners-bot bot commented Feb 14, 2022

Hey @Jiaming-X, @jeffkaufman! These files were changed:

extensions/amp-ad-network-adsense-impl/0.1/test/test-amp-ad-network-adsense-impl.js

Hey @jridgewell! These files were changed:

src/core/dom/style.js

img.style.width = '120px';
img.style.height = '100px';
img.id = 'img-' + i;
img.style.setProperty('width', '120px');
Copy link
Contributor

Choose a reason for hiding this comment

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

In actual component code consumed by buildDom, are property assignments like el.style.width = '120px'; allowed or will it break if they don't use the setter methods?

Copy link
Member Author

Choose a reason for hiding this comment

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

it’ll break!

Copy link
Contributor

Choose a reason for hiding this comment

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

Do we have lint rules in place yet to enforce this, or any docs/guidance in the main repo?

Copy link
Member Author

@samouri samouri Feb 14, 2022

Choose a reason for hiding this comment

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

Nope! I discovered it this AM, so nothing yet.
The unit tests added in this PR will ensure we don't regress for the 3 components covered, but will sync up at standup to see if there is anything we should do in addition.

Ideally we can fix the root cause in worker-dom.
Even if its a solution we only apply server-side.

* @return {Element}
*/
function getAmpSlideScroll(
opt_hasLooping,
opt_slideCount = 5,
opt_attachToDom = true,
opt_hasAutoplay = false,
opt_autoplayLoops
opt_autoplayLoops,
doc = env.win.document
Copy link
Contributor

Choose a reason for hiding this comment

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

Can you have an arg with a default after an arg without one?
Also, you're gonna hate this, but there are now a total of 6 optional arguments...meaning...options object time perhaps?

Copy link
Member Author

Choose a reason for hiding this comment

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

I don't hate it! I actually completely agree with it!
I'd insist on this though that I'd prefer to do it in a separate PR.

Copy link
Member Author

Choose a reason for hiding this comment

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

forgot to answer the earlier q, yes you can. all a default arg means is: “if provided undefined, default to X value”

Comment on lines +1504 to +1508
/* hasLooping */ true,
/* slideCount */ undefined,
/* attachToDom */ false,
/* opt_hasAutoPlay */ undefined,
/* opt_autoplayLoops */ undefined,
Copy link
Contributor

Choose a reason for hiding this comment

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

oPtIoNs ObJeCt?

Copy link
Member Author

Choose a reason for hiding this comment

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

Happy to commit to doing this in a foLLowUp Pr.
Worried if I do it here it will distract from the primary goals

test/unit/builtins/test-amp-layout.js Outdated Show resolved Hide resolved
Comment on lines +77 to +79
const browserHtml = getDeterministicOuterHTML(browserDiv);
const workerHtml = getDeterministicOuterHTML(workerDomDiv);
expect(workerHtml).equal(browserHtml);
Copy link
Contributor

Choose a reason for hiding this comment

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

This is a super common pattern with some typo potential. Might be more useful to directly export expectDeterministicOuterHtmlEqual(worker, browser)

Copy link
Member Author

@samouri samouri Feb 14, 2022

Choose a reason for hiding this comment

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

Considered this! Don't love the pattern of making helpers that perform assertions. I know when I read it in other folk's code it always takes me longer to understand the test case.

I have a preference for under-abtracting in unit tests (keeping them DAMP). That said, especially in this case, don't have a very strong opinion. Will test it out locally and see how it seems.

Copy link
Contributor

Choose a reason for hiding this comment

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

I likewise don't feel too strongly, esp given how few components will likely do ths

testing/helpers/index.js Show resolved Hide resolved
testing/helpers/index.js Outdated Show resolved Hide resolved
testing/helpers/index.js Show resolved Hide resolved
testing/helpers/index.js Show resolved Hide resolved
@samouri samouri removed the request for review from jridgewell February 14, 2022 21:24
@samouri samouri merged commit b875822 into ampproject:main Feb 15, 2022
@samouri samouri deleted the test-compiler branch February 15, 2022 16:47

/**
* Returns the outerHTML for an element, but with lexicographically sorted attributes.
* @param {Node} node
Copy link
Member

Choose a reason for hiding this comment

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

I think this has broken type check on main. Should probably be HTMLElement. check-types is not configured to run for this file, but it probably should be.

https://app.circleci.com/pipelines/github/ampproject/amphtml/22939/workflows/e2215f87-5ad7-4f16-9a77-ac3a6c209cc4/jobs/458197?invite=true#step-116-137

Copy link
Member Author

Choose a reason for hiding this comment

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

ampprojectbot pushed a commit that referenced this pull request Feb 17, 2022
* compiler.js buildDoms: ensure behavior matches browser

* document the hack

* fix test, also update compiler-hydration with latest.

* fix more broken unit tests

* pr feedback updates

(cherry picked from commit b875822)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

5 participants