On Nov 27, 2013, at 8:57 AM, Dominic Cooney <domin...@google.com> wrote:

> On Tue, Nov 26, 2013 at 2:03 PM, Ryosuke Niwa <rn...@apple.com> wrote:
> Hi,
> 
> I have been having informal discussions of our earlier proposal for 
> cross-orign use cases and declarative syntax for web components, and I 
> realized there was a lot of confusion about our motivations and decision 
> decisions.  So I wanted to explain why/how we came up that proposal in this 
> email.
> 
> 
> Problem: A lot of websites embed SNS widgets, increasing the security surface 
> of embedders.  The old version of techcrunch.com, for example, had 5+ social 
> share buttons on each article.  If any one of those SNS websites got 
> compromised, then the embedder will also get compromised.
> 
> This is a valid problem. Does anyone have related use cases that might be 
> in-scope for this discussion?

Comment forms (e.g. DISQUS) is another important use case.

> What if we used iframe?
> What if we replaced each such instance with an iframe?  That would give us a 
> security boundary.
> 
> On the other hand, using an iframe for each social button is very expensive 
> because each iframe loads a document, creates its own security origin, JS 
> global object, and so forth. Initializing new script context (a.k.a. "VM", 
> "world", "isolate", etc…) for every single SNS widget on a page is quite 
> expensive.  If we had 10 articles, and each article had 5 social buttons, 
> we'll have 50 iframes, each of which needs to load megabytes of JavaScript.
> 
> iframe is also heavily restricted in terms of its ability to layout itself. 
> Comment widgets (e.g. DISQUS) for example need to stretch themselves to the 
> height of its content.
> 
> We also need a better mechanism to pass arguments and communicate with 
> cross-origin frames than postMessage.
> 
> 
> What if we made iframe lighter & used seamless iframe?
> The cost of iframe could be reduced substantially if we cached and internally 
> shared each page's JavaScript.  However, we still have to instantiate its own 
> script context, document, and window objects.
> 
> We can also use seamless iframe to address the comment widget use case.
> 
> 
> What if we let each iframe create multiple "views"?
> The problem with using an iframe for a cross-origin widget is that each 
> iframe creates its own document, window, etc… even if there are multiple 
> widgets from the same origin.  e.g. if we had a tweet button on 10 different 
> articles, we have to create its own document ,window, etc… for each tweet 
> button.
> 
> We can reduce this cost if we could share the single frame, and have it 
> render multiple "views".  Naturally, each such view will be represented as a 
> separate DOM tree.  In this model, a single iframe owns multiple DOM trees, 
> each of which will be displayed at different locations in the host document.  
> Each such a DOM tree is inaccessible from the host document, and the host 
> document is inaccessible from the iframe.
> 
> This model dramatically reduces the cost of having multiple widgets from the 
> same origin.  e.g. if we have 10 instances of widgets from 5 different social 
> networks, then we'll have only 5 iframes (each of which will have 10 "views") 
> as opposed to 50 of them.
> 
> 
> What if we provided a declarative syntax to create such a view?
> Providing a better API proved to be challenging.  We could have let page 
> authors register a custom element for each cross-origin widget but that would 
> mean that page authors have to write a lot of script just to embed some 
> third-party widgets.  We need some declarative syntax to let authors wrap an 
> iframe.
> 
> Furthermore, if we wanted to use the multiple-views-per-iframe, then we'll 
> need a mechanism to declare where each instance of such a view is placed in 
> the host document with arguments/configuration options for each view.
> 
> A custom element seemed like a natural fit for this task but the 
> prototype/element object cannot be instantiated in the host document since 
> the cross-origin widgets' script can't run in the host document and prototype 
> objects, etc… cannot be shared between the host document and the shared 
> iframes.  So we'll need some mechanism for the shared iframe to define custom 
> element names, and have the host document explicitly import them as needed.
> 
> 
> At this point, the set of features we needed looked very similar to the 
> existing custom element and shadow DOM.  Each "view" of the shared iframe was 
> basically a shadow DOM with a security boundary sitting between the host 
> element and the shadow root.  The declarative syntax for the "view" was 
> basically a declarative syntax of a custom element that happens to 
> instantiate a shadow DOM with a caveat that the shadow host is inaccessible 
> form the component, and the shadow DOM is inaccessible from the host 
> document.  It also seemed natural for such an "shared iframe" to be loaded 
> using HTML imports.
> 
> 
> You can think of our proposal as breaking iframe down into two pieces:
> Creating a new document/window
> Creating a new view
> I think decomposing the problem this way is a good step.
> 
> Re: creating a new document/window, purely in terms of *mechanics*, IFRAME 
> does this already. Is anything else required?

The problem is that iframe does both 1 and 2 but I agree that iframe already 
provides this mechanism if we set style=display:none.  But it would be really 
ugly and cumbersome if we had to import various SNS widgets with iframe with 
style set to display:none.

> Re: creating a new view, this is really interesting to me. It seems there are 
> a few different parts, I think most of these are needed for the use case 
> above; I've also noted where we might break out and "explain" some existing 
> part of the platform.
> 
> - Arranging the rendering of a DOM (sub)tree into a "view". IFRAME, 
> ShadowRoot and indeed just "rendering in general" do this.
> - Arranging the rendering of something else into a "view". Replaced elements 
> like OBJECT and IMG do this. Maybe this is just trivially "arrange the 
> rendering of a DOM containing CANVAS" though.
> - Communicating or blocking layout across the "view" boundary. Cases where 
> information flows outside-in: the viewport-document relationship; IFRAME. 
> Cases where information flows two ways: seamless IFRAME, Shadow DOM, layout 
> in general.
> - Something about laying things out/rendering outside the bounds of the 
> "view". Shadow DOM and does this (you can rel/abs/fixed position stuff 
> outside of the host element bounds.) This is a tricky one... in scope or does 
> Shadow DOM remain a special case? Would some embedders trust a component 
> enough to let them clickjack them, just not steal their cookies, etc.?

Right.  We need to add something like overflow: clip by default to prevent 
click hijacking.

> and providing a mechanism to do 2 without doing 1 (or that doing 2 multiple 
> times after doing 1 once), and making it usable with a declarative syntax.
> 
> This definitely deserves to be bullet 3--usable with declarative syntax.
> 
> To clarify that I understand--the importance of succinct declarative syntax 
> is so that the embedder doesn't end up including the "shim" script for Foo's 
> widget from foo.com, which means trusting foo.com which was the whole point! 
> Right?

Right.  Using Foo widget from foo.com should NOT involve running scripts from 
foo.com in the host document.

> It would be nice if we could solve this problem in a layered way. For 
> example, I think the "view" stuff above is a lower-level primitive, and the 
> declarative syntax should be explained in terms of (something for getting a 
> window+document--IFRAME?) plus "view" plus (extremely small alpha that 
> explains how the stuff is wired up.)

That makes sense although we haven't come up with use cases where we just want 
to use the multiple "views" cross-origin without the declarative syntax.

> I guess it is OK if the API is not declarative on the widget side? If we 
> assume the widget enjoys the isolation of an IFRAME, is performance the 
> primary motivator on this side?

Being declarative will definitely benefit the performance because preload 
scanner, etc… could detect what kind of "views" are exposed/implemented in a 
given "slave" (or "widget") document without running scripts.

Also, I'd imagine a lot of widgets would end up using templates so having to 
manually instantiate those templates would be annoyance.

> It would be nice if the widget author could get something rendered very 
> quickly.

Right.

> I think this "declarative" part of the problem breaks down this way:
> 
> - How the page author "invokes" something in the embedded component. How is 
> it named and how does the author mention the name?

So I think a custom element is the natural mechanism. e.g.

<import src="http://foo.com/widget.html"; customelements="foo-button">
<foo-button>Foo this</foo-button>

Note that we can't let the imported "slave" document define an arbitrary set of 
custom elements by default.

is=blah syntax isn't as useful/interesting here because it's unusual to use a 
cross-origin widget to replace an existing built in HTML element.

> - How does the embedding page understand that there's an "instance" of their 
> stuff contributing to the main page now?

Again, the custom element's created callback is a very nice mechanism for that.

> - How does the author configure an instance from the embedded component? 
> Presumably the button needs to know something things from its embedder, like 
> API keys, etc.


If we decided that each "view" is a custom element, then a very natural way for 
it to communicate the information is via data attributes.

- R. Niwa


Reply via email to