Thursday, January 2, 2014

Creating a Polymer Package for Bower Installs

At the risk of sounding like a broken record, I know how to bundle a Polymer in Dart. Like any package in Dart, you create a Dart Pub package and you are done. But how do you do the same thing in JavaScript?

Given that Polymer has made Bower its de facto package management solution, I think the answer likely lies in creating some kind of Bower package. I have no idea how to do that. Reading through the documentation some, it seems like Bower, like Dart's Pub, allows installs from git repositories (local and remote). To test this out, I create a new, local git repository and make some educated guesses as to bower init values:
➜  repos  mkdir hello-you
➜  repos  cd !$
➜  repos  cd hello-you
➜  hello-you  git init
Initialized empty Git repository in /home/chris/repos/hello-you/.git/
➜  hello-you git:(master) bower init
[?] name: hello-you
[?] version: 0.0.0
[?] description: A super cool Polymer. Tell your friends.
[?] main file: 
[?] keywords: polymer
[?] authors: Chris Strom 
[?] license: MIT
[?] homepage:
[?] set currently installed components as dependencies? No
[?] add commonly ignored files to ignore list? Yes
[?] would you like to mark this package as private which prevents it from being accidentally published to the registry? No

  name: 'hello-you',
  version: '0.0.0',
  authors: [
    'Chris Strom '
  description: 'A super cool Polymer. Tell your friends.',
  keywords: [
  license: 'MIT',
  homepage: '',
  ignore: [
I also add Polymer as a dependency in the generated bower.json:
  "name": "hello-you",
  // ...
  "dependencies": {
    "polymer": "Polymer/polymer#~0.1.1"
The various <polymer-*> project elements, like polymer-ajax, are all defined in separate, Bower-enabled repositories. They all seem to keep the Polymer definition in the main directory, so I start with that.

In there, I create hello-you.html with a skeleton version of the trivial app that I have been using:
<link rel="import" href="../polymer/polymer.html">
<polymer-element name="hello-you">
    <h2>Hello {{your_name}}</h2>
      <input value="{{your_name}}">
      <input type=submit value="Colorize!" on-click="{{feelingLucky}}">
    <!-- ... -->
    Polymer('hello-you', {
      your_name: '',

      feelingLucky: function() {
        // Randomly change the color here...
Here, I am borrowing the location for the Polymer library from the <polymer-*> elements. Since this polymer will be installed with Bower, it will be installed in the bower_components directory alongside Polymer. Hence I do not need to include bower_components in the URL path.

One thing that I cannot figure out is how to smoke test my Polymer. If I create a smoke.html in the main directory that uses hello-you.html from the same directory, it looks like:
<!DOCTYPE html>
<html lang="en">
    <title>Smoke Test for Hello You Polymer</title>
    <!-- 1. Load Polymer before any code that touches the DOM. -->
    <script src="bower_components/platform/platform.js"></script>
    <!-- 2. Load component(s) -->
    <link rel="import" href="hello-you.html">
    <div class="container">
The problem is that hello-you.html is importing polymer not from a local bower_components, but is using ../polymer/polymer.html, which winds up trying to access a resource from the wrong location:
XMLHttpRequest cannot load http://polymer/polymer.html. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:8000' is therefore not allowed access. smoke.html:1
I think the <polymer-*> elements may get around this by running a web server from the directory containing the individual repositories. That feels a bit ugly, so I shelve that for today. Instead, to smoke test, I temporarily change the import in my Polymer to explicitly use the bower_components path:
<link rel="import" href="bower_components/polymer/polymer.html">
<!-- <link rel="import" href="../polymer/polymer.html"> -->
<polymer-element name="hello-you">
  <!-- ... -->
After verifying that things are working, I remove the bower_components import, check my code in, and am ready to try installing this elsewhere.

In an empty directory, I bower install my Polymer:
➜  js git:(master) bower install ~/repos/hello-you 
bower hello-you#*           not-cached /home/chris/repos/hello-you#*
bower hello-you#*              resolve /home/chris/repos/hello-you#*
bower hello-you#*             checkout master
bower hello-you#*             resolved /home/chris/repos/hello-you#0476883f8c
bower polymer#~0.1.1            cached git://
bower polymer#~0.1.1          validate 0.1.1 against git://
bower platform#0.1.1            cached git://
bower platform#0.1.1          validate 0.1.1 against git://
bower hello-you#*              install hello-you#0476883f8c
bower polymer#~0.1.1           install polymer#0.1.1
bower platform#0.1.1           install platform#0.1.1

hello-you#0476883f8c bower_components/hello-you
└── polymer#0.1.1

polymer#0.1.1 bower_components/polymer
└── platform#0.1.1

platform#0.1.1 bower_components/platform
That looks promising!

In the same directory, I create an index.html that uses both the necessary platform polyfills and my bower <hello-you> Polymer:
<!DOCTYPE html>
<html lang="en">
    <title>Testing a Bower Polymer</title>
    <!-- 1. Load Polymer before any code that touches the DOM. -->
    <script src="bower_components/platform/platform.js"></script>
    <!-- 2. Load component(s) -->
    <link rel="import" href="bower_components/hello-you/hello-you.html">
    <div class="container">
And, after starting up a simple server, it works:

Nice! I could complain that this is not quite as smooth as running a pub serve web server—especially for smoke testing my the bower package. But really, this is pretty easy and miles easier than doing it without a package manager, so yay!

Day #984

No comments:

Post a Comment