Sunday, October 5, 2014

Command-Line Polymer.dart Generators


I am working on the second in the series of screencasts for readers of the “Extras” edition of Patterns in Polymer. Try as I might, I cannot get it down to under 12 minutes. I would much prefer that they run ~5 minutes, so tonight I explore alternate approaches to code what I need.

The goal of this screencast is to build a working Polymer element. I am not trying to get all functionality in place in this screencast. Rather, I am trying to get everything in the right place to build the real thing. For the Dart version of the screencast, I can code up the pubspec.yaml, web/index.html, x-pizza.html, and x_pizza.dart files in 15 minutes. I could probably get that down to 12 minutes, but I need help if I am going to get to 5-8 minutes.

I could speed up certain sections of the video or use some pre-written snippets, but I have a slight preference for keeping it real-time. So that means code generation. I would further prefer to use standard generators rather than hand-writing my own. Fortunately, Polymer.dart has a few built-in.

I start by globally registering Polymer for running scripts:
$ pub global activate polymer
Resolving dependencies... (30.5s)
...
Activated polymer 0.15.0+1.
Not sure what's up with the 30.5 seconds. Hopefully that's just an internet glitch.

Before using any of the generators, I need a project to play about in. I create a temporary directory with a pubspec.yaml:
$ mkdir tmp
$ cd !$
$ echo "name: x_pizza" > pubspec.yaml
There are two bin scripts in Polymer 0.15.0+1:
$ ls ~/.pub-cache/hosted/pub.dartlang.org/polymer-0.15.0+1/bin
new_element.dart  
new_entry.dart
I will start by creating a new element, which supports the following command-line options:
$ pub global run polymer:new_element -h
pub run polymer:new_element [-o output_dir] [-e super-element] element-name
-o, --output-dir    Output directory
-e, --extends       Extends polymer-element or DOM element (e.g., div, span)
-h, --[no-]help     
So let's create an <x-pizza> element:
$ pub global run polymer:new_element -o lib/elements x-pizza
Successfully created:
  /home/chris/tmp/lib/elements/x_pizza.dart
  /home/chris/tmp/lib/elements/x_pizza.html
And that does exactly what I would expect (and need). The Dart class definition for the element has the boilerplate stuff:
$ cat lib/elements/x_pizza.dart
import 'package:polymer/polymer.dart';
/**
 * A Polymer x-pizza element.
 */
@CustomTag('x-pizza')
class XPizza extends PolymerElement {
  /// Constructor used to create instance of XPizza.
  XPizza.created() : super.created() {
  }
  // Commented out lifecycle methods here...
}
That alone will save me 30 seconds of typing. Compound it with the HTML template definition and I am getting closer to what I need:
$ cat lib/elements/x_pizza.html 
<!-- import polymer-element's definition -->
<link rel="import" href="../../../packages/polymer/polymer.html">
<polymer-element name="x-pizza">
  <template>
    <style>
      :host {
        display: block;
      }
    </style>
    <!-- Template content here -->
  </template>
  <script type="application/dart" src="x_pizza.dart"></script>
</polymer-element>
It sure would be nice if I could generate some of the web/index.html smoke test page. And add the Polymer dependency and transformer to my pubspec.yaml, which is still just:
$ cat pubspec.yaml 
name: x_pizza
Say, maybe that's what the other generator does:
$ pub global run polymer:new_entry -h            
pub run polymer:new_entry entry_point_file.html
Well, that help output leaves a lot to the imagination. Fortunately, it too does exactly what I would expect (and need). Well almost:
$ pub global run polymer:new_entry web/index.html
Added web/index.html to /home/chris/tmp/pubspec.yaml
Successfully created:
  /home/chris/tmp/web/index.html
As the output indicates, I now have a Polymer transformer pointing to the smoke test page:
$ cat pubspec.yaml                               
name: x_pizza
transformers:
- polymer:
    entry_points:
    - web/index.html
A nice-to-have would be adding the Polymer dependency to pubspec.yaml, but this will already help some (especially since I keep omitting the “s” at the end of “transformers” for some reason).

What will help even more is the boilerplate smoke test page at web/index.html:
$ cat web/index.html 
<!doctype html>
<html>
  <head>
    <script src="packages/web_components/dart_support.js"></script>
    <!-- link rel="import" href="path_to_html_import.html" -->
  </head>
  <body>
    <!-- HTML for body here -->
    <script type="application/dart">export 'package:polymer/init.dart';</script>
  </body>
</html>
I still have to link to the lib/x_pizza.html import in there, but that will certainly save some time and typing.

All-in-all, I am excited about these Polymer Dart generators. I expect they will go a long way to solving my screencast time-crunch. Best of all, they are built right into the Polymer.dart library. Now I just need to find a way to do this with the JavaScript version of the screencast. It may be time to play with the new Yeoman generators. Tomorrow.


Day #204

No comments:

Post a Comment