Refactored of passing frame attribute/context information#6498
Refactored of passing frame attribute/context information#6498lannka merged 22 commits intoampproject:masterfrom google:frizz-postmessage-api-name-refactor
Conversation
|
apologies for the duplicate commit messages, not exactly sure what happened there. |
lannka
left a comment
There was a problem hiding this comment.
In case you are not aware: what's our plan for the master selection code?
src/3p-frame.js
Outdated
| }; | ||
| iframe.setAttribute( | ||
| 'data-amp-3p-sentinel', attributes._context.amp3pSentinel); | ||
| 'data-amp-3p-sentinel', attributes._context.sentinel); |
There was a problem hiding this comment.
should we just generate the sentinel here, if this is the only place uses the sentinel.
There was a problem hiding this comment.
no, it needs to be within the _context object because that is where it gets pulled from by the ampcontext library. the data-amp-3p-sentinel attribute gets deprecated by #6506
| const host = parseUrl(baseUrl).hostname; | ||
| // Pass ad attributes to iframe via the fragment. | ||
| const src = baseUrl + '#' + JSON.stringify(attributes); | ||
| const name = host + '_' + attributes.type + '_' + count[attributes.type]++; |
There was a problem hiding this comment.
was the name attribute used anywhere?
There was a problem hiding this comment.
we decided to make a breaking change here @keithwrightbos
There was a problem hiding this comment.
I was wondering if this is not used anywhere, can we just remove them?
There was a problem hiding this comment.
I believe it is used, at least there are tests that check for it
test/functional/test-impression.js
Outdated
| import * as sinon from 'sinon'; | ||
|
|
||
| describe('impression', () => { | ||
| describe('test-impression', () => { |
3p/integration.js
Outdated
| window.context.reportRenderedEntityIdentifier = | ||
| reportRenderedEntityIdentifier; | ||
| window.context.computeInMasterFrame = computeInMasterFrame; | ||
| window.context.addContextToIframe = getAddContextToIframe(iframeName); |
There was a problem hiding this comment.
we normally use bind to create a function:
window.context.addContextToIframe = addNameToIframe.bind(null, iframeName)
function addNameToIframe(name, iframe) {
iframe.name = name;
}
3p/integration.js
Outdated
| data = JSON.parse(window.name).attributes; | ||
| window.context = data._context; | ||
| } catch (err) { | ||
| window.context = {}; |
3p/integration.js
Outdated
| const iframeName = window.name; | ||
| let data; | ||
| try { | ||
| data = JSON.parse(window.name).attributes; |
src/3p-frame.js
Outdated
| // Pass ad attributes to iframe via the fragment. | ||
| const src = baseUrl + '#' + JSON.stringify(attributes); | ||
| const name = host + '_' + attributes.type + '_' + count[attributes.type]++; | ||
| const src = baseUrl; |
src/3p-frame.js
Outdated
| domFingerprint: domFingerprint(element), | ||
| startTime, | ||
| }; | ||
| attributes.ampcontextVersion = (getMode().localDev ? 'LOCAL' : |
There was a problem hiding this comment.
should not be in attributes?
There was a problem hiding this comment.
what do you mean? i.e. should it be in the _context?
There was a problem hiding this comment.
depend on where do you need this? it's not from element attribute, and you don't want them to be shown as attribute, right?
There was a problem hiding this comment.
I'll move this as part of the #6506 as I am already making the name building helper function there
There was a problem hiding this comment.
seems this line can be added in your next PR, if you plan to move it eventually
3p/integration.js
Outdated
| const iframeName = window.name; | ||
| let data; | ||
| try { | ||
| data = JSON.parse(window.name).attributes; |
There was a problem hiding this comment.
probably it's a good time to revisit the data structure, it's quite confusing now.
We can change it from
{
...
attributes: {
_context: {}
}
}
to
{
attributes: {},
context: {},
}
There was a problem hiding this comment.
in case this comment was buried.
There was a problem hiding this comment.
I can fix this, but it would be a lot easier for me to do it in #6506 if that's alright with you. I need to make a helper function that constructs the whole name object anyways, and that's the PR where I'm going to put it
3p/integration.js
Outdated
| reportRenderedEntityIdentifier; | ||
| window.context.computeInMasterFrame = computeInMasterFrame; | ||
| window.context.addContextToIframe = getAddContextToIframe(iframeName); | ||
| window.context.addContextToIframe = addNameToIframe.bind(null, iframeName); |
There was a problem hiding this comment.
This is bound to the iframe param now, not the name.
3p/integration.js
Outdated
| } | ||
|
|
||
| /** | ||
| * Adds the serialized ad attributes to an iframe's name attribute. |
src/3p-frame.js
Outdated
| canary: !!(parentWindow.AMP_CONFIG && parentWindow.AMP_CONFIG.canary), | ||
| hidden: !viewer.isVisible(), | ||
| amp3pSentinel: generateSentinel(parentWindow), | ||
| sentinel: generateSentinel(parentWindow), |
There was a problem hiding this comment.
Is this a breaking change?
There was a problem hiding this comment.
I'll double check, but I'm fairly sure that anything this change may break would:
A. Be fixed with the sentinel refactor pr #6506
B. Would not be used by any publishers/advertisers/creatives (as the sentinel here is for the postMessage api that the AmpContext library uses, which is not being used by anyone yet).
| let data; | ||
| try { | ||
| data = JSON.parse(iframeName).attributes; | ||
| window.context = data._context; |
There was a problem hiding this comment.
This is now at data.attributes.context, per https://github.com/ampproject/amphtml/pull/6498/files#diff-34e84f9cf5e8134d86bf1fc893ab293aR128.
There was a problem hiding this comment.
data is the attributes off of the name object, so window.context should get data._context, unless I'm misunderstanding what you mean
There was a problem hiding this comment.
Ohhh! I missed the .attributes on the line above. Ignore this comment.
|
|
||
| iframe.src = src; | ||
| iframe.src = baseUrl; | ||
| iframe.name = name; |
There was a problem hiding this comment.
Need to decodeURIComponent?
There was a problem hiding this comment.
No, it's just the base url
src/3p-frame.js
Outdated
| const name = JSON.stringify({ | ||
| host, | ||
| type: attributes.type, | ||
| count: count[attributes.type], |
There was a problem hiding this comment.
Need to increment this value (this was a hard fought bug).
There was a problem hiding this comment.
@jridgewell do you know what is the counter used for? I don't see it documented anywhere.
There was a problem hiding this comment.
The counter is to ensure the iframe's window is not cached. #2955
There was a problem hiding this comment.
Ah, good to know. @bradfrizzell could you add a link in the code?
| let data; | ||
| try { | ||
| data = JSON.parse(iframeName).attributes; | ||
| window.context = data._context; |
There was a problem hiding this comment.
Ohhh! I missed the .attributes on the line above. Ignore this comment.
|
ptal |
|
Some of my comments was buried. For example: #6498 (comment) |
|
Sorry about that, I addressed them. Changing the whole data structure of the attributes would be easier for me to fix in #6506 if that's alright. If you think it must be done as part of this PR I can do that |
lannka
left a comment
There was a problem hiding this comment.
Sounds good to me to do them later. Please add a TODO.
I just had one more question about the counter. Not sure if @jridgewell can answer.
Otherwise this PR looks good.
src/3p-frame.js
Outdated
| const name = JSON.stringify({ | ||
| host, | ||
| type: attributes.type, | ||
| count: count[attributes.type], |
There was a problem hiding this comment.
@jridgewell do you know what is the counter used for? I don't see it documented anywhere.
|
Ah, there's another previous comment not addressed yet (about the master selection code): |
|
ptal @lannka |
3p/integration.js
Outdated
| * @param {string} name A URIencoded JSON object of context | ||
| * that needs to be attached to an iframe. | ||
| * @param {Element} iframe | ||
| */ |
There was a problem hiding this comment.
hmm, seems now it's only used in one place, shall we just inline the function?
| const data = parseFragment(location.hash); | ||
| window.context = data._context; | ||
|
|
||
| const iframeName = window.name; |
There was a problem hiding this comment.
please explain why we cache this value.
There was a problem hiding this comment.
I suppose we don't need to. fixed
There was a problem hiding this comment.
i actually meant to add a comment why we cache this value.
Otherwise, you might want to move master selection code below all the code that read window.name.
There was a problem hiding this comment.
d'oh. undid and added comment
src/3p-frame.js
Outdated
| // This name attribute may be overwritten if this frame is chosen to | ||
| // be the master frame. That is ok, as we will read the name off | ||
| // for our uses before that would occur. | ||
| // @see https://github.com/ampproject/amphtml/blob/master/3p/integration.js#L315 |
There was a problem hiding this comment.
nit: remove the line number as it might soon be irrelevant
|
ptal @lannka |
3p/integration.js
Outdated
| * @param {string} name A URIencoded JSON object of context | ||
| * that needs to be attached to an iframe. | ||
| * @param {Element} iframe | ||
| */ |
There was a problem hiding this comment.
sorry, by inline i meant to have
window.context.addContextToIframe = (iframe, name) => {
iframe.name = name;
}
There was a problem hiding this comment.
I don't think doing it like that will work, though. we need the name to get captured in a closure, which is why I'm using bind above. I can move it all together and use bind up there but then it ends up getting a little less clean than just having them separated (in my opinion)
There was a problem hiding this comment.
oh sorry, i meant
window.context.addContextToIframe = iframe => {
iframe.name = iframeName;
}
| const data = parseFragment(location.hash); | ||
| window.context = data._context; | ||
|
|
||
| const iframeName = window.name; |
There was a problem hiding this comment.
i actually meant to add a comment why we cache this value.
Otherwise, you might want to move master selection code below all the code that read window.name.
|
ptal |
src/3p-frame.js
Outdated
| // be the master frame. That is ok, as we will read the name off | ||
| // for our uses before that would occur. | ||
| // @see https://github.com/ampproject/amphtml/blob/master/3p/integration.js | ||
| const name = JSON.stringify({ |
There was a problem hiding this comment.
as discussed, we'll introduce an experiment flag to protect this behavior change (URL fragment => name attribute). So that we will have a easy way to recover if anything happen during releasing.
|
@lannka I added an experiment flag. Please take a look, let me know if I did this correctly. |
3p/messaging.js
Outdated
| const object = opt_object || {}; | ||
| object.type = type; | ||
| object.sentinel = window.context.amp3pSentinel; | ||
| object.sentinel = window.context.sentinel; |
There was a problem hiding this comment.
could you make this naming change in a separate PR? In case this renaming break anything, we can easily revert a smaller PR.
3p/integration.js
Outdated
| /** | ||
| * If true, then in experiment where the passing of context metadata | ||
| * has been moved from the iframe src hash to the iframe name attribute. | ||
| */ |
There was a problem hiding this comment.
the flag value is not available inside iframe. (I'm working on it right now #6684 ). To not be blocked by me, I suggest you read from fragment first, and then from name.
src/3p-frame.js
Outdated
| * If true, then in experiment where the passing of context metadata | ||
| * has been moved from the iframe src hash to the iframe name attribute. | ||
| */ | ||
| const nameExpOn = isExperimentOn(self, 'move-context-to-name'); |
There was a problem hiding this comment.
suggested naming: '3p-iframe-context-in-name'
There was a problem hiding this comment.
ended up using 'iframeContextInName'
src/3p-frame.js
Outdated
| domFingerprint: domFingerprint(element), | ||
| startTime, | ||
| }; | ||
| attributes.ampcontextVersion = (getMode().localDev ? 'LOCAL' : |
There was a problem hiding this comment.
seems this line can be added in your next PR, if you plan to move it eventually
|
addressed your comments @lannka |
lannka
left a comment
There was a problem hiding this comment.
This looks good.
Please do thorough manual tests on your local server, to make sure no new error messages show up in the browser console. You will want to specifically pay attention to :
/examples/ads.amp.max.html
/examples/facebook.amp.max.html
/examples/twitter.amp.max.html
/examples/reddit.amp.max.html
tools/experiments/experiments.js
Outdated
| Spec: 'https://github.com/ampproject/amphtml/issues/3813', | ||
| }, | ||
| { | ||
| id: 'move-context-to-name', |
There was a problem hiding this comment.
Change this move-context-to-name to 3p-frame-context-in-name?
| id: 'move-context-to-name', | ||
| name: 'Move passing context metadata from url hash to name attribute', | ||
| Spec: '', | ||
| }, |
There was a problem hiding this comment.
please create a cleanupIssue as well
3p/integration.js
Outdated
| // Need to cache iframeName as it will be potentially overwritten by | ||
| // masterSelection, as per below. | ||
| const iframeName = window.name; | ||
| try { |
There was a problem hiding this comment.
can you move the try-catch into parseFragment? And make it return null for exception.
|
Checked those pages. they all looked good. I'm going to make sure the few console messages are all the same on the master branch |
This commit may break functionality.
|
gah sorry about that, I just stupidly rebased without thinking |
|
ptal / merge if ready |
lannka
left a comment
There was a problem hiding this comment.
Please manual test twice, one with the flag on and one with the flag off, if you haven't done so. To toggle the flag, run the following in the console:
AMP.toggleExperiment('3p-frame-context-in-name');
src/3p-frame.js
Outdated
| * If true, then in experiment where the passing of context metadata | ||
| * has been moved from the iframe src hash to the iframe name attribute. | ||
| */ | ||
| const iframeContextInName = isExperimentOn(self, 'move-context-to-name'); |
There was a problem hiding this comment.
the string literal needs to be identical to experiment ID you defined in experiments.js.
So, 'move-context-to-name' => '3p-frame-context-in-name'
There was a problem hiding this comment.
ah whoops. fixed.
tools/experiments/experiments.js
Outdated
| Spec: 'https://github.com/ampproject/amphtml/issues/3813', | ||
| }, | ||
| { | ||
| id: 'iframeContextInName', |
There was a problem hiding this comment.
to follow the convention: '3p-frame-context-in-name'
|
Ran the manual tests both ways. Everything looked fine, no new error messages/differences between experiment on/off. |
|
PTAL |
| expect(docInfo.pageViewId).to.not.be.empty; | ||
| const amp3pSentinel = iframe.getAttribute('data-amp-3p-sentinel'); | ||
| let amp3pSentinel; | ||
| if (iframeContextInName) { |
There was a problem hiding this comment.
These tests need to be done with both iframeContextInName set to false and set to true. As it is, we'll never test the true case.
…#6498) * Moved context info to name object, associated changes. This commit may break functionality. * Fixed broken tests * Fixed function binding and addressed small comments * Added dev message on context parsing failure * Fixed param order for addNameToIframe * Fixed count and fixed param order in docstring * Added todo * Added code pointer * Fixed broken tests and naming of amp3pSentinel * Fixed broken 3p-messaging tests * Fixed lint issue * Added comment to address use of name attr. for master * Removed caching of window.name * Removed line number from code pointer * Redo caching of window.name * Inlined adding name func * Added experiment flag and fixed associated tests. * Changed exp flag name; Undid change to amp3pSentinel name * Added cleanup issue to exp flag; Fixed attaching of context * Fixed jsdoc return type to eliminate presubmit issue * Fixed typo * Fixed exp id name, add additional check before reading off hash
…#6498) * Moved context info to name object, associated changes. This commit may break functionality. * Fixed broken tests * Fixed function binding and addressed small comments * Added dev message on context parsing failure * Fixed param order for addNameToIframe * Fixed count and fixed param order in docstring * Added todo * Added code pointer * Fixed broken tests and naming of amp3pSentinel * Fixed broken 3p-messaging tests * Fixed lint issue * Added comment to address use of name attr. for master * Removed caching of window.name * Removed line number from code pointer * Redo caching of window.name * Inlined adding name func * Added experiment flag and fixed associated tests. * Changed exp flag name; Undid change to amp3pSentinel name * Added cleanup issue to exp flag; Fixed attaching of context * Fixed jsdoc return type to eliminate presubmit issue * Fixed typo * Fixed exp id name, add additional check before reading off hash
…#6498) * Moved context info to name object, associated changes. This commit may break functionality. * Fixed broken tests * Fixed function binding and addressed small comments * Added dev message on context parsing failure * Fixed param order for addNameToIframe * Fixed count and fixed param order in docstring * Added todo * Added code pointer * Fixed broken tests and naming of amp3pSentinel * Fixed broken 3p-messaging tests * Fixed lint issue * Added comment to address use of name attr. for master * Removed caching of window.name * Removed line number from code pointer * Redo caching of window.name * Inlined adding name func * Added experiment flag and fixed associated tests. * Changed exp flag name; Undid change to amp3pSentinel name * Added cleanup issue to exp flag; Fixed attaching of context * Fixed jsdoc return type to eliminate presubmit issue * Fixed typo * Fixed exp id name, add additional check before reading off hash
Previously, all of the context information used to build window.context was passed on the hash of the src url. This is being switched to the name element instead of iframes. This is done to make passing the context information down to nested iframes much more simple, specifically in relation to the AmpContext library.