Showing posts with label bower. Show all posts
Showing posts with label bower. Show all posts

Tuesday, December 2, 2014

Prepping a Polymer Element for Release (Bower)


The best laid plans… are something I clearly know nothing about.

I had planned to try out my new <a-form-input> Polymer, which acts as a base element for other Polymer elements that want native <form> behavior, in a separate Polymer element. My thinking was to identify areas in which my organization structure might not work well in a reusable setting. I never got that far as I took a peak at how Core Elements solves this. Although I could not adapt their approach directly (each core-element is a subdirectory in the project's test harness), I did find my approach lacking.

But tonight I am going to use this element in a separate element. No distractions!

I start by updating my project's bower.json so that Bower will install <a-form-input> from my local filesystem (I will publish once this is working):
{
  "name": "plain_old_forms",
  "dependencies": {
    "polymer": "Polymer/polymer",
    "a-form-input": "/home/chris/repos/a-form-input"
  }
}
Annoyingly, Bower copies the repository when doing this instead of creating a symbolic link:
bower install
bower a-form-input#*          checkout master
bower a-form-input#*          resolved /home/chris/repos/a-form-input#7286265529
bower a-form-input#*           install a-form-input#7286265529

a-form-input#7286265529 bower_components/a-form-input
└── polymer#0.5.1
No matter, the only reason that I would want the symbolic link is to try changes to the library immediately in my project. But it's going to work the first time… because that always happens.

I am going to modify my old friend <x-pizza> to support native HTML forms. I start in the HTML definition, which needs to import the <a-form-input> definition and then extend it:
<link rel="import" href="../bower_components/polymer/polymer.html">
<link rel="import" href="../bower_components/a-form-input/a-form-input.html">
<polymer-element name="x-pizza" extends="a-form-input">
  <template><!-- ... --></template>
  <script src="x_pizza.js"></script>
</polymer-element>
The import path is Bower thanks to the Bower install. This should ensure that, assuming everything works, I am good to release this to general consumption. The extends attribute is how Polymer does "inheritance". With that, <x-pizza> should operate as a real live HTML form element. It should also add the name and value properties to the <x-pizza> backing class. I will need to update the value property inside of the backing class, so I move to that next.

The backing class requires only two changes—one obvious and the other the opposite of obvious:
Polymer('x-pizza', {
  attached: function() {
    this.super();
    this._updateGraphic();
  },
  // ...
  _updateText: function() {
    this.value = this.model.firstHalfToppings.join(',') + "\n" +
      this.model.secondHalfToppings.join(',') + "\n" +
      this.model.wholeToppings.join(',');
  },
  // ...
});
The obvious change is that I need to assign the text value of the pizza's toppings to this.value. This is an HTML form input now, so it needs to update the value property. The less obvious change is the need to call this.super() in the attached() lifecycle method. Without this, the method of the same name in the base element/class, <a-form-input> will not be invoked, which breaks everything. This being JavaScript, inheritance never comes naturally, so I always forget this… until everything breaks.

Last, I assign a name attribute to <x-pizza> element in the containing document like I would any other form element:
<!doctype html>
<html lang="en">
  <head>
    <!-- ... -->
    <script src="bower_components/webcomponentsjs/webcomponents.js"></script>
    <link rel="import" href="elements/x-pizza.html">
  </head>
  <body>
    <form action="test" method="post">
      <h1>Plain-old Form</h1>
      <input type=text name="plain_old_param">
      <x-pizza name="pizza_toppings"></x-pizza>
      <button>Order my pizza!</button>
    </form>
  </body>
</html>
With that… I have a working Polymer element that injects native HTML form values:



Submitting this form includes the value from <x-pizza>:
plain_old_param:Data from a regular input
pizza_toppings:pepperoni
sausage
green peppers
So this would appear to be working.

Which means it is time to create the public GitHub repository:
$ git remote add origin git@github.com:eee-c/a-form-input.git
$ git push -u origin master
...
To git@github.com:eee-c/a-form-input.git
 * [new branch]      master -> master
Branch master set up to track remote branch master from origin.
Then I prep for bower publishing by tagging:
git tag -a v0.0.1 -m "Tag version 0.0.1"
$ git push --tags
...
To git@github.com:eee-c/a-form-input.git
 * [new tag]         v0.0.1 -> v0.0.1
At this point I register with Bower:
$ ower register a-form-input https://github.com/eee-c/a-form-input.git
bower                          convert Converted https://github.com/eee-c/a-form-input.git to git://github.com/eee-c/a-form-input.git
...
bower a-form-input#*          resolved git://github.com/eee-c/a-form-input.git#0.0.1
[?] Registering a package will make it installable via the registry (https://bower.herokuapp.com), continue? Yes
bower a-form-input            register git://github.com/eee-c/a-form-input.git

Package a-form-input registered successfully!
Nice!

I modify the bower.json so that it points to this newly released version instead of my local repository:
{
  "name": "plain_old_forms",
  "dependencies": {
    "polymer": "Polymer/polymer",
    "a-form-input": "~0.0.1"
  }
}
And, after a quick reinstall (rm -rf bower_components; bower install), I again have a working native HTML form input—this time pulled from Bower. I still need a bit of documentation for this element on the GitHub page, but this looks to be ready for public consumption.


Day #12

Monday, December 1, 2014

Organizing Polymer Projects for Reuse, Unit Testing, and Smoke Testing


My tests say that the <a-form-input> Polymer element works, but I have my doubts that I have the repository organized properly. The <a-form-input> element is primarily intended to be used as a base element for other Polymer elements that would like to behave like native HTML <form> input elements (something that Polymer does not support out of the box).

My main worry is the element definition, which resides at the top-level of the element's repository:
.
├── a-form-input.html
├── a_form_input.js
├── bower.json
├── index.html
├── karma.conf.js
├── package.json
├── README.md
└── test
    ├── AFormInputSpec.js
    ├── PolymerSetup.js
    └── x-double.html
Specifically, I worry about the first line in the element definition:
<link rel="import" href="bower_components/polymer/polymer.html">
<polymer-element name="a-form-input" attributes="name value">
  <template></template>
  <script src="a_form_input.js"></script>
</polymer-element>
I referenced Polymer via bower_components because that is where Bower installs things locally. This works when performing smoke tests over a simple HTTP server, but seems destined to break when installed elsewhere. And I realize that I have not given this much thought, which is rather strange considering that Patterns in Polymer is already at 1.0.

I'll chalk that up to I already gave it due consideration and have since forgotten the outcome. Yeah, that's the ticket.

Ahem.

I thought initially to start investigation by using this element in the “play” area of the book's repository. I realize now that I ought to check out the Polymer project itself. They have definitely already solved this, so...

I check out the <core-meta> element which serves as the base of all the Core Elements. Like all of the other core-elements, it plays nicely with Bower. Like my <a-form-input>, the <core-meta> element definition resides at the top level of the repository (so at least I got that right). The actual definition, however, does not reference Bower:
<link rel="import" href="../polymer/polymer.html">
<polymer-element name="core-meta" attributes="label type" hidden>
<script>
  <!-- ... -->
</script>
</polymer-element>
That is not going to quite work for me, however. It does resolve the problem that I have yet to even consider—how this element will reference other elements when installed elsewhere. Removing the explicit reference to bower_components makes all the sense in the world in that respect.

But when I run a simple HTTP server to smoke test the element (via an index.html page also in the top-level of the repository), the route to ../polymer will expect to find a top-level polymer directory.

The solution that I wind up adopting is to manually create a symbolic link to my current project inside the project's bower_components directory:
$ cd bower_components
$ rm -rf *
$ ln -s .. a-form-input
$ cd ..
$ ls -l bower_components
total 0
lrwxrwxrwx 1 chris chris 2 Dec  1 23:53 a-form-input -> ..
I will check this symbolic link into source control so that the a-form-input project always contains a reference to itself. This will still allow dependencies to be installed without trouble:
$ bower install
bower polymer#*                 cached git://github.com/Polymer/polymer.git#0.5.1
bower polymer#*               validate 0.5.1 against git://github.com/Polymer/polymer.git#*
bower core-component-page#^0.5.0           cached git://github.com/Polymer/core-component-page.git#0.5.1
bower core-component-page#^0.5.0         validate 0.5.1 against git://github.com/Polymer/core-component-page.git#^0.5.0
bower webcomponentsjs#^0.5.0               cached git://github.com/Polymer/webcomponentsjs.git#0.5.1
bower webcomponentsjs#^0.5.0             validate 0.5.1 against git://github.com/Polymer/webcomponentsjs.git#^0.5.0
bower polymer#^0.5.0                      install polymer#0.5.1
bower core-component-page#^0.5.0          install core-component-page#0.5.1
bower webcomponentsjs#^0.5.0              install webcomponentsjs#0.5.1
...
$ ls -l bower_components
total 12
lrwxrwxrwx 1 chris chris    2 Dec  1 23:53 a-form-input -> ..
drwxr-xr-x 2 chris chris 4096 Dec  1 23:58 core-component-page
drwxr-xr-x 2 chris chris 4096 Dec  1 23:58 polymer
drwxr-xr-x 2 chris chris 4096 Dec  1 23:58 webcomponentsjs
That seems to do the trick, if I fire up my smoke test HTTP server:
$ python -m SimpleHTTPServer 8000
Then my test element continues to work.

This solution does not come without risks, however. The main concern is that I have a link in a subdirectory to a parent directory. This can easily result in infinite recursion. In fact, my Karma files trip over this right away:
    // list of files / patterns to load in the browser
    files: [
      'bower_components/webcomponentsjs/webcomponents.js',
      'test/PolymerSetup.js',

      {pattern: 'bower_components/**', included: false, served: true},
      {pattern: '*.html', included: false, served: true},
      {pattern: '*.js', included: false, served: true},
      {pattern: 'test/*.html', included: false, served: true},
      'test/*Spec.js'
    ],
The bower_components/** glob tries to match all subdirectories and their contents. Since one of the subdirectories is the parent directory, I wind up matching the top-level directory in my repository which includes bower_components and another reference to the top-level directory. Yikes!

So, to support the seemingly benign link-to-current-project in bower_components, I have to get a little fancy with my Karma file patterns:
    files: [
      'bower_components/webcomponentsjs/webcomponents.js',
      'test/PolymerSetup.js',

      {
        pattern: 'bower_components/!(a-form-input)/**',
        included: false,
        served: true},
      {
        pattern: 'bower_components/a-form-input/*.+(html|js)',
        included: false,
        served: true
      },

      {pattern: 'test/*.html', included: false, served: true},
      'test/*Spec.js'
    ],
The first bower_components pattern finds all subdirectories and files in bower_components except those in a-form-input. This avoids the infinite recursion, but I still need to grab the HTML and JavaScript definitions for the current element, which is what the second bower_components pattern does.

With that, I have my Karma tests passing again:
$ karma start --single-run
INFO [karma]: Karma v0.12.28 server started at http://localhost:9876/
INFO [launcher]: Starting browser Chrome
INFO [Chrome 39.0.2171 (Linux)]: Connected on socket lHJe_wkPmox9Vo1egAIe with id 36845514
.....
Chrome 39.0.2171 (Linux): Executed 5 of 5 SUCCESS (0.152 secs / 0.147 secs)
And my smoke test page still works:



I still need to try this out in an actual project, but I will leave that for tomorrow. Hopefully basing this approach on the core-elements approach will make live usage more or less trivial. But something is bound to go wrong...


Day #11

Thursday, September 4, 2014

Generating Code from NPM that Installs Bower(!)


I have my eee-polymer-tests testing package for custom Polymer elements in pretty good shape. It will install and configure the necessary Karma configuration and skeleton tests to run a single, generated test on a Polymer element (which passes!). But...

My approach assumes two things: that the element definition is located in the elements subdirectory of the current package and that Bower is being used to install Polymer and its dependencies. Neither is a particularly poor assumption. The elements subdirectory is my personal preference, but I like it because it keeps my custom elements separate from any apparatus used to maintain the code. The Polymer project itself uses Bower for its elements, so I am OK sticking with it.

But, unlike all of the other checks that I have in eee-polymer-tests:
What is the name of the Polymer element being tested? click-sink

Generating test setup for: click-sink
[WARN] File exists: karma.conf.js. (use --force to overwrite)
[WARN] File exists: test/PolymerSetup.js. (use --force to overwrite)
[WARN] File exists: test/ClickSinkSpec.js. (use --force to overwrite)
I am not checking for the proper elements subdirectory, nor the Polymer + Bower configuration.

Testing for the existence of the elements directory is pretty straight-forward after my previous efforts:
function okElements() {
  if (!fs.existsSync('elements')) {
    var message = '[WARN] There is no elements subdirectory for Polymer elements. Tests will fail!';
    console.log(message.red);
    return false;
  }
  return true;
}
Checking for the existence of the bower.json is pretty much the same, except for the filename. I can even read the NPM module's package.json, which is what is running the generator in eee-polymer-tests, and write a corresponding bower.json if it does not already exist:
  var npmJson = JSOaN.parse(fs.readFileSync('package.json'));
  var bowerJson = {
    "name": npmJson.name,
    "version": "0.0.0",
    "description": npmJson.description,
    "ignore": [
      "**/.*",
      "node_modules",
      "bower_components",
      "test",
      "tests"
    ],
    "dependencies": {
      "polymer": "Polymer/polymer"
    }
  };
This gives me the brilliant idea to install Bower as part of eee-polymer-tests and ensure that Polymer is installed. Installing Bower is easy enough with NPM—it is, after all, the JavaScript package manager that is installed with the NPM JavaScript package manager. I add it to the list of eee-polymer-tests' dependencies:
{
  "name": "eee-polymer-tests",
  // ...
  "dependencies": {
    "colors": ">0.0",
    "minimist": ">0.0",
    "bower": ">0.0"
  },
  "peerDependencies": {
    "karma-jasmine": "~0.2.0",
    "karma-chrome-launcher": ">0.0"
  }
}
To actually install, it turns out that Bower has an API:
var bower = require('bower');
function generateBower() {
  // ...
  bower.commands
    .install(['Polymer/polymer'], { save: true }, { /* custom config */ })
    .on('end', function (installed) {
        console.log(installed);
     });
}
Which works quite as expected. Well, the installed object that is logged is just an empty object literal, but it does save changes to the bower.json file that is currently installed.

As cool as that is, I lean toward not using it. I have no idea if any besides myself will have use for eee-polymer-tests. Generating a simple test structure with it is one thing (and will be quite helpful), but I already install bower out of habit. I will likely file this under “good to know,” but focus elsewhere. Like actually writing some new tests tomorrow.

Update: Ah, the heck with it. I added bower generation after all: bfe13c3.

Day #173

Thursday, June 5, 2014

Non-Worky Attempts at Core Elements in Polymer.dart


I have complete faith that the Polymer.dart developers will resolve the core-* elements problem in good order. Even so, I would like to take a quick look again tonight to see if it might be possible to better install core elements without waiting. This will likely wind up more of an exercise in Bower mechanics than anything else, but we'll see...

The problem is that there is currently no way to install core-* elements (e.g. <core-ajax>) with Polymer.dart. The Dart version of all of these elements have all been deprecated and most did not work anyway because of a late change to the 0.10 version of Polymer.dart. Exacerbating the problem is that installing with Bower—which is already a pain in a Dart project—does not work because the core-* elements look for a different polymer.html than the one used by Polymer.dart. This results in double-loading exceptions. There are even problems with event data between the JavaScript core-* elements and Polymer.dart custom elements. I am not going to attempt to investigate that—I am more interested in seeing what, if anything, Bower can do to help the situation.

Previously, I had to hand-edit the Bower installed <core-ajax> element so that it uses the same polymer.html as Polymer.dart:
<!-- <link rel="import" href="../polymer/polymer.html"> -->
<link rel="import" href="/packages/polymer/polymer.html">
I had hoped to find a location to bower install these core elements, but I see that is not going to work. For the installed ../polymer/polymer.html to resolve to /packages/polymer/polymer.html, I would need this to be an actual Dart package.

Bummer.

Or is it? Maybe this would work as a separate pub package? This is definitely veering into Polymer.dart team territory, but, I am curious. I start with a new local directory and add a pubspec.yaml:
name: eee_core_ajax
version: 0.0.1
description: Core elements for Polymer
author: Chris Strom 
I specify the lib directory for installation:
.bowerrc:
{
  "directory": "lib"
}
Next, I create a blank bower.json config file for my “Dart” package:
{
  "name": "eee_core_ajax",
  "version": "0.0.1",
  "authors": [
    "Chris Strom "
  ],
  "description": "Core ajax for use in Dart",
  "license": "MIT",
  "private": true,
  "ignore": [
    "**/.*",
    "node_modules",
    "bower_components",
    "test",
    "tests"
  ],
  "dependencies": {
  }
}
I add the latest <core-ajax> as:
➜  dart-core-ajax  bower install -S Polymer/core-ajax
bower core-ajax#*               cached git://github.com/Polymer/core-ajax.git#0.3.1
bower core-ajax#*             validate 0.3.1 against git://github.com/Polymer/core-ajax.git#*
bower polymer#>=0.3.0 <1.0.0    cached git://github.com/Polymer/polymer.git#0.3.1
bower polymer#>=0.3.0 <1.0.0  validate 0.3.1 against git://github.com/Polymer/polymer.git#>=0.3.0 <1.0.0
bower platform#>=0.3.0 <1.0.0   cached git://github.com/Polymer/platform.git#0.3.1
bower platform#>=0.3.0 <1.0.0 validate 0.3.1 against git://github.com/Polymer/platform.git#>=0.3.0 <1.0.0
bower core-component-page#>=0.3.0 <1.0.0           cached git://github.com/Polymer/core-component-page.git#0.3.1
bower core-component-page#>=0.3.0 <1.0.0         validate 0.3.1 against git://github.com/Polymer/core-component-page.git#>=0.3.0 <1.0.0
bower core-ajax#~0.3.1                            install core-ajax#0.3.1
bower polymer#>=0.3.0 <1.0.0                      install polymer#0.3.1
bower platform#>=0.3.0 <1.0.0                     install platform#0.3.1
bower core-component-page#>=0.3.0 <1.0.0          install core-component-page#0.3.1

core-ajax#0.3.1 lib/core-ajax
└── polymer#0.3.1

polymer#0.3.1 lib/polymer
├── core-component-page#0.3.1
└── platform#0.3.1

platform#0.3.1 lib/platform

core-component-page#0.3.1 lib/core-component-page
├── platform#0.3.1
└── polymer#0.3.1
Ah, nuts. That's not going to work. My core-ajax package is going to include a core-ajax sub-directory with that setup:
➜  dart-core-ajax  tree -L 2                       
.
├── bower.json
├── lib
│   ├── core-ajax
│   ├── core-component-page
│   ├── platform
│   └── polymer
└── pubspec.yaml

5 directories, 2 files
Bother. I remove the .bowerrc file, re-install everything in <package-root>/bower_components and manually copy the contents of bower_components/core-ajax into lib:
➜  dart-core-ajax  cp -r bower_components/core-ajax/* lib
Back in my original Polymer.dart code, I add this local directory as a dependency in pubspec.yaml:
name: svg_example
dependencies:
  polymer: ">=0.10.0 <0.11.0"
  eee_core_ajax:
    path: /home/chris/repos/dart-core-ajax
dev_dependencies:
  scheduled_test: any
transformers:
- polymer:
    entry_points: web/index.html
Now, my Polymer element definition template needs to point to this new local package:
<link rel="import"
      href="../../../packages/eee_core_ajax/core-ajax.html">
<polymer-element name="x-pizza">
  <template>
    <core-ajax
       auto
       id="pizza.svg"
       url="/packages/svg_example/images/pizza.svg"
       on-core-response="{{responseReceived}}"></core-ajax>
    <!-- ... -->
  </template>
  <script type="application/dart" src="x_pizza.dart"></script>
</polymer-element>
But, when I try to start pub serve, I get:
package:eee_core_ajax/core-xhr.html:23:1: don't know how to include eee_core_ajax|polymer/polymer.html from svg_example|web/index.html
Dang it. I could write a transformer—or even a script to change the value of the core-* link tag, but this already looking like too much work. Best to call it a night here and move on to more fertile territory tomorrow.

Day #85

Wednesday, February 12, 2014

Auto-running a Bunch of Polymer Tests


Mea culpa, mea culpa, mea maxima culpa.

Forgive me for I have not been testing. It has been two and a half long months since I last tested a Polymer. For penance I must figure out how to test all of these Polymers in one night.

Honestly, I do not need much. A simple test or two for each Polymer used in Patterns in Polymer would likely be enough. It would be nice if the tests upgraded Polymer on each run so that I might find out sooner rather than later when a new version of Polymer breaks things. Then a smoke test or two to verify that the element is working like I expect / hope.

Upgrading seems easier than I expected. At least easier in JavaScript thanks to Bower. I already know that Dart handles this out of the box with pub upgrade. I was not sure about Bower until I tried it:
➜  js git:(master) bower update
bower polymer#~0.1.1            cached git://github.com/Polymer/polymer.git#0.1.4
bower polymer#~0.1.1          validate 0.1.4 against git://github.com/Polymer/polymer.git#~0.1.1
bower platform#0.1.4            cached git://github.com/Polymer/platform.git#0.1.4
bower platform#0.1.4          validate 0.1.4 against git://github.com/Polymer/platform.git#0.1.4
bower polymer#~0.1.1           install polymer#0.1.4
bower platform#0.1.4           install platform#0.1.4

polymer#0.1.4 bower_components/polymer
└── platform#0.1.4

platform#0.1.4 bower_components/platform
A simple bower update before each test run ought to do nicely. Building on that knowledge and with a 2.5 month old Karma test, I start a run-all-the-tests script. I'll get to all-the-tests in a bit, but start with just a single pass to make sure I've got this in order. The bash script that I use is:
#!/bin/bash

# Change the current working directory to a chapter's code directory:
cd book/code-js/svg

# Update bower
bower update

# Run the Karma tests
karma start --single-run

# Handle failure
if [[ $? -ne 0 ]]; then
    echo "Some tests failed."
    exit 1
fi

# Success!
echo "Success!"
Amazingly, that just works:
➜  polymer-book git:(master) ✗ ./scripts/test.sh
bower polymer#~0.1.3            cached git://github.com/components/polymer.git#0.1.4
bower polymer#~0.1.3          validate 0.1.4 against git://github.com/components/polymer.git#~0.1.3
bower platform#0.1.4            cached git://github.com/Polymer/platform.git#0.1.4
bower platform#0.1.4          validate 0.1.4 against git://github.com/Polymer/platform.git#0.1.4
INFO [karma]: Karma v0.10.4 server started at http://localhost:9876/
INFO [launcher]: Starting browser Chrome
INFO [Chrome 34.0.1825 (Linux)]: Connected on socket JY9_C91o2eqYwtV6hFYk
Chrome 34.0.1825 (Linux): Executed 1 of 1 SUCCESS (0.567 secs / 0.477 secs)
Success!
The only drawback to this approach is that I need a actual Chrome window running. Continuous integration might be easier with something like PhantomJS.

Unfortunately, after I enable it in Karma, I get:
PhantomJS 1.9.7 (Linux) ERROR
        ReferenceError: Can't find variable: Window
        at /home/chris/repos/polymer-book/play/svg/js/bower_components/platform/platform.js:30
PhantomJS 1.9.7 (Linux): Executed 0 of 1 ERROR (0.174 secs / 0 secs)
Try as I might, I cannot seem to get rid of this. Defining a Window function in the test only results in a different error:
PhantomJS 1.9.7 (Linux) ERROR
        TypeError: 'undefined' is not an object (evaluating 'a.prototype')
        at /home/chris/repos/polymer-book/book/code-js/svg/bower_components/platform/platform.js:29
PhantomJS 1.9.7 (Linux): Executed 0 of 1 ERROR (0.137 secs / 0 secs)
It seems unlikely that I can figure that out without installing the non-minified version of the Polymer platform. That seems too big a yak to shave—at least for now.

Happy with the start of the script, I convert it to iterate over all of the book directories and get work writing a some good tests.

Mea cupla.


Day #1,025

Friday, January 31, 2014

Publishing to Bower: a Workflow for an AngularJS Directive


The question for today is, how do you extract a working Angular directive into a published Bower package?

From last night, I have my generalized solution for double binding Polymer variables in AngularJS (pushing changes into Polymer works fine, but seeing changes from Polymer in Angular needs a little help). I can change attributes and variable names in Angular templates:
<pre ng-bind="asdf"></pre>
<p>
  <x-pizza bind-polymer state="{{asdf}}"></x-pizza>
</p>
And, thanks to last night's generalized bind-polymer directive, it just works™:



I can add stuff to my <x-pizza> Polymer and Angular sees the change—even with whatever ridiculous variable name I might put in there. So I am good to go with this approach, except…

It likely will not fit a nice narrative in Patterns in Polymer—at least not a consistent narrative between the Dart and JavaScript versions of Polymer. The problem is that the Dart and JavaScript solutions are at completely different abstraction levels currently. Dart has a package that does this (angular_node_bind) and my JavaScript solution requires the reader to write their own Angular directive. Which means… I have a darn good excuse to publish my first Bower package!

I start with a new, local Git repository. Before publishing this to Bower, I ought to make sure that it works. It seems like Bower will only work with local Git repositories (not directories), I start angular-bind-polymer:
➜  repos  mkdir angular-bind-polymer
➜  repos  cd !$
➜  angular-bind-polymer  git init .
Initialized empty Git repository in /home/chris/repos/angular-bind-polymer/.git/
Next, I initialize this as a Bower project with bower init:
➜  angular-bind-polymer git:(master) bower init
I mostly accept the defaults from the very nice initialization script. The customizations are specific to this being an Angular module (it will depend on AngularJS) and how I organize the package (I will create the code directly in the top-level of the repository). The differences from the defaults in the resulting bower.json are then:
{
  "name": "angular-bind-polymer",
  // ...
  "description": "Angular directive for *double* variable binding of Polymer attributes.",
  "main": "angular_bind_polymer.js",
  // ...
  "dependencies": {
    "angular": "~1.2.9"
  }
}
Now for the main file, angular_bind_polymer.js. I have the Angular directive ready to go, I only need place it in the main file properly. For that, I assume that Angular will already be loaded, which will make the angular global variable available. I need to declare this as a module and the unofficial convention for these things seems to be prefixing the module name with a GitHub ID (eee-c in my case). So angular_bind_polymer.js becomes:
angular.module('eee-c.angularBindPolymer', []).
directive('bindPolymer', function($q, $timeout) {
  // Yesterday's directive definition here...
});
I check those in locally and am ready to try them back in the application from which this is being extracted.

So, back in the bower.json file from the original project, I add my local Git repository in the list of dependencies:
{
  "name": "angular_example",
  // ...
  "dependencies": {
    "angular": "~1.2.9",
    "polymer": "~0.1.3",
    "angular-route": "~1.2.9",
    "angular-bind-polymer": "/home/chris/repos/angular-bind-polymer/"
  }
}
In the application directory, I bower install to get my new module:
➜  js git:(master) ✗ bower install
bower angular-bind-polymer#*       not-cached /home/chris/repos/angular-bind-polymer#*
bower angular-bind-polymer#*          resolve /home/chris/repos/angular-bind-polymer#*
bower angular-bind-polymer#*         checkout master
bower angular-bind-polymer#*         resolved /home/chris/repos/angular-bind-polymer#7bcc2d673d
bower angular#~1.2.9                   cached git://github.com/angular/bower-angular.git#1.2.9
bower angular#~1.2.9                 validate 1.2.9 against git://github.com/angular/bower-angular.git#~1.2.9
bower angular#~1.2.9                      new version for git://github.com/angular/bower-angular.git#~1.2.9
bower angular#~1.2.9                  resolve git://github.com/angular/bower-angular.git#~1.2.9
bower angular#~1.2.9                 download https://github.com/angular/bower-angular/archive/v1.2.11-build.2195+sha.29432ff.tar.gz
bower angular#~1.2.9                  extract archive.tar.gz
bower angular#~1.2.9                 resolved git://github.com/angular/bower-angular.git#1.2.11-build.2195+sha.29432ff
bower angular-bind-polymer#*          install angular-bind-polymer#7bcc2d673d

angular-bind-polymer#7bcc2d673d bower_components/angular-bind-polymer
└── angular#1.2.9
Next, I need to update the web page that holds my Angular application so that, after loading Polymer, Angular, and other related sources, it loads my new package:
    <script src="bower_components/platform/platform.js"></script>
    <link rel="import" href="elements/x-pizza.html">

    <script src="bower_components/angular/angular.min.js"></script>
    <script src="bower_components/angular-route/angular-route.min.js"></script>
    <script src="bower_components/angular-bind-polymer/angular_bind_polymer.js"></script>
Finally, I remove the directive code from my Angular application and, in its place, add my new module:
var pizzaStoreApp = angular.module('pizzaStoreApp', [
  'ngRoute',
  'eee-c.angularBindPolymer'
]);

pizzaStoreApp.config(['$routeProvider',
  // Routing stuff here...
]);
And, with that, I am done! I have successfully created a working Angular module in a Git repository and used that repository to install and use that Angular module.

All that is left at this point is to register the package with bower. First I tag (and push to GitHub):
➜  angular-bind-polymer git:(master) git tag -a v0.0.1 -m "Tag version 0.0.1" 
➜  angular-bind-polymer git:(master) git push --tags
Counting objects: 1, done.
Writing objects: 100% (1/1), 171 bytes, done.
Total 1 (delta 0), reused 0 (delta 0)
To git@github.com:eee-c/angular-bind-polymer.git
 * [new tag]         v0.0.1 -> v0.0.1
Then I register:
➜  angular-bind-polymer git:(master) bower register angular-bind-polymer https://github.com/eee-c/angular-bind-polymer.git
bower                          convert Converted https://github.com/eee-c/angular-bind-polymer.git to git://github.com/eee-c/angular-bind-polymer.git
bower angular-bind-polymer#*   resolve git://github.com/eee-c/angular-bind-polymer.git#*
bower angular-bind-polymer#*  download https://github.com/eee-c/angular-bind-polymer/archive/v0.0.1.tar.gz
bower angular-bind-polymer#*   extract archive.tar.gz
bower angular-bind-polymer#*  resolved git://github.com/eee-c/angular-bind-polymer.git#0.0.1
[?] Registering a package will make it installable via the registry (https://bower.herokuapp.com), continue? Yes
bower angular-bind-polymer    register git://github.com/eee-c/angular-bind-polymer.git

Package angular-bind-polymer registered successfully!
All valid semver tags on git://github.com/eee-c/angular-bind-polymer.git will be available as versions.
To publish a new version, just release a valid semver tag.

Run bower info angular-bind-polymer to list the available versions
And I'm done!

Day #1,013

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: https://github.com/eee-c/hello-you
[?] 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: [
    'polymer'
  ],
  license: 'MIT',
  homepage: 'https://github.com/eee-c/hello-you',
  ignore: [
    '**/.*',
    'node_modules',
    'bower_components',
    'test',
    'tests'
  ]
}
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">
  <template>
    <h2>Hello {{your_name}}</h2>
    <p>
      <input value="{{your_name}}">
      <input type=submit value="Colorize!" on-click="{{feelingLucky}}">
    </p>
    <!-- ... -->
  </template>
  <script>
    Polymer('hello-you', {
      your_name: '',

      feelingLucky: function() {
        // Randomly change the color here...
      }
    });
  </script>
</polymer-element>
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">
  <head>
    <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">
  </head>
  <body>
    <div class="container">
      <hello-you></hello-you>
    </div>
  </body>
</html>
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">
  <!-- ... -->
</polymer-element>
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://github.com/Polymer/polymer.git#0.1.1
bower polymer#~0.1.1          validate 0.1.1 against git://github.com/Polymer/polymer.git#~0.1.1
bower platform#0.1.1            cached git://github.com/Polymer/platform.git#0.1.1
bower platform#0.1.1          validate 0.1.1 against git://github.com/Polymer/platform.git#0.1.1
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">
  <head>
    <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">
  </head>
  <body>
    <div class="container">
      <hello-you></hello-you>
    </div>
  </body>
</html>
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

Tuesday, December 31, 2013

Polymer, External Libraries, and Latency


One of the many things I appreciate about Polymer is how it handles getting everything ready. There are a lot of interconnected parts that can be loaded in a Polymer application or widget, but Polymer manages them with aplomb. This is principally accomplished via the WebComponentsReady event which Polymer generates and uses—mostly in the form a nice, simple animated reveal of all Polymers when they are ready to be used.

I am unsure, however, how this WebComponentsReady strategy works when a Polymer is also dependent on third party libraries. I just so happen to be working on a Polymer that depends on Underscore.js. When everything is run locally with zero latency this seems to work just fine. But how will my initial approach fair under more realistic conditions?

From last night, my Polymer is pulling in Underscore.js from the same local web server that hosts my application and my Polymer code. The Polymer does this inside the defining <polymer-element>:
<link rel="import" href="../bower_components/polymer/polymer.html">
<polymer-element name="hello-you">
  <template><!-- ... --></template>
  <script src="../bower_components/underscore/underscore.js"></script>
  <script>
    // Polymer element code here ...
  </script>
</polymer-element>
Currently, this produces network request like this:



My hello-you.html Polymer definition <link>-imports the polymer.html definition and the Underscore library. As soon as the relatively small polymer.html is imported, it requests polymer.js, which contains all of the necessary Polymer library code. While polymer.js is loading, Underscore.js completes loading and is evaluated, making it available when my Polymer code is evaluated. And this is important because my Polymer uses underscore as soon as it is ready:
<link rel="import" href="../bower_components/polymer/polymer.html">
<polymer-element name="hello-you">
  <template>
    <!-- ... -->
  </template>
  <script src="../bower_components/underscore/underscore.js"></script>
  <script>
    Polymer('hello-you', {
      your_name: '',
      // ...
      feelingLucky: _.debounce(
        // A function in need of debouncing...
        750,
        true
      )
    });
  </script>
</polymer-element>
So what happens if there is a ton of latency (as in a mobile connection)? Will my Polymer class definition crash because the _ Underscore.js top-level variable is not defined?

That turns out to be a nearly impossible question to answer directly. Even though Underscore.js is larger than Polymer.js, the indirection of importing polymer.html which then imports polymer.js turns out to be sufficient to make it impossible to break my Polymer. Even if I create latency of up to 1.6 seconds:
$ sudo tc qdisc add dev lo root netem delay 800ms
(always, always, always remember to sudo tc qdisc del dev lo root when done testing latency)

Even this is not enough to make the evaluation times different enough so I can determine if Underscore.js is not available for Polymer. So instead, I create a gigantic JavaScript file that is mostly comment filler, but defines a single variable that I use in my Polymer. And, when I load the script I find:



That is beautiful. Even though the filler script takes significantly longer to load than Polymer does, Polymer is aware of the need to wait and does not do its thing until the <script> tag is ready.

The other question that I would like to answer has more to do with deployment—how does latency affect third party libraries when they are hosted on CDNs. It so happens that Underscore.js is hosted on a CDN, so I switch my <script> tag to point to such a CDN:
<link rel="import" href="../bower_components/polymer/polymer.html">
<polymer-element name="hello-you">
  <template><!-- ... --></template>
  <script src="http://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.5.2/underscore-min.js"></script>
  <script>
    // Polymer element code here ...
  </script>
</polymer-element>
Now, I can add insane latency to my network connection, leaving the localhost connection effectively instantaneous:
$ sudo tc qdisc add dev eth1 root netem delay 10000ms
With that, I still see Polymer doing the right thing:



It takes 20 seconds to load underscore from that CDN because of my absurd traffic control (tc) setting. And yet Polymer just works. It waits until the library is loaded and then reveals the fully working Polymer element.

How cool is that?

One final note here is that it does not seem to matter where the <script> tag goes. Polymer still does right when the <script> tag goes at the top of the Polymer definition:
<link rel="import" href="../bower_components/polymer/polymer.html">
<script src="http://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.5.2/underscore-min.js"></script>
<polymer-element name="hello-you">
  <template><!-- ... --></template>
  <script>
    // Polymer element code here ...
  </script>
</polymer-element>
I think that serves better to illustrate the immediate dependencies of a Polymer—something akin to declaring “normal” code's imports at the top of a file. Since there does not appear to be a difference in functionality or performance, I will likely opt for that approach in Patterns in Polymer.

I do love it when I discover that libraries and tools just work like this. Maybe someday I can write tools that behave this well, but until then I will have to content myself with being able to appreciate them. And write lots of books extolling their many virtues!



Day #982

Monday, December 30, 2013

Getting Started with Bower and Polymer


Managing and using dependencies in Dart is a joy. That is rather the point of coding in Dart. Doing the same in JavaScript is an adventure. But it is an adventure that is improving. One of the ways in which it is the Bower project, which is, I suppose, one of the reasons that the Polymer project has adopted Bower for managing its own dependencies.

Tonight, I would like to explore using Bower to manage a custom Polymer. I would also like to see if I can get Bower to install a third party library like Underscore.js for use inside my Polymer. I know full well how I would go about doing this in the Dart port of Polymer, but am a little fuzzy on the JavaScript details.

I get started with bower init:
$ bower init
[?] name: underscore_example
[?] version: 0.0.0
[?] description: Mucking around with Polymer dependencies
[?] main file: 
[?] keywords: 
[?] authors: Chris Strom 
[?] license: MIT
[?] homepage: https://github.com/eee-c/polymer-patterns
[?] set currently installed components as dependencies? Yes
[?] 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? Yes

{
  name: 'underscore_example',
  version: '0.0.0',
  homepage: 'https://github.com/eee-c/polymer-patterns',
  authors: [
    'Chris Strom '
  ],
  description: 'Mucking around with Polymer dependencies',
  license: 'MIT',
  private: true,
  ignore: [
    '**/.*',
    'node_modules',
    'bower_components',
    'test',
    'tests'
  ]
}

[?] Looks good? Yes
Next, I install Polymer, adding it to the list of dependencies in the generated bower.json file:
bower install --save Polymer/polymer
bower polymer#*                 cached git://github.com/Polymer/polymer.git#0.1.1
bower polymer#*               validate 0.1.1 against git://github.com/Polymer/polymer.git#*
bower platform#0.1.1            cached git://github.com/Polymer/platform.git#0.1.1
bower platform#0.1.1          validate 0.1.1 against git://github.com/Polymer/platform.git#0.1.1
bower polymer#~0.1.1           install polymer#0.1.1
bower platform#0.1.1           install platform#0.1.1

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

platform#0.1.1 bower_components/platform
Finally, I add my other dependency, Underscore.js:
$ bower install --save underscore     
...
bower underscore#~1.5.2        install underscore#1.5.2

underscore#1.5.2 bower_components/underscore
At this point, I have the generated bower.json plus my new dependencies (which were saved by the --save option to bower install above):
{
  "name": "underscore_example",
  // ...
  "dependencies": {
    "polymer": "Polymer/polymer#~0.1.1",
    "underscore": "~1.5.2"
  }
}
The dependencies are installed and ready to use:
tree -d -L 1 bower_components
bower_components
├── platform
├── polymer
└── underscore

3 directories
But my guess is that I do not want to check anything under the bower_components directory into source control. The entire contents can be recreated on another developer's machine or in a deployment environment with bower install. So my next step is to add bower_components to my dot-gitignore file:
$ echo bower_components >> .gitignore 
$ cat .gitignore 
node_modules
bower_components
Now that I have the JavaScript that I want to use, let's use it. I start with the application code that goes in the main web page. The Polymer documentation starts with the Polymer itself, but I find it easiest to have the page page ready. My index.html:
<!DOCTYPE html>
<html lang="en">
  <head>
    <title>Working with Underscore.js</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="scripts/hello-you.html">
  </head>
  <body>
    <div class="container">
      <hello-you></hello-you>
    </div>
  </body>
</html>
And now, my <hello-you> Polymer. I have been using a simple Polymer for illustration that binds an <input> value to a variable that is also bound in the Polymer title. I also have a feelingLucky() method that randomly changes the title's color:
<link rel="import" href="../bower_components/polymer/polymer.html">
<polymer-element name="hello-you">
  <template>
    <h2>{{hello}} {{your_name}}</h2>
    <p>
      <input value="{{your_name}}">
      <input type=submit value="{{done}}!" on-click="{{feelingLucky}}">
    </p>
    <!-- ... -->
  </template>
  <script>
    Polymer('hello-you', {
      your_name: '',
      // ...
      feelingLucky: function() {
         // Change the H2's color here...
      }
    });
  </script>
</polymer-element>
I am not doing anything new in the code tonight. What is different is the <link> import on the first line—I am pulling the Polymer baseclass definition from the Bower installation. With my application already pulling this Polymer in from scripts/hello-you.html, I have a working Polymer built from bower components:



But how do I best go about using my Underscore.js dependency? Say, for instance, I want to debounce the “Done!” button that triggers the feelingLucky() method. I am unsure where best to pull in the Underscore.js library. No matter where I do so, I am pulling the library into global scope—this is JavaScript, after all. I will worry about where best to place the <script> tag that imports Underscore another day. For now, I get the library added via a <script> tag with an Underscore.js src attribute just above the <script> tag that defines the Polymer:
<link rel="import" href="../bower_components/polymer/polymer.html">
<polymer-element name="hello-you">
  <template>
    <!-- ... -->
  </template>
  <script src="../bower_components/underscore/underscore.js"></script>
  <script>
    Polymer('hello-you', {
      your_name: '',
      // ...
      feelingLucky: _.debounce(
        function() {
          // Change the H2's color here...
        },
        750,
        true
      )
    });
  </script>
</polymer-element>
And that works like a charm. If I click the “Done!” button, my feelingLucky() method does indeed change the Polymer's title color right away (the true 3rd parameter to _.debounce() calls the function immediately rather than waiting for the bounce to expire). If I try to double-click, then the color only changes once. If I wait a little less than a second before clicking a second time, I can see the title change colors multiple times.

I note here that, thanks to Underscore's respect for the sanctity of this, I can continue to refer to this inside the anonymous function as if this represents the current object. That is, I can still treat it like a method, which is nice.

That is a good stopping point for tonight. Bower may not be Dart Pub, but it is pretty darn nice. I still need to take a closer look at where best to place the Underscore.js <script> tag. I should also look into the best application structure—in particular, should my Polymer expect to find the bower_component directory one directory above it or can I find a more general solution? I also need to decide how best to deploy this code—especially how best to use a library like Underscore which is available on lovely CDNs.

Good questions all. For tomorrow.


Day #981

Sunday, December 1, 2013

Polymer Code Cleanup with Polymer-Elements


Having slept on it, the idea of establishing pub-sub chains of Polymer elements has, if anything, grown on me. I originally intended to investigate inheritance and Polymer's extends option tonight, but… inheritance. Instead, I continue to poke at interaction between Polymer elements by taking a look at the Polymer project's own elements.

I finished last night with a Polymer that listened for events from another Polymer:
    <store-changes><!-- Polymer to store change events in localStorage -->
      <change-sink><!-- Polymer to normalize change events -->
        <div contenteditable><!-- plain old editable div -->
          <!-- ... -->
        </div>
      </change-sink>
    </store-changes>
I wound up putting a lot of localStorage code into <store-changes>. It would be nice to separate out a little of that localStorage logic so that <store-changes> can worry only about what to store.

Well, it so happens that the Polymer project has a <polymer-localstorage> element. To use that, I need to install polymer-elements with Bower. Bower is yet another package manager for JavaScript-land, which, interestingly enough, is installed with another JavaScript package manager, npm:
$ npm install -g bower
After dealing with npm nonsense (does that ever work right the first time?), I am ready to bower install polymer-elements:
$ bower install polymer-elements
Next, I import the element into my web page:
    <!-- 1. Load Polymer before any code that touches the DOM. -->
    <script src="scripts/polymer.min.js"></script>
    <!-- 2. Load component(s) -->
    <link rel="import" href="scripts/change-sink.html">
    <link rel="import" href="scripts/store-changes.html">
    <link rel="import" href="bower_components/polymer-elements/polymer-localstorage/polymer-localstorage.html">
And place it inside my custom <store-changes> element:
    <store-changes>
      <polymer-localstorage name="store-changes" value="{{value}}"></polymer-localstorage>    
      <change-sink>
        <!-- ... -->
      </change-sink>
    </store-changes>
That will create a localStorage entry at "store-changes". Better yet, it will take care of marshalling the data as JSON for me. This should cut down significantly on the work that I need to do. To use this in <store-changes>, I grab a reference to <polymer-localstorage> in the ready() callback:
<polymer-element name="store-changes">
  <script>
    Polymer('store-changes', {
      ready: function() {
        this.store = this.querySelector('polymer-localstorage');
        this.addEventListener('change', this.storeChange);
      },
      // ...
    });
  </script>
</polymer-element>
Then, when those changes are detected, I store them using this.store:
    Polymer('store-changes', {
      ready: function() {
        this.store = this.querySelector('polymer-localstorage');
        this.addEventListener('change', this.storeChange);
      },
      storeChange: function(e) {
        var change = e.detail,
            store = this.store.value || {};

        var update = {
          current: change.is,
          previous: store.previous || []
        };
        update.previous.unshift(change.is);
        update.previous.splice(10);

        this.store.value = update;
      }
    });
There is still a fair bit of code in there, but now it all deals with initial values and managing the history (which only contains the 10 most recent changes). There is nothing in there about JSON nor is there any overhead associated with creating the default JSON record. This new <polymer-localstorage> element does it all for me.

If I redefine yesterday's get() in terms of <polymer-localstorage>:
      get: function(i) {
        return this.store.value.previous[i];
      },
Then I am again able to retrieve the list of changes—even after a page reload:
el = document.querySelector('store-changes')
el.get(3)
"<h1>Change #4</h1>"
el.get(2)
"<h1>Change #3</h1>"
el.get(1)
"<h1>Change #2</h1>"
el.get(0)
"<h1>Change #1</h1>"
Nice!

Actually, it is not all bad with respect to inheritance in Polymer—some of the examples look more like implementation than inheritance. That is especially interesting using a UI-less base for a UI implementation. I will probably take a look at that tomorrow.


Day #952