Using Polymer in Meteor?

As mentioned on the other thread, I’d like to explore using Polymer with Meteor/React. I think that the declarative style of Polymer is a natural fit with JSX templates, there is very little functional overlap, you just treat them like they were native widgets. And while Polymer’s support for WAI-ARIA isn’t as good as it could be, it’s a lot better than the vast majority of toolkits I have looked at.

However, actually getting it to work is problematic. There’s about a dozen packages on atmosphere, most of which are unmaintained, undocumented, don’t work, or have big scary warnings in the docs. I tried several of the most promising looking, but was unable to add the packages to a fresh meteor project due to version conflicts.

There’s a few other packages out there which are not on atmosphere, but they involve even dodgier steps like running bower installs. The best of these appears to be https://github.com/Differential/polymer-demo, but it appears to be only a demo and not an installable package. I rate it the best because the demo appears to have support for running Vulcanize in prod builds so that you get a single JS blob for all of the polymer widgets that you are using instead of hundreds of individual downloads. But I’m not yet enough of a Meteor guru to actually make this work in my project.

I’ve also looked at other non-Polymer packages which support the Material Design L&F, but as I mentioned in the other thread I am seriously disappointed with the lack of a11y support in those libraries.

So here’s how I do it: First of all, forget meteor packages. You will never be happy with that. You need/want to bower install custom elements that aren’t from the official catalogue eventually, so customelements.io for example. So going with bower is the best bet. Bower init in your root directory, it’ll be installed into public/bower, import your elements in your main.html. You can import a file that imports all other imports, so for example in main.html you do a html import that imports the file imports.html, this file contains your references to every html import you’re making. Then this file can be easily vulcanized (concatenated, minified, etc)

Now for the trickier part, using the elements. You should use webcomponents-lite by default, it’s the better polyfill - but it doesn’t play nicely with meteor. When you use stuff like meteor’s {{#each}} and you try to insert elements into custom elements, meteor can’t figure out where to place the elements properly since webcomponents-lite polyfills shadow-dom in a less strict, but far more performant manner than the old polyfill. So how to fix the issue? Very simple: Create a wrapper custom element that essentially receives nothing else than data from your meteor helpers. You do everything from this custom-element, you don’t use Blaze’s layout features. That’s why I generally like to call these items xyz-view.html, I’d like to consider them the main view for a specific page, so I have a landing-view, printshop-view, map-view, etc. and in those custom-elements I import and use the elements I’m using for the view. It sounds a bit complicated but it’s essentially just using a html-custom element as sort of a template instead of/on top of a blaze template. So my actual blaze templates literally just look like this.

<`template='templatename'> (see, i even forgot the syntax since i'm not using blaze templates)`
    <map-view data-property-defined-in-the-element='{{data-from-blaze-helper}}'></map-view>
</template>

I’m including @sashko here because I really want to start a conversation how we can fix this issue. The integration should be actually simple as you can see from above, I just don’t know how to get started and some suggestions how to write a meteor package the way I think it should work would be helpful. Anyway, that’s another discussion for how to make Polymer work backwards compatible without using the way I’m using it.

I think the first thing to do would be to get a critical mass of people who are interested in making polymer work and writing a good integration. Then I’d be happy to consult on the best ways to make it happen in Meteor. Anyway, it seems to me that Bower is basically doomed and people are now using NPM primarily to download client side components - even the Angular community is switching over to NPM now.

How do you use polymer with something like Webpack or Gulp? That could be a good starting point.

OK I understood most of what you said and I’m going to experiment with it. Note that I was planning on using JSX rather than Blaze, so hopefully the problem you mentioned won’t be an issue.

How do you install something like webcomponents-lite with npm? Since it doesn’t install the package in a public/ folder, I’m not sure how to refer to it from the .html file.

I think people do this via custom loaders or module interpreters - so basically you can import HTML files from your JavaScript etc. but I don’t know that much about polymer so I don’t know how it is supposed to work.

Sorry if I was unclear - my question about npm installation had nothing to do with Polymer. The issue is how to make a data resource inside an npm module available on the client. In order to be able to reference the polyfill code in a <script> tag, it needs to be in a ‘public’ folder. However, npm wants to put things in the ‘node_modules’ folder at the root of the project.

I’ve checked stack overflow and other sites and there’s a bunch of confusing answers, all of which date from the Meteor 0.6 era. I was wondering if there was more correct and up-to-date answer.

Yea, the polymer team actually intends to switch to NPM. Last I’ve known was they’re still sticking with Bower because it has better dependency management for the component based workflow apparently.

Well, I got things to work with bower and differential:vulcanize. In addition to following the instructions at https://github.com/Differential/meteor-vulcanize/blob/master/README.md, I also needed to create a .bowerrc file that tells it to put the components in the public folder.

So now this totally works: :smile:

App = React.createClass({
  render() {
    return (
      <paper-header-panel className="flex">
        <paper-toolbar>...etc...</paper-toolbar>
      </paper-header-panel>
    );
  }});

Interesting! How heavy is react? Can you customize it for this usecase? I would ditch Blaze if I could just have react import my components in my view and that’s it.

If you just want to use something to import Polymer components, Blaze is a far better option since it is much smaller and will add fewer KB to your page.

Yes, but then at the same time Blaze loads both jquery and underscore when it’s not needed. That adds unneeded footprint again :confused:

Basically the main concern for using Polymer is: You shouldn’t need to load all these dependencies just to use the components. I just need two things for our app: Load a component into the view/route & load some reactive data (of course, those requirements might change as our app grows). So with that said, yes Blaze works for now but the dependency on jquery and underscore are a problem, this adds a ton of data to load that we just can’t afford to load in our region.

Also, to be honest I’m afraid BlazeLayout will become deprecated soon/less maintained since kadira is focusing heavily on the React stack.

Then you can avoid having Blaze or React - there are plenty of ways to get an element on the page without a whole rendering framework. I’m just saying including React for that purpose is a big mistake.

1 Like

If that happens MDG will have to maintain it or something like it as part of Blaze, since we are recommending Flow Router in the Meteor Guide.

Update: Some additional issues I’ve encountered using Polymer and react:

  1. React treats custom HTML tags differently than the standard tags. In particular, using “className” won’t work, you need to use “class” just as if you were using regular HTML.

  2. There a limits on what you can do in terms of styling Polymer elements. Many elements can be styled using regular CSS properties and this works well. However, you can’t use CSS custom properties of the form --property_name. Specifically:

  • You can’t use them in external stylesheets because the polyfill doesn’t support this.
  • You can’t embed them in the main document because the JSX parser chokes on the syntax, for example:

<style is="custom-style"> paper-badge { --paper-badge-background-color: blue; } // Won't parse </style>

I can think of several workarounds, but they are all fairly painful.

  1. Listening to events is not as nice as it could be.

Elements like paper-button produce ‘tap’ events (yes, you can listen to ‘click’ but it’s not as good.) Unfortunately, neither the React syntax (onTap={handler}) or the Polymer syntax (on-tap) will work correctly. Instead, you’ve got to get the element reference in the componentDidMount method and call element.addEventListener('tap', handler);

However, none of these issues are showstoppers for me, and overall I’m liking the way the app looks & feels.

1 Like