Skip to content
This repository has been archived by the owner on Dec 19, 2017. It is now read-only.

Dart to HTML Imports

Kathy Walrath edited this page Sep 15, 2015 · 5 revisions

This document presents a design for an annotation that allows users to write HTML imports from Dart code. This proposal relies on an existing proposal to add an initialization package.

Motivation

We'd like to integrate HTML Imports and Dart imports, so people can use custom elements, and any HTML files those elements depend on will be transitively imported. This will allow developers of custom elements to encapsulate the use of HTML imports in Dart and will reduce the duplication there is between HTML imports and Dart imports today.

The main motivating example today is our implementation of the material design for Dart. The current implementation is written with custom elements and we provide Dart proxies with a Dart friendly API to use them. Importing a proxy is not enough to use the element, users so far need to replicate the import in HTML. Dart-to-HTML imports will let us remove the duplicate import in HTML, instead the proxies will declare what HTML needs to be included so that the elements work correctly.

Design

We propose adding an @HtmlImport annotation that indicates that Dart is interested in loading HTML code. During development time, the annotation behaves as a static initializer that dynamically injects the HTML import to the page. For deployment, a transformer will be used to eliminate the dynamic injection of HTML imports and replace them with actual inlined HTML code.

Syntax

An Dart-to-HTML import is written as an annotation attached to a library element:

@HtmlImport('paper_dialog.html')
library paper_elements.paper_dialog;

technically the annotation could go somewhere else, but because our implementation builds on top of initializers, using a directive makes it clear that we intend to resolve and initialize Dart-to-HTML imports before any other initializers in library are executed.

Semantics

The basic idea behind an @HtmlImport in a Dart library is that it should be equivalent to have written an actual <link rel="import"> in the HTML document that transitively loaded such library.

@HtmlImport takes a string URI argument, which is resolved with respect to the URI of the file where it appears. The resolved URI will be used for the actual HTML import. This argument is allowed to use package: schemes, and they will be canonicalized first to ensure that they are equivalent to HTML imports written as relative paths reaching into the packages/ directory.

Initially this design doesn't support having Dart script tags in the imported HTML page. This is due to limitations on Dartium today that don't allow loading extra Dart script tags after the isolate starts executing (more details below). If that limitation were to be removed, we could remove our restriction. In that case, if the HTML import includes additional Dart script tags, their initializers would be executed before other initializers on the library containing the @HtmlImport annotation and before initializers of Dart libraries imported from that library directly in Dart.

This design allows users to export custom elements so that they can be imported via Dart or via traditional HTML imports, so if someone wants to consume an element, she can choose the best way to import it for her app. Note that, even if Dart script tags are not allowed in HTML files included via @HtmlImports, it is still possible to do this by following a pattern of indirection with 2 HTML files:

  • my_element.dart:
// Users can consume <my-element> by importing this from Dart.
@HtmlImport('my_element_nodart.html')
library my_element;
...
  • my_element.html:
<!-- Users can consume <my-element> in HTML by importing
     this file from their HTML files. -->
<link rel="import" href="my_element_nodart.html>
<script type="application/dart" src="my_element.dart"></script>
  • my_element_nodart.html:
<!-- This file contains the actual definition of the element,
     but it doesn't include any Dart script tags -->
<polymer-element name="my-element">...</polymer-element>

Implementation

Dart-to-HTML will have two implementations. One that works in Dartium without any code transformations, and another that uses transformations that can then be compiled with dart2js.

Dartium implementation

To fully comply with our semantics, we need to do two passes of static initialization: one pass to only run through each @HtmlImport and inline HTML documents, and a second pass that performs all other initializations. This will ensure that initialization is done in the proper order.

Transformer-based implementation

The transformer-based implementation simply consists on adding HTML imports to HTML files. Other transformations, such as inlining or static initialization, will be handled separately by other parts of the system, so we don't need to worry about them here.

The transformation algorithm is as follows:

  • Find all Dart script tags in a given HTML file
  • Traverse the import graph on each Dart script tag and find any @HtmlImport annotation.
  • Resolve the URI for the annotation, and add the corresponding <link rel="import"> on the HTML file
  • repeat for each HTML file in the project.