Thursday, March 27, 2014

Polymer Deployment as an Afterthought


I really don't care about deployment. Except, of course, when it's time to deploy.

At this point, I have written some 1500+ blog posts on a number of subjects. Nearly 200 have been on testing. Fewer than 30 have been on deployment. And that seems about right to me. Pushing out software, whether it is rubbish or not, should be facilitated by a language, library, or framework—and then automated away. Making the software unrubbishy is the trick.

Still, I'd like a better idea of how best to deploy Polymer. At this point, I am more concerned about deploying Dart-flavored Polymer elements than JavaScript ones, so I start there tonight.

There are two different ways that I can think to categorize Polymer.dart deployments. The first is when a Polymer element is part of another application. The second is when the Polymer element is intended to be used on a page independently of other libraries or applications. I think I have a handle on the former from my work integrating Angular.dart and Polymer.dart. That leaves me with the question of how to best prepare a single element, say my <x-pizza> pizza builder element, for ease of inclusion on a page.

With Dart Polymers, deployment currently begins and ends with Dart Pub—the packaging tool. For Polymers, the application's pubspec.yaml configuration file needs to specify web page entry points:
name: deployment_experiment
dependencies:
  polymer: any
dev_dependencies:
  scheduled_test: any
transformers:
- polymer:
    entry_points: web/index.html
A simple pub build then takes that entry point:
<!DOCTYPE html>
<html lang="en">
  <head>
    <!-- Load component(s) -->
    <link rel="import" href="packages/deployment_experiment/elements/x-pizza.html">
    <!-- Load Polymer -->
    <script type="application/dart">
      export 'package:polymer/init.dart';
    </script>
  </head>
  <body>
    <div class="container">
      <h1>Ye Olde Dart Pizza Shoppe</h1>
      <x-pizza></x-pizza>
    </div>
  </body>
</html>
And compiles the Dart code to JavaScript and prepares the HTML for deployment. Preparing the HTML mostly involves including the Polymer element templates directly in the HTML and sourcing the compiled JavaScript:
<!DOCTYPE html><html lang="en">
<head>
<script src="packages/shadow_dom/shadow_dom.debug.js"></script>
<script src="packages/custom_element/custom-elements.debug.js"></script>
<script src="packages/browser/interop.js"></script>

    <!-- Load component(s) -->
    <!-- Load Polymer -->
    <script src="index.html_bootstrap.dart.js"></script>
</head>
<body>
<polymer-element name="x-pizza-toppings">
  <template><!-- ... --></template>
</polymer-element>
<polymer-element name="x-pizza">
  <template><!-- ... --></template>
</polymer-element>

    <div class="container">
      <h1>Ye Olde Dart Pizza Shoppe</h1>
      <x-pizza></x-pizza>
    </div>

</body></html>
If I wanted to deploy most of this code to a CDN so that anyone could readily include <x-pizza> elements, I would copy the various libraries (although the “min” versions instead of the “debug” versions). To try this out, I create a deploy directory and copy said JavaScript libraries into it:
➜  dart git:(master) ✗ mkdir deploy
➜  dart git:(master) ✗ cd deploy 
➜  deploy git:(master) ✗ mkdir scripts
➜  deploy git:(master) ✗ cp ../packages/shadow_dom/shadow_dom.min.js scripts 
➜  deploy git:(master) ✗ cp ../packages/custom_element/custom-elements.min.js scripts 
➜  deploy git:(master) ✗ cp ../packages/browser/interop.js scripts 
➜  deploy git:(master) ✗ cp ../build/web/index.html_bootstrap.dart.js scripts 
➜  deploy git:(master) ✗ cp ../build/web/index.html_bootstrap.dart.js.map scripts
I then create a new HTML file referencing these scripts instead of the pub build package locations:
<!DOCTYPE html><html lang="en"><head>
<script src="/scripts/shadow_dom.min.js"></script>
<script src="/scripts/custom-elements.min.js"></script>
<script src="/scripts/interop.js"></script>
<script src="/scripts/index.html_bootstrap.dart.js"></script>
</head>
<body>
  <polymer-element name="x-pizza-toppings">
    <template><!-- ... --></template>
  </polymer-element>
  <polymer-element name="x-pizza">
    <template><!-- ... --></template>
  </polymer-element>
  <div class="container">
    <h1>Ye Olde Dart Pizza Shoppe</h1>
    <x-pizza></x-pizza>
  </div>
</body></html>
And it works just fine. The only real problem is that developers using this would have to include the <polymer-element> templates in addition to the <script> tags. It would feel more like a “regular” library if it were all <script> tags. So I move the templates out into a JavaScript file that builds them from JavaScript strings:
var xPizzaToppingsHtml = '' +
'<polymer-element name="x-pizza-toppings">' +
'  <template>' +
// ...
'  </template>' +
'</polymer-element>';

var xPizzaHtml = '' +
'<polymer-element name="x-pizza">' +
'  <template>' +
// ...
'  </template>' +
'</polymer-element>';

var container = document.createElement('div');
container.innerHTML = xPizzaToppingsHtml + xPizzaHtml;
document.body.appendChild(container);
With that, my deployment becomes:
<!DOCTYPE html>
<html lang="en">
<head>
  <script src="/scripts/shadow_dom.min.js"></script>
  <script src="/scripts/custom-elements.min.js"></script>
  <script src="/scripts/interop.js"></script>
  <script src="/scripts/index.html_bootstrap.dart.js"></script>
</head>
<body>
  <div class="container">
    <h1>Ye Olde Dart Pizza Shoppe</h1>
    <x-pizza></x-pizza>
  </div>
</body>
<script src="/scripts/x_pizza_templates.js"></script>
</html>
Ideally, I would replace the five different <script> tags with a single <script> source, but I leave that for another day. For now, I would just like to have a quick way to deploy a single element for reuse on any kind of web page. And I think I have that:



The JavaScript files are all coming from my deploy-ready scripts directory. The HTML is all regular HTML, save for my custom <x-pizza> Polymer element. I think my custom Dart Polymer element is ready for public use!

Well, maybe and maybe not. There are still a few questions to answer. I would like to know if this still works should another Dart application exist on the page. It would be nice to combine all of the scripts into a single source file. I would also like to be able to automate all of this.

That said, I am pleased to have gotten this working as well as I have in a single night. The promise of deployable Dart Polymer elements feels that much closer!


Day #16

1 comment:

  1. This should really be automated. Please make it a patch for the Dart Editor. You can find the Dart Editor source code here:

    https://github.com/dart-lang/bleeding_edge/tree/master/dart/editor

    Then submit the patch to the official repo for review, here is how:

    https://code.google.com/p/dart/wiki/Contributing

    Please!

    ReplyDelete