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

1 comment:

  1. I get this error when installing polymer on windows pc. " bower ENOGIT git is not installed or not in the path

    ReplyDelete