Home Start Get started Build an element 1. Get set up 2. Add local DOM 3. Data binding & properties 4. React to input 5. Theming with custom properties Build an app 1. Get set up 2. Create a new page 3. Add some elements 4. Deploy Polymer Feature overview Quick tour Define elements Register an element Declare properties Instance methods Behaviors Local DOM & styling Local DOM Styling Events Handle and fire events Gesture events Data system Data binding Helper elements Tools Tools overview Polymer CLI Document your elements Test your elements Optimize for production Publish an element Advanced tools Services What's new Release notes 1.0 Migration guide About Polymer 1.0 Resources Community Browser compatibility API Reference Polymer.Base array-selector custom-style dom-bind dom-if dom-repeat dom-template Polymer.Templatizer Global settings App Toolbox What's in the box? Using the Toolbox App templates Responsive app layout Routing Localization App storage Service worker Serve your app Case study Shop Elements News Feature overview Quick tour
Define elements
Register an element Declare properties Instance methods Behaviors
Local DOM & styling
Local DOM Styling
Events
Handle and fire events Gesture events
Data system
Data binding Helper elements
Tools
Tools overview Polymer CLI Document your elements Test your elements Optimize for production Publish an element Advanced tools Services
What's new
Release notes 1.0 Migration guide About Polymer 1.0
Resources
Community Browser compatibility
API Reference
Polymer.Base array-selector custom-style dom-bind dom-if dom-repeat dom-template Polymer.Templatizer Global settings

Polymer CLI is the recommended starting point for building Polymer applications. If for some reason it does not meet your needs, you can use the underlying libraries that power its build toolchain. See Advanced tools for a list of these tools.

This guide teaches you more about two of these underlying tools: Vulcanize and Cripser. This doc is mainly of interest to people who are developing their own customized build toolchains.

Reducing network requests is important for a performant app experience. In the Polymer world, Vulcanize is the name given to a build tool that lets you concatenate a set of elements and their HTML imported dependencies into a single file. Vulcanize recursively pulls in all your imports, flattens their dependencies and spits out something that can reduce the number of network requests your app makes. Additionally, the Polymer build tools can also be used to transform your code to run in an environment that enforces content security policy (CSP), including Chrome Apps and Extensions.

Note: for more great info on performance considerations worth keeping in mind when using HTML Imports, see HTML Imports - #include for the web

Follow the steps below to get set up, or watch the Polycast:

Install Vulcanize and its dependencies using NPM:

npm install -g vulcanize

It's recommended to install Vulcanize globally so you can run it from anywhere on the command-line. To install locally, simply omit the -g flag.

Vulcanize can be used standalone from the command line, or as part of a gulp/grunt build chain.

If you have an input HTML file, elements.html, that uses a number of HTML imports, you can run it through Vulcanize as follows:

vulcanize elements.html -o elements.vulcanized.html

The -o or --output flag will direct the output to a new file called elements.vulcanized.html. If you omit the -o flag, Vulcanize will print the output to stdout, which can be useful if you want to pipe it to another command.

elements.vulcanized.html now contains a version of elements.html with all imports inlined and dependencies flattened. Paths to any URLs are automatically adjusted for the new output location, with the exception of those set in JavaScript.

You can pass additional options to Vulcanize in the form of flags. For a full list of supported flags, see the official Vulcanize documentation.

Here’s the same example from above. The extra flags tell Vulcanize to strip out comments, and to merge external scripts and CSS files into the vulcanized file.

vulcanize -o elements.vulcanized.html elements.html --strip-comments --inline-scripts --inline-css

Although Vulcanize does a great job of flattening imports, you may have an existing build system setup that needs to uglify/minify your code or run your CSS through a preprocessor. This section shows you how to add Vulcanize to gulp using gulp-vulcanize.

Using Grunt? You can use the grunt-vulcanize task. It supports a similar set of options [maybe link to README?]

To add Vulcanize to your build process:

Install gulp-vulcanize

npm install --save-dev gulp gulp-vulcanize

Require the Vulcanize module in your gulpfile and add a task to run it.

var gulp = require('gulp');
var vulcanize = require('gulp-vulcanize');

gulp.task('vulcanize', function() {
  return gulp.src('app/elements/elements.html')
    .pipe(vulcanize())
    .pipe(gulp.dest('dist/elements'));
});

gulp.task('default', ['vulcanize']);

This sample assumes your project has a single elements.html file that imports your other web component dependencies.

You should now be able to run gulp and vulcanize your dependencies.

To configure the task with the same stripComments, inlineScripts, and inlineCss options from above, pass them to the Vulcanize task in a configuration object:

gulp.task('vulcanize', function() {
  return gulp.src('app/elements/elements.html')
    .pipe(vulcanize({
      stripComments: true,
      inlineScripts: true,
      inlineCss: true
    }))
    .pipe(gulp.dest('dist/elements'));
});

Depending on the structure of your app, it may make sense to break it into a few small vulcanized bundles, instead of inlining everything into one file. This technique can cut down on loading times as it enables you to only load the elements required for a specific section.

To prevent certain imports from being inlined in your bundle, use the excludes and stripExcludes options together, passing each an array of file paths or regexes.

gulp.task('vulcanize', function() {
  return gulp.src('app/elements/elements.html')
    .pipe(vulcanize({
      excludes: ['elements/x-foo.html'],
      stripExcludes: ['elements/x-foo.html']
    }))
    .pipe(gulp.dest('dist/elements'));
});

If you wish to leave the link tags for an element inside of a bundle, omit the stripExcludes option. This will only prevent the resource(s) from being inlined in the bundle. This technique can be useful if you have several pages with different element sets (but all depending on polymer.html), where you may want to keep the polymer.html file separate, so the browser can cache it efficiently.

Consider a Polymer app composed of four HTML files: index.html, elements/elements.html, elements/x-foo.html, and elements/x-bar.html.

app/index.html:

<!doctype html>
<html>
  <head>
    <script src="bower_components/webcomponentsjs/webcomponents-lite.js"></script>
    <link rel="import" href="elements/elements.html">
  </head>
  <body>
   ...
  </body>
</html>

app/elements/elements.html:

<link rel="import" href="x-foo.html">
<link rel="import" href="x-bar.html">

app/elements/x-foo.html:

<link rel="import" href="../bower_components/polymer/polymer.html">
<dom-module id="x-foo">
  <template>
    <p>Hello from x-foo!</p>
  </template>
  <script>
    Polymer({
      is: 'x-foo'
    });
  </script>
</dom-module>

app/elements/x-bar.html:

<link rel="import" href="../bower_components/polymer/polymer.html">
<dom-module id="x-bar">
  <template>
    <p>Hello from x-bar!</p>
  </template>
  <script>
    Polymer({
      is: 'x-bar'
    });
  </script>
</dom-module>

Without any concatenation in place, loading this application results in at least 5 network requests. Let's bring that number down. Running Vulcanize on elements/elements.html, and specifying elements.vulcanized.html as the output:

vulcanize elements.html -o elements.vulcanized.html

This results in a elements.vulcanized.html that looks a little like this:

<!-- all the code for polymer.html -->
<dom-module id="x-foo" assetpath="/">
  <template>
    <p>Hello from x-foo!</p>
  </template>
  <script>
    Polymer({is: 'x-foo'});
  </script>
</dom-module>
<dom-module id="x-bar" assetpath="/">
  <template>
    <p>Hello from x-bar!</p>
  </template>
  <script>
    Polymer({is: 'x-bar'});
  </script>
</dom-module>

Content Security Policy (CSP) is a JavaScript security model that aims to prevent XSS and other attacks. In so doing, it prohibits the use of inline scripts.

To use Polymer in a CSP environment (such as a Chrome App or Extension), you can use the Crisper project. Crisper removes all scripts from the HTML Imports and places their contents into an external JavaScript file.

Like Vulcanize, Crisper can be used either from the command line, or as a gulp plugin.

To install Crisper, run the following command:

npm install -g crisper

Crisper can work directly with the piped output from Vulcanize, as shown below:

vulcanize elements/elements.html --inline-script | crisper --html elements/elements.vulcanized.html --js elements/elements.vulcanized.js

It may seem a little strange to call vulcanize with --inline-script then pass it through crisper to separate out the JavaScript. However, if any of your elements use external scripts, this flag ensures that both inline and external scripts are extracted and concatenated into elements.vulcanized.js.

Similarly, you can pipe the output from the Vulcanize task directly to the Crisper task in gulp.

Run the following command:

npm install -g gulp-crisper

Then add it to your gulpfile:

var gulp = require('gulp');
var vulcanize = require('gulp-vulcanize');
var crisper = require('gulp-crisper');

gulp.task('vulcanize', function() {
  return gulp.src('app/elements/elements.html')
    .pipe(vulcanize())
    .pipe(crisper())
    .pipe(gulp.dest('dist/elements'));
  });

gulp.task('default', ['vulcanize']);

This depends on how large your application is. Excessive requests are often far worse than filesize. Hypothetically, let's say you have 20 HTML files/imports of 0.5MB each. Out of which only 2 (1MB) are required on the first page. You might want to vulcanize just those two requests into a critical bundle, then load the others in a separate, deferred bundle using Polymer’s importHref method.

For example:

Polymer.Base.importHref('/elements/less-important-stuff.html',
  // onsuccess callback
  function() {
    console.log('yay! our app is ready!');
  },
  // onerror callback
  function(err) {
    console.log('uh oh, something failed', err);
  },
  // use `async` on import
true);

Some of the things that you should think about before combining a large number of imports are when you combine 100 files together, you're eliminating 99 requests. But concatenation does have some drawbacks:

  • The single file takes much longer to download, and potentially blocks loading of an important page.

  • The browser needs to parse and render additional code that might not be required yet.

The short answer is "don't guess it, test it". There are always trade-offs when it comes to concatenation, but tools like WebPageTest can be useful for determining what your true bottlenecks are.