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

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: trying upload again Created 6 years, 10 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
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...) Expand all
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')) {
82 return null;
83 }
84 return _inlineImport(id);
75 85
76 return _inlineImport(id); 86 } else if (rel == 'stylesheet') {
77 }).then((_) => hasImports); 87 if (id == null) return null;
88 changed = true;
89 return _inlineStylesheet(id, tag);
90 }
91 }).then((_) => changed);
78 } 92 }
79 93
80 // Loads an asset identified by [id], visits its imports and collects its 94 // Loads an asset identified by [id], visits its imports and collects its
81 // html imports. Then inlines it into the main document. 95 // html imports. Then inlines it into the main document.
82 Future _inlineImport(AssetId id) => 96 Future _inlineImport(AssetId id) =>
83 readAsHtml(id, transform).then((doc) => _visitImports(doc, id).then((_) { 97 readAsHtml(id, transform).then((doc) => _visitImports(doc, id).then((_) {
84 98
85 new _UrlNormalizer(transform, id).visit(doc); 99 new _UrlNormalizer(transform, id).visit(doc);
86 _extractScripts(doc); 100 _extractScripts(doc);
87 101
88 // TODO(jmesserly): figure out how this is working in vulcanizer. 102 // TODO(jmesserly): figure out how this is working in vulcanizer.
89 // Do they produce a <body> tag with a <head> and <body> inside? 103 // Do they produce a <body> tag with a <head> and <body> inside?
90 imported.nodes 104 imported.nodes..addAll(doc.head.nodes)..addAll(doc.body.nodes);
91 ..addAll(doc.head.nodes)
92 ..addAll(doc.body.nodes);
93 })); 105 }));
94 106
107 Future _inlineStylesheet(AssetId id, Element link) {
108 return transform.readInputAsString(id).then((css) {
109 var url = getAssetUrl(id, transform);
110 css = new _UrlNormalizer(transform, id).visitCss(css, url);
111 link.replaceWith(new Element.tag('style')..text = css);
112 });
113 }
114
95 /** 115 /**
96 * Split Dart script tags from all the other elements. Now that Dartium 116 * 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 117 * 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 118 * tags. Instead, we collect the urls of each script tag so we import
99 * them directly from the Dart bootstrap code. 119 * them directly from the Dart bootstrap code.
100 */ 120 */
101 void _extractScripts(Document document) { 121 void _extractScripts(Document document) {
102 bool first = true; 122 bool first = true;
103 for (var script in document.querySelectorAll('script')) { 123 for (var script in document.querySelectorAll('script')) {
104 if (script.attributes['type'] == 'application/dart') { 124 if (script.attributes['type'] == 'application/dart') {
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after
165 if (_urlAttributes.contains(key)) { 185 if (_urlAttributes.contains(key)) {
166 var url = node.attributes[key]; 186 var url = node.attributes[key];
167 if (url != null && url != '' && !url.startsWith('{{')) { 187 if (url != null && url != '' && !url.startsWith('{{')) {
168 node.attributes[key] = _newUrl(url, node.sourceSpan); 188 node.attributes[key] = _newUrl(url, node.sourceSpan);
169 } 189 }
170 } 190 }
171 } 191 }
172 super.visitElement(node); 192 super.visitElement(node);
173 } 193 }
174 194
195 static final _URL = new RegExp(r'url\(([^)]*)\)', multiLine: true);
196 static final _QUOTE = new RegExp('["\']', multiLine: true);
197
198 /** Visit the CSS text and replace any relative URLs so we can inline it. */
199 // Ported from:
200 // https://github.com/Polymer/vulcanize/blob/c14f63696797cda18dc3d372b78aa3378 acc691f/lib/vulcan.js#L149
201 // TODO(jmesserly): use csslib here instead? Parsing with RegEx is sadness.
202 // Maybe it's reliable enough for finding URLs in CSS? I'm not sure.
203 String visitCss(String cssText, String url) {
204 var src = new SourceFile.text(url, cssText);
205 return cssText.replaceAllMapped(_URL, (match) {
206 // Extract the URL, without any surrounding quotes.
207 var span = src.span(match.start, match.end);
208 var href = match[1].replaceAll(_QUOTE, '');
209 href = _newUrl(href, span);
210 return 'url($href)';
211 });
212 }
213
175 _newUrl(String href, Span span) { 214 _newUrl(String href, Span span) {
176 var uri = Uri.parse(href); 215 var uri = Uri.parse(href);
177 if (uri.isAbsolute) return href; 216 if (uri.isAbsolute) return href;
178 if (!uri.scheme.isEmpty) return href; 217 if (!uri.scheme.isEmpty) return href;
179 if (!uri.host.isEmpty) return href; 218 if (!uri.host.isEmpty) return href;
180 if (uri.path.isEmpty) return href; // Implies standalone ? or # in URI. 219 if (uri.path.isEmpty) return href; // Implies standalone ? or # in URI.
181 if (path.isAbsolute(href)) return href; 220 if (path.isAbsolute(href)) return href;
182 221
183 var id = resolve(sourceId, href, transform.logger, span); 222 var id = resolve(sourceId, href, transform.logger, span);
184 if (id == null) return href; 223 if (id == null) return href;
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after
218 'cite', // in blockquote, del, ins, q 257 'cite', // in blockquote, del, ins, q
219 'data', // in object 258 'data', // in object
220 'formaction', // in button, input 259 'formaction', // in button, input
221 'href', // in a, area, link, base, command 260 'href', // in a, area, link, base, command
222 'icon', // in command 261 'icon', // in command
223 'manifest', // in html 262 'manifest', // in html
224 'poster', // in video 263 'poster', // in video
225 'src', // in audio, embed, iframe, img, input, script, source, track, 264 'src', // in audio, embed, iframe, img, input, script, source, track,
226 // video 265 // video
227 ]; 266 ];
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698