Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(73)

Side by Side Diff: pkg/polymer/lib/src/build/import_inliner.dart

Issue 575503002: When inlining imports from head, put them inside a hidden div (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: move/clarify comment Created 6 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « no previous file | pkg/polymer/lib/src/build/linter.dart » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a 2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file. 3 // BSD-style license that can be found in the LICENSE file.
4 4
5 /// Transfomer that inlines polymer-element definitions from html imports. 5 /// Transfomer that inlines polymer-element definitions from html imports.
6 library polymer.src.build.import_inliner; 6 library polymer.src.build.import_inliner;
7 7
8 import 'dart:async'; 8 import 'dart:async';
9 import 'dart:convert'; 9 import 'dart:convert';
10 10
(...skipping 15 matching lines...) Expand all
26 // TODO(sigmund): move to web_components package (dartbug.com/18037). 26 // TODO(sigmund): move to web_components package (dartbug.com/18037).
27 class _HtmlInliner extends PolymerTransformer { 27 class _HtmlInliner extends PolymerTransformer {
28 final TransformOptions options; 28 final TransformOptions options;
29 final Transform transform; 29 final Transform transform;
30 final BuildLogger logger; 30 final BuildLogger logger;
31 final AssetId docId; 31 final AssetId docId;
32 final seen = new Set<AssetId>(); 32 final seen = new Set<AssetId>();
33 final scriptIds = <AssetId>[]; 33 final scriptIds = <AssetId>[];
34 final extractedFiles = new Set<AssetId>(); 34 final extractedFiles = new Set<AssetId>();
35 bool experimentalBootstrap = false; 35 bool experimentalBootstrap = false;
36 final Element importsWrapper = new Element.html('<div hidden></div>');
36 37
37 /// The number of extracted inline Dart scripts. Used as a counter to give 38 /// The number of extracted inline Dart scripts. Used as a counter to give
38 /// unique-ish filenames. 39 /// unique-ish filenames.
39 int inlineScriptCounter = 0; 40 int inlineScriptCounter = 0;
40 41
41 _HtmlInliner(TransformOptions options, Transform transform) 42 _HtmlInliner(TransformOptions options, Transform transform)
42 : options = options, 43 : options = options,
43 transform = transform, 44 transform = transform,
44 logger = new BuildLogger(transform, 45 logger = new BuildLogger(transform,
45 convertErrorsToWarnings: !options.releaseMode, 46 convertErrorsToWarnings: !options.releaseMode,
46 detailsUri: 'http://goo.gl/5HPeuP'), 47 detailsUri: 'http://goo.gl/5HPeuP'),
47 docId = transform.primaryInput.id; 48 docId = transform.primaryInput.id;
48 49
49 Future apply() { 50 Future apply() {
50 seen.add(docId); 51 seen.add(docId);
51 52
52 Document document; 53 Document document;
53 bool changed = false; 54 bool changed = false;
54 55
55 return readPrimaryAsHtml(transform, logger).then((doc) { 56 return readPrimaryAsHtml(transform, logger).then((doc) {
56 document = doc; 57 document = doc;
58
59 // Insert our importsWrapper. This may be removed later if not needed, but
60 // it makes the logic simpler to have it in the document.
61 document.body.insertBefore(importsWrapper, document.body.firstChild);
62
57 changed = new _UrlNormalizer(transform, docId, logger).visit(document) 63 changed = new _UrlNormalizer(transform, docId, logger).visit(document)
58 || changed; 64 || changed;
59 65
60 experimentalBootstrap = document.querySelectorAll('link').any((link) => 66 experimentalBootstrap = document.querySelectorAll('link').any((link) =>
61 link.attributes['rel'] == 'import' && 67 link.attributes['rel'] == 'import' &&
62 link.attributes['href'] == POLYMER_EXPERIMENTAL_HTML); 68 link.attributes['href'] == POLYMER_EXPERIMENTAL_HTML);
63 changed = _extractScripts(document) || changed; 69 changed = _extractScripts(document) || changed;
70
71 // We only need to move the head into the body for the entry point.
72 _moveHeadToBody(document);
73
64 return _visitImports(document); 74 return _visitImports(document);
65 }).then((importsFound) { 75 }).then((importsFound) {
66 changed = changed || importsFound; 76 changed = changed || importsFound;
77
67 return _removeScripts(document); 78 return _removeScripts(document);
68 }).then((scriptsRemoved) { 79 }).then((scriptsRemoved) {
69 changed = changed || scriptsRemoved; 80 changed = changed || scriptsRemoved;
70 81
82 // Remove the importsWrapper if it contains nothing. Wait until now to do
83 // this since it might have a script that got removed, and thus no longer
84 // have any children.
85 if (importsWrapper.children.isEmpty) importsWrapper.remove();
86
71 var output = transform.primaryInput; 87 var output = transform.primaryInput;
72 if (changed) output = new Asset.fromString(docId, document.outerHtml); 88 if (changed) output = new Asset.fromString(docId, document.outerHtml);
73 transform.addOutput(output); 89 transform.addOutput(output);
74 90
75 // We produce a secondary asset with extra information for later phases. 91 // We produce a secondary asset with extra information for later phases.
76 transform.addOutput(new Asset.fromString( 92 transform.addOutput(new Asset.fromString(
77 docId.addExtension('._data'), 93 docId.addExtension('._data'),
78 JSON.encode({ 94 JSON.encode({
79 'experimental_bootstrap': experimentalBootstrap, 95 'experimental_bootstrap': experimentalBootstrap,
80 'script_ids': scriptIds, 96 'script_ids': scriptIds,
81 }, toEncodable: (id) => id.serialize()))); 97 }, toEncodable: (id) => id.serialize())));
82 98
83 // Write out the logs collected by our [BuildLogger]. 99 // Write out the logs collected by our [BuildLogger].
84 if (options.injectBuildLogsInOutput) { 100 if (options.injectBuildLogsInOutput) {
85 return logger.writeOutput(); 101 return logger.writeOutput();
86 } 102 }
87 }); 103 });
88 } 104 }
89 105
90 /// Visits imports in [document] and add the imported documents to documents. 106 /// Visits imports in [document] and add the imported documents to documents.
91 /// Documents are added in the order they appear, transitive imports are added 107 /// Documents are added in the order they appear, transitive imports are added
92 /// first. 108 /// first.
93 /// 109 ///
94 /// Returns `true` if and only if the document was changed and should be 110 /// Returns `true` if and only if the document was changed and should be
95 /// written out. 111 /// written out.
96 Future<bool> _visitImports(Document document) { 112 Future<bool> _visitImports(Document document) {
97 bool changed = false; 113 bool changed = false;
98 114
99 _moveHeadToBody(document);
100
101 // Note: we need to preserve the import order in the generated output. 115 // Note: we need to preserve the import order in the generated output.
102 return Future.forEach(document.querySelectorAll('link'), (Element tag) { 116 return Future.forEach(document.querySelectorAll('link'), (Element tag) {
103 var rel = tag.attributes['rel']; 117 var rel = tag.attributes['rel'];
104 if (rel != 'import' && rel != 'stylesheet') return null; 118 if (rel != 'import' && rel != 'stylesheet') return null;
105 119
106 // Note: URL has already been normalized so use docId. 120 // Note: URL has already been normalized so use docId.
107 var href = tag.attributes['href']; 121 var href = tag.attributes['href'];
108 var id = uriToAssetId(docId, href, logger, tag.sourceSpan, 122 var id = uriToAssetId(docId, href, logger, tag.sourceSpan,
109 errorOnAbsolute: rel != 'stylesheet'); 123 errorOnAbsolute: rel != 'stylesheet');
110 124
(...skipping 20 matching lines...) Expand all
131 /// inlining. 145 /// inlining.
132 /// 146 ///
133 /// Note: we do this for stylesheets as well to preserve ordering with 147 /// Note: we do this for stylesheets as well to preserve ordering with
134 /// respect to eachother, because stylesheets can be pulled in transitively 148 /// respect to eachother, because stylesheets can be pulled in transitively
135 /// from imports. 149 /// from imports.
136 // TODO(jmesserly): vulcanizer doesn't need this because they inline JS 150 // TODO(jmesserly): vulcanizer doesn't need this because they inline JS
137 // scripts, causing them to be naturally moved as part of the inlining. 151 // scripts, causing them to be naturally moved as part of the inlining.
138 // Should we do the same? Alternatively could we inline head into head and 152 // Should we do the same? Alternatively could we inline head into head and
139 // body into body and avoid this whole thing? 153 // body into body and avoid this whole thing?
140 void _moveHeadToBody(Document doc) { 154 void _moveHeadToBody(Document doc) {
141 var insertionPoint = doc.body.firstChild;
142 for (var node in doc.head.nodes.toList(growable: false)) { 155 for (var node in doc.head.nodes.toList(growable: false)) {
143 if (node is! Element) continue; 156 if (node is! Element) continue;
144 var tag = node.localName; 157 var tag = node.localName;
145 var type = node.attributes['type']; 158 var type = node.attributes['type'];
146 var rel = node.attributes['rel']; 159 var rel = node.attributes['rel'];
147 if (tag == 'style' || tag == 'script' && 160 if (tag == 'style' || tag == 'script' &&
148 (type == null || type == TYPE_JS || type == TYPE_DART) || 161 (type == null || type == TYPE_JS || type == TYPE_DART) ||
149 tag == 'link' && (rel == 'stylesheet' || rel == 'import')) { 162 tag == 'link' && (rel == 'stylesheet' || rel == 'import')) {
150 // Move the node into the body, where its contents will be placed. 163 // Move the node into the importsWrapper, where its contents will be
151 doc.body.insertBefore(node, insertionPoint); 164 // placed. This wrapper is a hidden div to prevent inlined html from
165 // causing a FOUC.
166 importsWrapper.append(node);
152 } 167 }
153 } 168 }
154 } 169 }
155 170
156 /// Loads an asset identified by [id], visits its imports and collects its 171 /// Loads an asset identified by [id], visits its imports and collects its
157 /// html imports. Then inlines it into the main document. 172 /// html imports. Then inlines it into the main document.
158 Future _inlineImport(AssetId id, Element link) { 173 Future _inlineImport(AssetId id, Element link) {
159 return readAsHtml(id, transform, logger).catchError((error) { 174 return readAsHtml(id, transform, logger).catchError((error) {
160 logger.error(INLINE_IMPORT_FAIL.create({'error': error}), 175 logger.error(INLINE_IMPORT_FAIL.create({'error': error}),
161 span: link.sourceSpan); 176 span: link.sourceSpan);
(...skipping 362 matching lines...) Expand 10 before | Expand all | Expand 10 after
524 /// style tag except these ones. 539 /// style tag except these ones.
525 const IGNORED_LINKED_STYLE_ATTRS = 540 const IGNORED_LINKED_STYLE_ATTRS =
526 const ['charset', 'href', 'href-lang', 'rel', 'rev']; 541 const ['charset', 'href', 'href-lang', 'rel', 'rev'];
527 542
528 /// Global RegExp objects. 543 /// Global RegExp objects.
529 final _INVALID_LIB_CHARS_REGEX = new RegExp('[^a-z0-9_]'); 544 final _INVALID_LIB_CHARS_REGEX = new RegExp('[^a-z0-9_]');
530 final _NUM_REGEX = new RegExp('[0-9]'); 545 final _NUM_REGEX = new RegExp('[0-9]');
531 final _BINDING_REGEX = new RegExp(r'(({{.*}})|(\[\[.*\]\]))'); 546 final _BINDING_REGEX = new RegExp(r'(({{.*}})|(\[\[.*\]\]))');
532 547
533 _getSpan(SourceFile file, AstNode node) => file.span(node.offset, node.end); 548 _getSpan(SourceFile file, AstNode node) => file.span(node.offset, node.end);
OLDNEW
« no previous file with comments | « no previous file | pkg/polymer/lib/src/build/linter.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698