Index: pkg/polymer/lib/src/build/import_inliner.dart |
diff --git a/pkg/polymer/lib/src/build/import_inliner.dart b/pkg/polymer/lib/src/build/import_inliner.dart |
index d58afcaef53fea337ba48e4614a5639d9c1dc8c7..d80adc11b6e6af52551e9a37631c8bdbc4585bd1 100644 |
--- a/pkg/polymer/lib/src/build/import_inliner.dart |
+++ b/pkg/polymer/lib/src/build/import_inliner.dart |
@@ -24,9 +24,11 @@ class _HtmlInliner extends PolymerTransformer { |
final TransformLogger logger; |
final AssetId docId; |
final seen = new Set<AssetId>(); |
- final imported = new DocumentFragment(); |
final scriptIds = <AssetId>[]; |
+ static const TYPE_DART = 'application/dart'; |
+ static const TYPE_JS = 'text/javascript'; |
+ |
_HtmlInliner(this.options, Transform transform) |
: transform = transform, |
logger = transform.logger, |
@@ -40,12 +42,11 @@ class _HtmlInliner extends PolymerTransformer { |
return readPrimaryAsHtml(transform).then((document) => |
_visitImports(document, docId).then((importsFound) { |
+ var output = transform.primaryInput; |
if (importsFound) { |
- document.body.insertBefore(imported, document.body.firstChild); |
- transform.addOutput(new Asset.fromString(docId, document.outerHtml)); |
- } else { |
- transform.addOutput(transform.primaryInput); |
+ output = new Asset.fromString(docId, document.outerHtml); |
} |
+ transform.addOutput(output); |
// We produce a secondary asset with extra information for later phases. |
transform.addOutput(new Asset.fromString( |
@@ -65,6 +66,8 @@ class _HtmlInliner extends PolymerTransformer { |
Future<bool> _visitImports(Document document, AssetId sourceId) { |
bool changed = false; |
+ _moveHeadToBody(document); |
+ |
// Note: we need to preserve the import order in the generated output. |
return Future.forEach(document.querySelectorAll('link'), (Element tag) { |
var rel = tag.attributes['rel']; |
@@ -76,21 +79,53 @@ class _HtmlInliner extends PolymerTransformer { |
if (rel == 'import') { |
changed = true; |
- tag.remove(); |
- if (id == null || !seen.add(id)) return null; |
- return _inlineImport(id); |
+ if (id == null || !seen.add(id)) { |
+ tag.remove(); |
+ return null; |
+ } |
+ return _inlineImport(id, tag); |
} else if (rel == 'stylesheet') { |
if (id == null) return null; |
changed = true; |
+ |
return _inlineStylesheet(id, tag); |
} |
}).then((_) => changed); |
} |
+ /** |
+ * To preserve the order of scripts with respect to inlined |
+ * link rel=import, we move both of those into the body before we do any |
+ * inlining. |
+ * |
+ * Note: we do this for stylesheets as well to preserve ordering with |
+ * respect to eachother, because stylesheets can be pulled in transitively |
+ * from imports. |
+ */ |
+ // TODO(jmesserly): vulcanizer doesn't need this because they inline JS |
+ // scripts, causing them to be naturally moved as part of the inlining. |
+ // Should we do the same? Alternatively could we inline head into head and |
+ // body into body and avoid this whole thing? |
+ void _moveHeadToBody(Document doc) { |
+ var insertionPoint = doc.body.firstChild; |
+ for (var node in doc.head.nodes.toList(growable: false)) { |
+ if (node is! Element) continue; |
+ var tag = node.tagName; |
+ var type = node.attributes['type']; |
+ var rel = node.attributes['rel']; |
+ if (tag == 'style' || tag == 'script' && |
+ (type == null || type == TYPE_JS || type == TYPE_DART) || |
+ tag == 'link' && (rel == 'stylesheet' || rel == 'import')) { |
+ // Move the node into the body, where its contents will be placed. |
+ doc.body.insertBefore(node, insertionPoint); |
+ } |
+ } |
+ } |
+ |
// Loads an asset identified by [id], visits its imports and collects its |
// html imports. Then inlines it into the main document. |
- Future _inlineImport(AssetId id) => |
+ Future _inlineImport(AssetId id, Element link) => |
readAsHtml(id, transform).then((doc) => _visitImports(doc, id).then((_) { |
new _UrlNormalizer(transform, id).visit(doc); |
@@ -98,7 +133,9 @@ class _HtmlInliner extends PolymerTransformer { |
// TODO(jmesserly): figure out how this is working in vulcanizer. |
// Do they produce a <body> tag with a <head> and <body> inside? |
+ var imported = new DocumentFragment(); |
imported.nodes..addAll(doc.head.nodes)..addAll(doc.body.nodes); |
+ link.replaceWith(imported); |
Siggi Cherem (dart-lang)
2014/02/20 03:50:55
not sure I follow, why not remove the link node?
Jennifer Messerly
2014/02/20 03:59:08
replaceWith should remove it & replace it with the
Siggi Cherem (dart-lang)
2014/02/20 04:37:19
Sorry, I saw the added lines, and for some reason
|
})); |
Future _inlineStylesheet(AssetId id, Element link) { |
@@ -118,7 +155,7 @@ class _HtmlInliner extends PolymerTransformer { |
void _extractScripts(Document document) { |
bool first = true; |
for (var script in document.querySelectorAll('script')) { |
- if (script.attributes['type'] == 'application/dart') { |
+ if (script.attributes['type'] == TYPE_DART) { |
script.remove(); |
// only one Dart script per document is supported in Dartium. |