Friday, January 3, 2014

Packing Old Polymers for New Browsers


This is crazy. Somehow I do not have a running sample of an <ice-code-editor> Polymer available anywhere. At various times I had gotten this working. I even have a post from last year that worked at one point. But now nothing. Since I wanted to explore wrapping Polymer around existing, large codebases anyway, this seems a good opportunity.

First, it has been a while since I last tried to Polymerize the ICE Code Editor. None of the samples that I include in the web directory are working anymore. A quick scan of git log reveals that my last Polymer work was pre-Dart 1.0:



I cherry-pick that 1.0 commit (git cherry-pick f698145) rather than rebasing the polymer branch onto the latest master branch. Hopefully that is all I need to get things working again and it seems less likely to (a) devolve into resolving multiple merge conflicts and (b) introduce other, unrelated problems.

And that does get most of the examples working. It even gets an embedded example working:



But that was a pre-Polymer attempt at a similar solution. Unfortunately, I seem to have a Polymer bug. Hopefully it is just an old-version-of-polymer bug:
Internal error: 'package:polymer_expressions/polymer_expressions.dart': Error: line 53 pos 34: cannot resolve class 'BindingDelegate' from 'PolymerExpressions'
class PolymerExpressions extends BindingDelegate {
                                 ^ 
And, holy cow, I am using an old, modified, locally installed version of Polymer per my pubspec.yaml:
name: ice_code_editor
# ...
dependencies:
  crypto: any
  js: any
  ctrl_alt_foo: any
  json: any
  polymer: {path: /home/chris/repos/dart/dart/pkg/polymer}
Heh. Any time I think I am living too close to the bleeding edge for Patterns in Polymer I can now remind myself that at least this kind of hacking is no longer necessary.

I switch to the latest, packaged Polymer:
name: ice_code_editor
# ...
dependencies:
  crypto: any
  js: any
  ctrl_alt_foo: any
  json: any
  polymer: any
After that change, I pub get, which gets me to one of my favorite games: “my, how things have changed!”

Instead of the old combination of JavaScript boot script and Polymer import, I switch to the new export-init-script:
<head>
  <!-- Load component(s) -->
  <link rel="import" href="packages/ice_code_editor/polymer/ice_code_editor.html">
  <!-- Load Polymer -->
  <script type="application/dart">
    export 'package:polymer/init.dart';
  </script>
</head>
In the olden days of 2013, I had to mixin an observable class into my Polymer definition—no more. There used to be a create() lifecycle method as in the JavaScript version of Polymer—now it is a named constructor. Lastly, to manipulate the DOM of the current element, I previously had to go through the host property—now I can call append() directly.

The end result looks much more familiar to me after my recent 1.5 month deep-dive into all things Polymer:
import 'package:polymer/polymer.dart';

import 'dart:html';
import 'package:ice_code_editor/ice.dart' as ICE;

@CustomTag('ice-code-editor')
class IceCodeEditorElement extends PolymerElement {
  @published String src;
  @published int line_number = 0;
  ICE.Editor editor;

  IceCodeEditorElement.created(): super.created() {
    var container = new DivElement()
      ..id = 'ice-${this.hashCode}'
      ..style.width = '600px'
      ..style.height = '400px';

    append(container);
    // ...
  }
  // ...
}
And that does the trick. I have my custom <ice-code-editor> element back and am able to embed multiple instances of it:



But that is only half of tonight's battle. I also wanted to deploy this. That raises a very important question: how the heck do you deploy Polymer.dart code?

I know that I need at least one thing added to make that happen—a Pub transformer. To make ready its custom elements, Polymer.dart includes a build “transformer” that does all of the necessary work. Specifying a transformer is done in the pubspec.yaml file:
name: ice_code_editor
# ...
dependencies:
  crypto: any
  js: any
  ctrl_alt_foo: any
  json: any
  polymer: any
transformers:
- polymer:
    entry_points: web/polymer.html
But, even though this worked fine from Dartium, the resultant pub serve fails. When I load the polymer.html test page, I get a 404 for http://localhost:8080/polymer.html_bootstrap.dart.js. Checking the output from the pub serve web server log, I see a bunch of warnings and errors—errors like:
Build error:
Transform Dart2JS on ice_code_editor|web/polymer.html_bootstrap.dart threw error: 'file:///mnt/data/b/build/slave/dart-editor-linux-stable/build/dart/
sdk/lib/_internal/pub/lib/src/barback/dart2js_transformer.dart': malformed type: line 118: type 'CompilerException' is not loaded
                if (error is CompilerException) return; 
                             ^
malformed type used.
../../../../mnt/data/b/build/slave/dart-editor-linux-stable/build/dart/sdk/lib/_internal/pub/lib/src/barback/dart2js_transformer.dart 118  Dart2JSTransformer.apply.<fn>.<fn>
Eventually, I read enough of the errors to realize that one of them contains useful information. It seems that I have one last holdover from the ancient 2013 version of Polymer.dart. The method signature for attributeChanged(), which I am overriding in my Polymer, has changed:
packages/ice_code_editor/polymer/ice_code_editor_element.dart:33:8: Error: Cannot override method 'attributeChanged' in 'Polymer'; the parameters do not match.
  void attributeChanged(String name, String oldValue) {
       ^^^^^^^^^^^^^^^^
After fixing that (it now requires a third, newValue parameter), I am in business. My <ice-code-editor> Polymer works in Chrome just like it did in Dartium:



Once that is working, I can pub build my page, which dumps output into the build subdirectory. Once it is done, I start a simple HTTP server in there:
➜  build git:(polymer) ✗ python -m SimpleHTTPServer 8000
Serving HTTP on 0.0.0.0 port 8000 ...
With that, I can access my Polymer from any static site with any modern web browser:



Nice! I still need to build for production (this includes some debug code). I would also like to see if I can shrink the codesize down some. Between the editor and the visualization layer, there is a lot of code. Still the current 2.5 MB seems excessive. But hopefully the hard part is out of the way.

Day #985

No comments:

Post a Comment