Third Party Polymer Elements - javascript

I'm trying to understand if polymer is built for a specific use-case-- third party web components.
What I need to accomplish is create a web component that takes as input from the caller's page an image url (attributes on an element is ok) and inside the polymer component it renders the image in a special way using HTML5 canvas.
To me, it seems like polymer isn't currently built for third-party usage. Reasons why:
one must have enough control over the caller's page to add platform.js to the <head>, specifically the <head>
my version of platform.js could potentially be different than the caller page's platform.js (or bare minimum i'm polluting the page with polymer's JS objs, right?)
in non-chrome browsers style and other tags are injected into <head>, possibly conflicting with the source page
one must have control over the caller's <body> tag if wanting to set options to avoid FOUC
Traditionally all my web components have been built via iframes and i'd like to modernize my approach with a view towards a "shadow-dom future."
Is there a way to use polymer in a third-party safe way? Perhaps a mashup with [lightningjs?

Polymer and Web Components are entirely structured around 3rd party usage, this is a central design pillar.
The broadest notion IMO is that developers will be able to go to the web and find numerous Web Components to choose from. This is not unlike being able to choose from an enormous set of JQuery plugins, but with a much greater degree of interoperability and composition because each instance can be treated as a traditional Element.
platform.js
Platform.js is modeling future browser capabilities called Web Components. There are practical realities of making this work right now, so yes, in order for a third party to use Web Components at all, they will need to opt-in in to platform.js (and all that entails). It's true that this fact makes it's difficult (today) to inject Web Components into somebody's page without their assent.
my version of platform.js could potentially be different than the caller page's
As above, platform.js is required upfront to use Web Components. This is why it's named the way it is. Unless the main page owner includes this capability, he's not providing a platform to which you can supply Web Components.
This is not dissimilar to modern libraries, e.g. JQuery. You can load numerous copies and/or versions of JQuery in one document if you aren't careful, but it's wasteful. Coordination is preferred.
With the exception of platform.js, Web Components is geared around N modules using M dependencies, and that all working together optimally. This is another way sharing is a pillar of the design.
in non-chrome browsers style and other tags are injected into , possibly conflicting with the source page
This all the price of polyfilling. If you need purity of environment, you will have to wait until Web Components are widely implemented natively. As a practical matter, the style tags are very specialized and are unlikely to conflict with anything.
one must have control over the caller's tag if wanting to set options to avoid FOUC
This is not strictly true, you can build Web Components that control their own FOUC up to a point. But it's a lot of extra work, and as a third-party, you really can't know what kind of loading mechanisms or idioms some developer is going to employ, so trying to orchestrate too much without his cooperation is going to be difficult.
Traditionally all my web components have been built via iframes
IFRAME is quite a bit different from Web Components. An IFRAME is a fresh context, and so you have a lot more safety net, but it's heavyweight and there are coordination costs.
Although platform.js, by it's very nature, is changing the shared platform, Custom Elements themselves need not mess with the user's global namespace or his CSS (although they can). Code can be restricted to the element's prototype, and CSS and DOM can be stashed inside ShadowDOM. The overall intent is that none of that need leak out of the Element, unless somebody wants it to.

Related

What are the pitfalls of embedding using iframe

I am experimenting with Elm to build a reusable dashboard-like UI to be declaratively configured via yaml files.
The yaml files would specify a group of embeddable web-apps (not only elm based but ideally also react/angular/vue) to be included in each instance of this UI, for example by specifying a label and a repository url.
I have tried using the traditional Elm/React way to take over a standard non-iframe dom element with various problems. (mainly, elm replaces the element it takes over, meaning various apps cannot share the same container)
If you want you can see the entire proof of concept here
https://github.com/Dansvidania/mondrian-elm
Are there better ways? (I am sure there are) But also, what are the problems I might encounter if I did decide to go with iframes? I only find anecdotal evidence against iframes, and (in particular for sandboxing) they seem ideal.
Thanks in advance
From Cam Jackson's Micro Frontends artice on martinfowler.com
Just as with the server-side includes option, building a page out of iframes is not a new technique and perhaps does not seem that exciting. But if we revisit the chief benefits of micro frontends listed earlier, iframes mostly fit the bill, as long as we're careful about how we slice up the application and structure our teams.
We often see a lot of reluctance to choose iframes. While some of that reluctance does seem to be driven by a gut feel that iframes are a bit “yuck”, there are some good reasons that people avoid them. The easy isolation mentioned above does tend to make them less flexible than other options. It can be difficult to build integrations between different parts of the application, so they make routing, history, and deep-linking more complicated, and they present some extra challenges to making your page fully responsive.
I use iframes without issue.
Communicating with javascript code embedded in an iframe works but I always feel such code is nailed together and lacks elegance.
I set up messages between the parent web page and the iframe to overcome domain issues and also to clarify the communication that occurs between the parent page and the iframe.
Cookies and iframes do not play well cross domain - but this can be resolved.

Use common JS libs inside sandboxed iframes

I plan to build a module system for my webapp that uses sandboxed iframes and the postMessage API to securely run custom user modules. The iframe blocks all DOM access and should only communicate through an interface provided by me which checks some permissions and provides data.
The system itself is very simple and works fine with vanilla js code inside the modules, however I want to allow developers to use common frameworks/libs to ease development, i.e. by using Vue for data binding.
What is the best way to provide such functionality to the modules? Performance is a huge factor since several dozens of such modules might run at the same time. Is it secure to let sandboxed modules share libs?
Good advice: Unfortunately, iframe sandboxing goes both ways. In general (with a few exceptions: mainly postMessage and pages that satisfy the same-origin policy), an iframe is effectively a separate webpage and cannot be accessed from the host page, and vice-versa. It's probably a better alternative to just request that the individual developers use lightweight libraries.
Bad advice: If you hosted the other devs' files yourself, they could access each other, but having stuff accessible between iframes in this way is certainly not ideal- and doing it this way is a really bad idea, as it exposes you to all sorts of scripting-related attacks; not to mention the fact that the separate iframes would probably accidentally interfere with one another in unexpected ways if you shared Javascript variables between them. Don't do it this way unless you explicitly trust every single developer here to behave properly and code well (i.e. you're in the same workplace). Actually, just don't do it this way at all.
If you really really want to do this, though: an iframe whose target is hosted on the same website can access its parent page through the global variable parent (i.e. parent in an iframe is the same as window in the host, parent.$ would be the parent's jQuery object, and parent.document.getElementById is the same as document.getElementById). A parent page can access its same-origin iframes with document.getElementById("the id of the iframe").contentWindow (and .contentWindow.document, etc. will work here too), but again, if you hosted the code of potentially-malicious developers on your page to get around the same-origin policy, you'd be giving these developers access to your page and any information, including passwords, that your users type on it.

Is shadow dom a viable alternative yet to iframes for css encapsulation?

I have a use case where I want to embed multiple independent web apps in a page. I'd like them to not be able to interfere with each others' CSS. Seems like a classic Shadow DOM use case. I am trying to determine whether Shadow DOM and the available polyfills (particularly ShadyDom and ShadyCSS) are sufficient to support my use case. Bear in mind that these are existing web apps. My main concern with the polyfills is that they seem like they might require me to make changes to the applications that aren't really feasible in terms of how styles are scoped and the DOM is addressed. Most of the examples out there are around building web components, but that's not really my use case. Is Shadow DOM (+ polyfills) a viable option for encapsulating CSS in all browsers today for existing web apps? Are there any examples of this out there?
Yes it is as long as it works with your use case ;-)

Development process using BoilerplateJS

We're impressed with the integration and best practices that BoilerplateJS provides but the documentation is definitely lacking, especially for new RequireJS users.
We're a team of 5, each with different skill sets and one of the attractive points of BoilerplateJS is the ability to isolate UI components.
From the sample scaffolding, it's clear how we can unit-test each component separately. However, we're unclear how we can do this during development:
Developer A creates component structure and view model (tested) and passes it to Developer B
Developer B develops CSS and possibly animation for the component
Developer A and/or B integrate the component into the rest of the website and further test integration
How is it possible to achieve (2)? i.e. allow designers and developers to work on an isolated component - what is the recommended way to load the component so it can developed/debugged/tested?
About CSS
A UI component has roughly 3 parts: Structure (HTML), Presentation (CSS), Behavior (JS). A common way of handling is developers focusing on the Structure and Logic where designers work on the presentation.
This is how we developed the sample application of boilerplatejs. For example, the Menu, Theme and Localization components were developed by developers as a simple 'unordered lists' which looked like below exactly when they completed it (just delete the theme css link via Chrome Developer Tools and you will see the same):
Then designers took the ugly UI and created a theme that position and render these lists in a professional manner (we developed 2 themes stored at src/modules/baseModule/theme). It is of course hard for the developers to just deliver something that ugly, but they need to trust the ability of the designers to do their job. I'm sure you use a source control tool that allows different team members to work on the same component even simultaneously.
If you want the theming to be a prominent feature, I recommend minimizing component specific CSS files. Otherwise you might not be able to create different themes that completely changes the layout and look-n-feel of your components. Downside of not having component local css is the fact that components are not really self contained without 'presentation'. I'm still struggling to answer this question properly, any ideas/help is appreciated! See my related question on this below:
global CSS theming combination with component specific local stylesheets
Anyway there are several ways you may add CSS to your components, have a look at this question where these different ways are discussed.
Adding external CSS file to a BoilerplateJS project
Now about embedding components...
If you want the components embedded in to some other webpage, you can use the DOMController of boilerplate for that. For example, lets say you need to embed the 'departments (src/modules/sampleModule1/departments)' component to some other website. You will have to add a DomController in addition to already existing UrlController (UrlController respond to browser URL changes) to the module (src/modules/sampleModule1/module.js).
//crate a dom controller that searchs within whole document body
var domController = new Boiler.DomController($("body"));
domController.addRoutes({
//look for elements with id 'department_comp' and embed the department component
'#department_comp' : new DepartmentComponent(context),
});
domController.start();
Now on your webpage or on external site place a div or a section element for the DomController to embed department.
<section id="department_comp"></section>
Of course there are two things you need to take care of:
1) Your web page needs to have boilerplatejs runtime in it. This means all your third party JS libraries and theme CSS file should be statically added to the web page. (We are working around this, with v0.2-stable we expect to release a bootstrapper that can do all that with a single script declaration)
2) If your component uses JSON services from a different domain, you will have to address cross domain HTTP requests either with JSONp or CORS. But if your REST services are hosted on the same domain, you dont have to worry about this.

Embedding Javascript in Javascript (I'm serious)?

I'm working on a project where players can place graphical objects on a website and animate them with scripts. As the scripts are going to be shared to all participating clients, the scripting environment must be sandboxed, so that users can't ultimately destroy other users experience for all parts of the page.
It is crucial that the scripts can access shared visual content. Therefore I can't isolate them in iframes entirely - besides that I'm wondering if there's a smoother approach to separate contexts.
I have been dabbling with a native version, where I used separate contexts using the V8 javascript engine, but now I want to bring this to the browser - even if it's just Google Chrome only.
Got any ideas?
Sandboxing JavaScript is inherently difficult, chances are that the script will manage to break out no matter how hard you try. A better course of action might be loading the scripts into an iframe without direct access to the main frame and allowing it to communicate with the main frame via window.postMessage(). You could then define an API that the frame is allowed to use this way without being given too much power.
Edit: Same thing is possible with Web Workers as noted in Is It Possible to Sandbox JavaScript Running In the Browser?, browser support for web workers isn't quite as widespread as for window.postMessage() however (compare http://caniuse.com/#search=postMessage and http://caniuse.com/#search=workers).

Categories

Resources