Chromium Code Reviews

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

Issue 162093002: fix imports link rel=stylesheet (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 6 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments.
Jump to:
View unified diff | | Annotate | Revision Log
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
11 import 'package:barback/barback.dart'; 11 import 'package:barback/barback.dart';
12 import 'package:path/path.dart' as path; 12 import 'package:path/path.dart' as path;
13 import 'package:html5lib/dom.dart' show 13 import 'package:html5lib/dom.dart' show
14 Document, DocumentFragment, Element, Node; 14 Document, DocumentFragment, Element, Node;
15 import 'package:html5lib/dom_parsing.dart' show TreeVisitor; 15 import 'package:html5lib/dom_parsing.dart' show TreeVisitor;
16 import 'package:source_maps/span.dart' show Span; 16 import 'package:source_maps/span.dart';
17 17
18 import 'code_extractor.dart'; // import just for documentation. 18 import 'code_extractor.dart'; // import just for documentation.
19 import 'common.dart'; 19 import 'common.dart';
20 20
21 class _HtmlInliner extends PolymerTransformer { 21 class _HtmlInliner extends PolymerTransformer {
22 final TransformOptions options; 22 final TransformOptions options;
23 final Transform transform; 23 final Transform transform;
24 final TransformLogger logger; 24 final TransformLogger logger;
25 final AssetId docId; 25 final AssetId docId;
26 final seen = new Set<AssetId>(); 26 final seen = new Set<AssetId>();
(...skipping 21 matching lines...)
48 } 48 }
49 49
50 // We produce a secondary asset with extra information for later phases. 50 // We produce a secondary asset with extra information for later phases.
51 transform.addOutput(new Asset.fromString( 51 transform.addOutput(new Asset.fromString(
52 docId.addExtension('.scriptUrls'), 52 docId.addExtension('.scriptUrls'),
53 JSON.encode(scriptIds, toEncodable: (id) => id.serialize()))); 53 JSON.encode(scriptIds, toEncodable: (id) => id.serialize())));
54 })); 54 }));
55 } 55 }
56 56
57 /** 57 /**
58 * Visits imports in [document] and add the imported documents to [documents]. 58 * Visits imports in [document] and add the imported documents to documents.
59 * Documents are added in the order they appear, transitive imports are added 59 * Documents are added in the order they appear, transitive imports are added
60 * first. 60 * first.
61 *
62 * Returns `true` if and only if the document was changed and should be
63 * written out.
61 */ 64 */
62 Future<bool> _visitImports(Document document, AssetId sourceId) { 65 Future<bool> _visitImports(Document document, AssetId sourceId) {
63 bool hasImports = false; 66 bool changed = false;
64 67
65 // Note: we need to preserve the import order in the generated output. 68 // Note: we need to preserve the import order in the generated output.
66 return Future.forEach(document.querySelectorAll('link'), (Element tag) { 69 return Future.forEach(document.querySelectorAll('link'), (Element tag) {
67 if (tag.attributes['rel'] != 'import') return null; 70 var rel = tag.attributes['rel'];
71 if (rel != 'import' && rel != 'stylesheet') return null;
72
68 var href = tag.attributes['href']; 73 var href = tag.attributes['href'];
69 var id = resolve(sourceId, href, transform.logger, tag.sourceSpan); 74 var id = resolve(sourceId, href, transform.logger, tag.sourceSpan,
70 hasImports = true; 75 allowAbsolute: rel == 'stylesheet');
71 76
72 tag.remove(); 77 if (rel == 'import') {
73 if (id == null || !seen.add(id) || 78 changed = true;
74 (id.package == 'polymer' && id.path == 'lib/init.html')) return null; 79 tag.remove();
80 if (id == null || !seen.add(id) ||
81 (id.package == 'polymer' && id.path == 'lib/init.html')) return null ;
Siggi Cherem (dart-lang) 2014/02/13 00:08:18 80 :-(
Jennifer Messerly 2014/02/13 06:12:52 oops, missed this. fixed. out of curiosity, why t
Siggi Cherem (dart-lang) 2014/02/13 17:46:33 Oh, this was from some old bootstrap we used to ha
Jennifer Messerly 2014/02/13 20:43:45 awesome. done!
75 82
76 return _inlineImport(id); 83 return _inlineImport(id);
77 }).then((_) => hasImports); 84
85 } else if (rel == 'stylesheet') {
86 if (id == null) return null;
87 changed = true;
88 return _inlineStylesheet(id, tag);
89 }
90 }).then((_) => changed);
78 } 91 }
79 92
80 // Loads an asset identified by [id], visits its imports and collects its 93 // Loads an asset identified by [id], visits its imports and collects its
81 // html imports. Then inlines it into the main document. 94 // html imports. Then inlines it into the main document.
82 Future _inlineImport(AssetId id) => 95 Future _inlineImport(AssetId id) =>
83 readAsHtml(id, transform).then((doc) => _visitImports(doc, id).then((_) { 96 readAsHtml(id, transform).then((doc) => _visitImports(doc, id).then((_) {
84 97
85 new _UrlNormalizer(transform, id).visit(doc); 98 new _UrlNormalizer(transform, id).visit(doc);
86 _extractScripts(doc); 99 _extractScripts(doc);
87 100
88 // TODO(jmesserly): figure out how this is working in vulcanizer. 101 // TODO(jmesserly): figure out how this is working in vulcanizer.
89 // Do they produce a <body> tag with a <head> and <body> inside? 102 // Do they produce a <body> tag with a <head> and <body> inside?
90 imported.nodes 103 imported.nodes..addAll(doc.head.nodes)..addAll(doc.body.nodes);
91 ..addAll(doc.head.nodes)
92 ..addAll(doc.body.nodes);
93 })); 104 }));
94 105
106 Future _inlineStylesheet(AssetId id, Element link) =>
Siggi Cherem (dart-lang) 2014/02/13 00:08:18 the formatting mixing => + then below is a bit odd
Jennifer Messerly 2014/02/13 06:11:22 okay, I'll change this one. But, I'm think we shou
107 readAsString(id, transform).then((css) {
108
109 css = new _UrlNormalizer(transform, id).visitCss(css);
110 link.replaceWith(new Element.tag('style')..text = css);
111 });
112
95 /** 113 /**
96 * Split Dart script tags from all the other elements. Now that Dartium 114 * Split Dart script tags from all the other elements. Now that Dartium
97 * only allows a single script tag per page, we can't inline script 115 * only allows a single script tag per page, we can't inline script
98 * tags. Instead, we collect the urls of each script tag so we import 116 * tags. Instead, we collect the urls of each script tag so we import
99 * them directly from the Dart bootstrap code. 117 * them directly from the Dart bootstrap code.
100 */ 118 */
101 void _extractScripts(Document document) { 119 void _extractScripts(Document document) {
102 bool first = true; 120 bool first = true;
103 for (var script in document.querySelectorAll('script')) { 121 for (var script in document.querySelectorAll('script')) {
104 if (script.attributes['type'] == 'application/dart') { 122 if (script.attributes['type'] == 'application/dart') {
(...skipping 60 matching lines...)
165 if (_urlAttributes.contains(key)) { 183 if (_urlAttributes.contains(key)) {
166 var url = node.attributes[key]; 184 var url = node.attributes[key];
167 if (url != null && url != '' && !url.startsWith('{{')) { 185 if (url != null && url != '' && !url.startsWith('{{')) {
168 node.attributes[key] = _newUrl(url, node.sourceSpan); 186 node.attributes[key] = _newUrl(url, node.sourceSpan);
169 } 187 }
170 } 188 }
171 } 189 }
172 super.visitElement(node); 190 super.visitElement(node);
173 } 191 }
174 192
193 static final _URL = new RegExp(r'url\(([^)]*)\)', multiLine: true);
194 static final _QUOTE = new RegExp('["\']', multiLine: true);
195
196 /** Visit the CSS text and replace any relative URLs so we can inline it. */
197 // Ported from:
198 // https://github.com/Polymer/vulcanize/blob/c14f63696797cda18dc3d372b78aa3378 acc691f/lib/vulcan.js#L149
199 // TODO(jmesserly): use csslib here instead? Parsing with RegEx is sadness.
200 // Maybe it's reliable enough for finding URLs in CSS? I'm not sure.
201 String visitCss(String cssText) {
202 var src = new SourceFile.text(sourceId.path, cssText);
203 return cssText.replaceAllMapped(_URL, (match) {
204 // Extract the URL, without any surrounding quotes.
205 var span = src.span(match.start, match.end);
206 var href = match[1].replaceAll(_QUOTE, '');
207 href = _newUrl(href, span);
208 return 'url($href)';
209 });
210 }
211
175 _newUrl(String href, Span span) { 212 _newUrl(String href, Span span) {
176 var uri = Uri.parse(href); 213 var uri = Uri.parse(href);
177 if (uri.isAbsolute) return href; 214 if (uri.isAbsolute) return href;
178 if (!uri.scheme.isEmpty) return href; 215 if (!uri.scheme.isEmpty) return href;
179 if (!uri.host.isEmpty) return href; 216 if (!uri.host.isEmpty) return href;
180 if (uri.path.isEmpty) return href; // Implies standalone ? or # in URI. 217 if (uri.path.isEmpty) return href; // Implies standalone ? or # in URI.
181 if (path.isAbsolute(href)) return href; 218 if (path.isAbsolute(href)) return href;
182 219
183 var id = resolve(sourceId, href, transform.logger, span); 220 var id = resolve(sourceId, href, transform.logger, span);
184 if (id == null) return href; 221 if (id == null) return href;
(...skipping 33 matching lines...)
218 'cite', // in blockquote, del, ins, q 255 'cite', // in blockquote, del, ins, q
219 'data', // in object 256 'data', // in object
220 'formaction', // in button, input 257 'formaction', // in button, input
221 'href', // in a, area, link, base, command 258 'href', // in a, area, link, base, command
222 'icon', // in command 259 'icon', // in command
223 'manifest', // in html 260 'manifest', // in html
224 'poster', // in video 261 'poster', // in video
225 'src', // in audio, embed, iframe, img, input, script, source, track, 262 'src', // in audio, embed, iframe, img, input, script, source, track,
226 // video 263 // video
227 ]; 264 ];
OLDNEW

Powered by Google App Engine