Sunday, March 22, 2015

Importing Polymer.dart Elements without <link> Tags


Doing away with <link> imports in Polymer.dart 0.16 is pretty darn cool. It could also present me with a challenge in Patterns in Polymer. Hopefully I can make it work without too much effort, especially with the 1.2 edition right around the corner. There is only one way to find out!

My main concern is that, wherever possible in the book, I use the same text for both the JavaScript and Dart versions. This cuts down on copy edits and keeps me focused on concepts rather than nuances between the two implementations. This change would seem to necessitate more nuances—even if mostly confined to the setup sections of each chapter.

Much of the initialization in the Dart version of the book pulls in the <x-pizza> definition and initializes Polymer like this:
    <!-- Load component(s) -->
    <link rel="import"
          href="packages/page_objects/elements/x-pizza.html">

    <!-- Start Polymer -->
    <script type="application/dart">
      export 'package:polymer/init.dart';
    </script>
The new alternative available in 0.16 is to start Polymer and load the definition at the same time:
    <!-- Load the component and start Polymer -->
    <script type="application/dart">
      import 'packages/page_objects/elements/x_pizza.dart';
      export 'package:polymer/init.dart';
    </script>
I can't just make that change. In the previous version of Polymer.dart, the link-tag-imported HTML template definition pulled in the code definition. This new approach is importing the code definition, so now it needs a way to pull in the template definition.

Without updating my element definition, I get a warning that <x-pizza> is no longer defined:
[Warning from polymer (Linter) on page_objects|web/index.html]:
line 14, column 7 of web/index.html: custom element with name "x-pizza" not found. See http://goo.gl/5HPeuP#polymer_11 for details.
<x-pizza>
^^^^^^^^^
Build completed successfully
Why that counts as a successful build, I could not say, but it definitely needs a little something extra. My x_pizza.dart backing code had been:
import 'package:polymer/polymer.dart';
import 'dart:convert';
import 'dart:async';

@CustomTag('x-pizza')
class XPizza extends PolymerElement {
  // Super cool pizza stuff here...
}
To make this work with no-link-tag importing, I have to annotate the code as a library using @HtmlImport—the @HtmlImport annotation effectively taking the place of the old link-tag importing:
@HtmlImport('x-pizza.html')
library x_pizza;

import 'package:polymer/polymer.dart';
import 'dart:convert';
import 'dart:async';

@CustomTag('x-pizza')
class XPizza extends PolymerElement {
  // ...
}
The old link-tag importing still works if one prefers that, but this definitely cuts down on the number of lines required in the containing web page.

For this particular code, I am not quite done. Everything compiles and runs without error, but the <x-pizza> element no longer displays any UI. There are no warnings in the browser console, but I do see this message:
No elements registered in a while, but still waiting on 1 elements to be registered. Check that you have a class with an @CustomTag annotation for each of the following tags: 'x-pizza-toppings'
The problem here is that my <x-pizza> uses the <x-pizza-toppings> Polymer element for adding toppings (first half, second half, and whole) to the pizza. This error is telling me that I must also adapt it to the new approach.

I find this a strange error because I am still link-tag importing this child element from the <x-pizza> template:
<link rel="import" href="x-pizza-toppings.html">
<polymer-element name="x-pizza">
  <!-- Pizza html template stuff here.. -->
</polymer-element>
This template definition for <x-pizza-toppings> pulls in the backing class via the usual script tag:
<link rel="import" href="../../../packages/polymer/polymer.html">
<polymer-element name="x-pizza-toppings">
  <!-- Pizza topping html template stuff here.. -->
  <script type="application/dart" src="x_pizza_toppings.dart"></script>
</polymer-element>
And in that backing class is the @CustomTag that Polymer is complaining about:
import 'package:polymer/polymer.dart';

@CustomTag('x-pizza-toppings')
class XPizzaToppings extends PolymerElement {
  // Pizza topping code...
}
I am able to get this working, but then things get really strange...

To get it working, I convert <x-pizza-toppings> to the new no-link-tag style class definition:
@HtmlImport('x-pizza-toppings.html')
library x_pizza_toppings;

import 'package:polymer/polymer.dart';

@CustomTag('x-pizza-toppings')
  // Pizza topping code here...
}
In the code for the XPizza backing class, I now have to import (the Dart kind, not the link-tag kind) the x_pizza_toppings.dart code:
@HtmlImport('x-pizza.html')
library x_pizza;

import 'package:polymer/polymer.dart';
import 'dart:convert';
import 'dart:async';
import 'x_pizza_toppings.dart';

@CustomTag('x-pizza')
class XPizza extends PolymerElement {
  //  Pizza stuff here...
}
I also have to work back through the HTML template definitions in both x-pizza.html and x-pizza-toppings.html to remove the old link imports and the <script> tags that reference the backing class. Removing the <script> tags makes sense—the backing class is now responsible for pulling the template, not the other way around. So that is not too strange.

What is strange here is that I can no longer reproduce the original “waiting on 1 elements to be registered” error condition. If it revert my changes completely and retrace my steps, things either work or fail in different (more easily understood) ways. It feels like some bad code got cached somewhere (in the .pub directory?) during my initial pass at this, but can no longer be produced. That or I did something crazy the first pass through.

I am uncomfortable with this—it feels like I need to be quicker to manually delete .pub when I start doing this kind of thing. At the same time, I shouldn't have to do anything of the sort. For now, I chalk it up to pre-release glitches and (more likely) a dumb mistake that I can no longer remember.

In the end, I like the new approach. The waiting-for-registration problem leaves me a little unsettled, so I am not quite ready to adopt it as the approach in Patterns in Polymer. But it is probably worth a mention somewhere.


Day #6

No comments:

Post a Comment