-
Notifications
You must be signed in to change notification settings - Fork 33
Transparently Consume Material Elements in Dart
This document organizes a collection of design documents with the purpose of making it as easy as possible to consume custom elements, especially the material custom elements, in Dart programs. Please note that the examples in these documents are for illustration purposes, refer to the actual implementation of each package to learn the most recent API.
The polymer.dart project has historically taken many roles:
- bring to Dart the power of the next web generation standards, including features such as shadow-dom, custom-elements, and HTML imports
- make it easy to consume elements that use these features from Dart
- bring a set of custom elements that follow the material design to Dart
- make it easy to write new custom elements using the Polymer paradigm in Dart
Except for the last goal, all other goals are orthogonal to polymer itself. However, our implementation currently mixes all these pieces together and doesn't provide good encapsulation for Dart developers. For example, if a developer wants to consume material design elements today, he needs to first learn how to use polymer.dart and be aware of several details of HTML imports and code transformers before he can use them.
Our goal is to make the process of consuming material elements simpler and more transparent.
Here is an example of how we envision users will be able to write code to use a paper element in their app. Assuming they are not using polymer themselves, their HTML page is as simple as any HTML page that loads some Dart code:
index.html:
<script type="application/dart" src="index.dart"></script>Their Dart code imports a paper element and instantiates it in code. Unfortunately, there is no static initialization in the Dart language, so we ask them to include a couple lines of code to ensure the initialization of all web components:
index.dart:
import 'dart:html';
import 'packages:paper_elements/paper_dialog.dart';
import 'packages:initialize/initialize.dart' as init;
main() => init.run().then((_) {
document.body.append(new PaperDialog()..heading = "Hi there");
});
At this point, their application can run in development mode in Dartium. To deploy their application, they include a transformer section in their pubspec to indicate that web components are being used:
pubspec.yaml:
name: my_app
dependencies:
paper_elements: ">0.5.0 <0.6.0"
web_components: ">0.11.0 <0.12.0"
transformers:
- web_components
And that's all there is to it. Under the hood, however, there is a lot of machinery to make this work:
- we use a new Dart-to-HTML import feature to transparently load HTML definitions for paper elements.
- we execute static initializers to load the paper-dialog implementation and to register the corresponding proxies.
- we provide a mirror-based implementation that supports these features without using code transformations for development.
- we transform the application for deployment in multiple phases, including phases to inline HTML imports, combine script tags, and replace reflective initialization with code generation.
Our design is based on the following principles:
- encapsulate as much as possible how material elements are exposed in Dart
- expose features separately, so that users only need to learn the pieces they will be using
- make features composable, so packages like
web_components
and polymer.dart can combine features that are commonly used together.
To this end, we propose a layered design with several new pieces and changes to existing pieces of our infrastructure. This includes:
- adding generalized support for static initialization in Dart.
- revisiting HTML imports: making them more independent of the rest of polymer, and adding support for Dart-to-HTML imports.
- splitting the polymer codebase to make material elements independent of polymer.dart.
We'll discuss each in more detail below.
Under our new design, we require static initializations for two purposes: to use a declarative pattern to register custom elements and custom element proxies, and to implement Dart-to-HTML imports. Note that the former is something we already do in polymer.dart, so this proposal generalizes some of the practices we already have.
We decided to divide support for static initialization in two layers:
- Declarative initialization: Support for static initializers in purely Dart code. Without language support for static initialization, we will introduce this feature as a package.
- Initialization from HTML: Apply static initialization to Dart in the context of HTML documents. This document specifies how to support multiple script tags, HTML imports, and Dart-to-HTML imports.
This separation keeps the design simpler and enables us to use static initialization to implement Dart-to-HTML imports internally. Also, if static initializers ever become a language feature, that would simply replace the first layer, but leave most of the second layer intact.
HTML imports are the main mechanism used to deliver and share paper elements. We present a design document on Dart-to-HTML import support, which details how we plan to support declaring HTML imports from Dart files. This feature will help reduce the redundancy between Dart and HTML imports in applications today.
We want to minimize the dependencies needed to use paper elements. There are a few places where we can improve this:
- Make transformers composable and independent of each other: our current architecture mixes several transformations under the polymer.dart transformer. It's not clear how to use portions of those transformers separately from the rest.
- Today, users of paper elements depend on polymer.dart and all its transitive dependencies. For most elements only polymer.js is needed. We would like to explore splitting polymer.dart in two packages, so the polymer.js contents are distributed separately. One of the key challenge here is that some elements had to be ported (e.g core-list-dart, core-ajax-dart, core-localstorage-dart, core-xhr-dart).
- Move some other pieces from polymer.dart out to the
web_components
package. For example, html inlining, and the polyfill injection transformer.