How to use Polymer with Webpack

Rob Dodson
Jul 17, 2017 · 7 min read

Over the last year I’ve had a number of discussions with mid to large sized companies who are interested in creating common UI libraries that all of their teams can share. Often these teams are on different stacks (React, Vue, Angular, etc.) so using something like Web Components and Polymer makes sense, as all of these frameworks can consume and communicate with Web Components.

Most frameworks tend to rely on ES Modules or CommonJS and tools like Webpack to bundle their code. Polymer, on the other hand, uses HTML Imports. This means developers who want to use the two together will need to reconcile how things get bundled and the order in which they’re loaded.

But Webpack can already understand multiple file formats (.css, .tsx, etc). So could it be extended to understand HTML imports? Sure, why not! Today I’m really excited to show off polymer-webpack-loader, a new tool which consumes HTML Imports and outputs modules ready for Webpack. Not only does this make it much easier to use Polymer with other frameworks, but it also adds interesting new features to Polymer like the ability to use ES Module import syntax to pull in code installed via npm.

Before I get too ahead of myself I want to point out that this is not an official Polymer project — Polymer isn’t “going all in on Webpack” or anything like that — this is just an awesome tool created by two community members, Bryan Coulter and Chad Killingsworth, that solves a pain point a number of developers have encountered. Although the project is still in a beta phase, I thought it would be cool to do a short write up so members of the Polymer community can kick the tires and give it some feedback.

Who is this for?

polymer-webpack-loader will be most beneficial for anyone who:

  • Is integrating Polymer elements as part of a larger project that uses a different framework.
  • Wants to use import syntax to leverage npm packages in their Polymer elements.
  • Wants to use TypeScript, JSX, emojiscript, [insert yr FancyScript of choice].

How does it work?

All <link> elements are converted to ES Module import statements. For example <link rel="import" href="paper-button.html"> becomes import ‘paper-button.html’; That might seem a little weird but remember, everything is a module in Webpack, even HTML and CSS files. By converting <link> elements to import statements, Webpack is able to crawl the rest of our dependency graph.

Step 2. Turn <dom-module>’s into string templates

Step 3. Separate out <script> elements

At the end of all this we should end up with a bundle.js with all of our elements and any other dependencies compiled into it.

Let’s do a hello world!

To get started with the loader, install it from npm.

npm install --save-dev polymer-webpack-loader

Or if you’re using the demo project, cd into the demo directory and run npm i and bower i.

Next, drop the loader into your webpack.config.js, here's the full config file from the demo. I've done my best to comment each section so if you're new to Webpack you can grok what's going on.

The key thing to note is the module section where we define the rules array. The first rule tests to see if a file ends in .html, if so, it gets sent to a set of chained loaders. Loaders transform a file in some way, similar to "tasks" in other build tools. Here we're saying "run everything through polymer-webpack-loader, take the output from that and give it to babel-loader."

Next we’ll need to give our app a starting point, so create an index.js file and include an import statement to pull in an HTML Import.

/* src/index.js */import './my-element.html';

And here’s the actual definition for my-element.html.

my-element.html, is a fairly plain Polymer element with one interesting feature. In the <script> element I'm importing the date-fns library. Webpack will resolve this to the version in my node_modules directory and compile it into my bundle, which is pretty sweet. Finally we can leverage properly scoped modules in our element definitions!

The last thing we need to do is throw together an index.ejs which will be served by the Webpack dev server.

The index.ejs loads the Custom Elements ES5 adapter, Web Components polyfills, and the bundle.js created by Webpack. It also contains an instance of <my-element> in the <body>.

Not sure what that Custom Elements ES5 Adapter is all about? Check out this clip for the full explanation.

Note the line that says <%= htmlWebpackPlugin.files.js[0] %>, as this is where our bundle.js will end up.

Finally, in the terminal run npm start to kickoff the Webpack dev server which will open a browser window for you. You should see something like this:

Success! You’ve now got Polymer bundling with Webpack and leveraging imports from your node_modules directory.

Open questions

Can I publish elements I create using the loader to WebComponents.org?

Does this mean I don’t have to use bower anymore?

What about PRPL / code splitting?

We can achieve the same effect in Webpack using a feature called Code Splitting. The authors of the polymer-webpack-loader have put together a nice Polymer Starter Kit example which demonstrates how to setup your Webpack configuration for code splitting, and how to swap out Polymer’s importHref method for Webpack's dynamic import().

Conclusion

Big thanks to Bryan Coulter and Chad Killingsworth for creating polymer-webpack-loader and Sean Larkin for reviewing this post.

Originally published at robdodson.me on July 17, 2017.

Dev Channel

Developers Channel - the thoughts, opinions and musings…