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

Side by Side Diff: pkg/polymer/lib/src/loader.dart

Issue 151893003: Use a transformer to initialize custom elements and call initMethod. This is the (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. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « pkg/polymer/lib/src/build/script_compactor.dart ('k') | pkg/polymer/pubspec.yaml » ('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 part of polymer; 5 part of polymer;
6 6
7 /** Annotation used to automatically register polymer elements. */ 7 /** Annotation used to automatically register polymer elements. */
8 class CustomTag { 8 class CustomTag {
9 final String tagName; 9 final String tagName;
10 const CustomTag(this.tagName); 10 const CustomTag(this.tagName);
11 } 11 }
12 12
13 /** 13 /**
14 * Metadata used to label static or top-level methods that are called 14 * Metadata used to label static or top-level methods that are called
15 * automatically when loading the library of a custom element. 15 * automatically when loading the library of a custom element.
16 */ 16 */
17 const initMethod = const _InitMethodAnnotation(); 17 const initMethod = const _InitMethodAnnotation();
18 18
19 /** 19 /**
20 * Initializes a polymer application as follows: 20 * Initializes a polymer application as follows:
21 * * set up up polling for observable changes 21 * * set up up polling for observable changes
22 * * initialize Model-Driven Views 22 * * initialize Model-Driven Views
23 * * Include some style to prevent flash of unstyled content (FOUC) 23 * * Include some style to prevent flash of unstyled content (FOUC)
24 * * for each library in [libraries], register custom elements labeled with 24 * * for each library included transitively from HTML and HTML imports,
25 * [CustomTag] and invoke the initialization method on it. If [libraries] 25 * register custom elements declared there (labeled with [CustomTag]) and
26 * is null, first find all libraries that need to be loaded by scanning for 26 * invoke the initialization method on it (top-level functions annotated with
27 * HTML imports in the main document. 27 * [initMethod]).
28 *
29 * The initialization on each library is a top-level function and annotated with
30 * [initMethod].
31 *
32 * The urls in [libraries] can be absolute or relative to
33 * `currentMirrorSystem().isolate.rootLibrary.uri`.
34 */ 28 */
35 Zone initPolymer() { 29 Zone initPolymer() {
30 // We use this pattern, and not the inline lazy initialization pattern, so we
31 // can help dart2js detect that _discoverInitializers can be tree-shaken for
32 // deployment (and hence all uses of dart:mirrors from this loading logic).
33 // TODO(sigmund): fix polymer's transformers so they can replace initPolymer
34 // by initPolymerOptimized.
35 if (_initializers == null) _initializers = _discoverInitializers();
36 if (_useDirtyChecking) { 36 if (_useDirtyChecking) {
37 return dirtyCheckZone()..run(_initPolymerOptimized); 37 return dirtyCheckZone()..run(initPolymerOptimized);
38 } 38 }
39 39
40 _initPolymerOptimized(); 40 return initPolymerOptimized();
41 return Zone.current;
42 } 41 }
43 42
44 /** 43 /**
45 * Same as [initPolymer], but runs the version that is optimized for deployment 44 * Same as [initPolymer], but runs the version that is optimized for deployment
46 * to the internet. The biggest difference is it omits the [Zone] that 45 * to the internet. The biggest difference is it omits the [Zone] that
47 * automatically invokes [Observable.dirtyCheck], and the list of libraries must 46 * automatically invokes [Observable.dirtyCheck], and the list of initializers
48 * be supplied instead of being dynamically searched for at runtime. 47 * must be supplied instead of being dynamically searched for at runtime using
48 * mirrors.
49 */ 49 */
50 // TODO(jmesserly): change the Polymer build step to call this directly. 50 Zone initPolymerOptimized() {
51 void _initPolymerOptimized() {
52 document.register(PolymerDeclaration._TAG, PolymerDeclaration); 51 document.register(PolymerDeclaration._TAG, PolymerDeclaration);
53 52
54 _loadLibraries(); 53 for (var initializer in _initializers) {
54 initializer();
55 }
55 56
56 // Run this after user code so they can add to Polymer.veiledElements 57 // Run this after user code so they can add to Polymer.veiledElements
57 _preventFlashOfUnstyledContent(); 58 _preventFlashOfUnstyledContent();
58 59
59 customElementsReady.then((_) => Polymer._ready.complete()); 60 customElementsReady.then((_) => Polymer._ready.complete());
61 return Zone.current;
60 } 62 }
61 63
62 /** 64 /**
63 * Configures [initPolymer] making it optimized for deployment to the internet. 65 * Configures [initPolymer] making it optimized for deployment to the internet.
64 * With this setup the list of libraries to initialize is supplied instead of 66 * With this setup the initializer list is supplied instead of being dynamically
65 * being dynamically searched for at runtime. Additionally, after this method is 67 * searched for at runtime. Additionally, after this method is called,
66 * called, [initPolymer] omits the [Zone] that automatically invokes 68 * [initPolymer] omits the [Zone] that automatically invokes
67 * [Observable.dirtyCheck]. 69 * [Observable.dirtyCheck].
68 */ 70 */
69 void configureForDeployment(List<String> libraries) { 71 void configureForDeployment(List<Function> initializers) {
70 _librariesToLoad = libraries; 72 _initializers = initializers;
71 _useDirtyChecking = false; 73 _useDirtyChecking = false;
72 } 74 }
73 75
74 /** 76 /**
75 * Libraries that will be initialized. For each library, the intialization 77 * List of initializers that by default will be executed when calling
76 * registers any type tagged with a [CustomTag] annotation and calls any 78 * initPolymer. If null, initPolymer will compute the list of initializers by
79 * crawling HTML imports, searchfing for script tags, and including an
80 * initializer for each type tagged with a [CustomTag] annotation and for each
77 * top-level method annotated with [initMethod]. The value of this field is 81 * top-level method annotated with [initMethod]. The value of this field is
78 * assigned programatically by the code generated from the polymer deploy 82 * assigned programatically by the code generated from the polymer deploy
79 * scripts. During development, the libraries are inferred by crawling HTML 83 * scripts.
80 * imports and searching for script tags.
81 */ 84 */
82 List<String> _librariesToLoad = 85 List<Function> _initializers;
83 _discoverScripts(document, window.location.href); 86
84 bool _useDirtyChecking = true; 87 bool _useDirtyChecking = true;
85 88
86 void _loadLibraries() { 89 List<Function> _discoverInitializers() {
87 for (var lib in _librariesToLoad) { 90 var initializers = [];
91 var librariesToLoad = _discoverScripts(document, window.location.href);
92 for (var lib in librariesToLoad) {
88 try { 93 try {
89 _loadLibrary(lib); 94 _loadLibrary(lib, initializers);
90 } catch (e, s) { 95 } catch (e, s) {
91 // Deliver errors async, so if a single library fails it doesn't prevent 96 // Deliver errors async, so if a single library fails it doesn't prevent
92 // other things from loading. 97 // other things from loading.
93 new Completer().completeError(e, s); 98 new Completer().completeError(e, s);
94 } 99 }
95 } 100 }
101 return initializers;
96 } 102 }
97 103
98 /** 104 /**
99 * Walks the HTML import structure to discover all script tags that are 105 * Walks the HTML import structure to discover all script tags that are
100 * implicitly loaded. This code is only used in Dartium and should only be 106 * implicitly loaded. This code is only used in Dartium and should only be
101 * called after all HTML imports are resolved. Polymer ensures this by asking 107 * called after all HTML imports are resolved. Polymer ensures this by asking
102 * users to put their Dart script tags after all HTML imports (this is checked 108 * users to put their Dart script tags after all HTML imports (this is checked
103 * by the linter, and Dartium will otherwise show an error message). 109 * by the linter, and Dartium will otherwise show an error message).
104 */ 110 */
105 List<String> _discoverScripts(Document doc, String baseUri, 111 List<String> _discoverScripts(Document doc, String baseUri,
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after
152 /** 158 /**
153 * Reads the library at [uriString] (which can be an absolute URI or a relative 159 * Reads the library at [uriString] (which can be an absolute URI or a relative
154 * URI from the root library), and: 160 * URI from the root library), and:
155 * 161 *
156 * * If present, invokes any top-level and static functions marked 162 * * If present, invokes any top-level and static functions marked
157 * with the [initMethod] annotation (in the order they appear). 163 * with the [initMethod] annotation (in the order they appear).
158 * 164 *
159 * * Registers any [PolymerElement] that is marked with the [CustomTag] 165 * * Registers any [PolymerElement] that is marked with the [CustomTag]
160 * annotation. 166 * annotation.
161 */ 167 */
162 void _loadLibrary(String uriString) { 168 void _loadLibrary(String uriString, List<Function> initializers) {
163 var uri = _rootUri.resolve(uriString); 169 var uri = _rootUri.resolve(uriString);
164 var lib = _libs[uri]; 170 var lib = _libs[uri];
165 if (_isHttpStylePackageUrl(uri)) { 171 if (_isHttpStylePackageUrl(uri)) {
166 // Use package: urls if available. This rule here is more permissive than 172 // Use package: urls if available. This rule here is more permissive than
167 // how we translate urls in polymer-build, but we expect Dartium to limit 173 // how we translate urls in polymer-build, but we expect Dartium to limit
168 // the cases where there are differences. The polymer-build issues an error 174 // the cases where there are differences. The polymer-build issues an error
169 // when using packages/ inside lib without properly stepping out all the way 175 // when using packages/ inside lib without properly stepping out all the way
170 // to the packages folder. If users don't create symlinks in the source 176 // to the packages folder. If users don't create symlinks in the source
171 // tree, then Dartium will also complain because it won't find the file seen 177 // tree, then Dartium will also complain because it won't find the file seen
172 // in an HTML import. 178 // in an HTML import.
173 var packagePath = uri.path.substring( 179 var packagePath = uri.path.substring(
174 uri.path.lastIndexOf('packages/') + 'packages/'.length); 180 uri.path.lastIndexOf('packages/') + 'packages/'.length);
175 var canonicalLib = _libs[Uri.parse('package:$packagePath')]; 181 var canonicalLib = _libs[Uri.parse('package:$packagePath')];
176 if (canonicalLib != null) { 182 if (canonicalLib != null) {
177 lib = canonicalLib; 183 lib = canonicalLib;
178 } 184 }
179 } 185 }
180 186
181 if (lib == null) { 187 if (lib == null) {
182 _loaderLog.info('$uri library not found'); 188 _loaderLog.info('$uri library not found');
183 return; 189 return;
184 } 190 }
185 191
186 // Search top-level functions marked with @initMethod 192 // Search top-level functions marked with @initMethod
187 for (var f in lib.declarations.values.where((d) => d is MethodMirror)) { 193 for (var f in lib.declarations.values.where((d) => d is MethodMirror)) {
188 _maybeInvoke(lib, f); 194 _addInitMethod(lib, f, initializers);
189 } 195 }
190 196
191 for (var c in lib.declarations.values.where((d) => d is ClassMirror)) { 197 for (var c in lib.declarations.values.where((d) => d is ClassMirror)) {
192 // Search for @CustomTag on classes 198 // Search for @CustomTag on classes
193 for (var m in c.metadata) { 199 for (var m in c.metadata) {
194 var meta = m.reflectee; 200 var meta = m.reflectee;
195 if (meta is CustomTag) { 201 if (meta is CustomTag) {
196 Polymer.register(meta.tagName, c.reflectedType); 202 initializers.add(() => Polymer.register(meta.tagName, c.reflectedType));
197 } 203 }
198 } 204 }
199 205
200 // TODO(sigmund): check also static methods marked with @initMethod. 206 // TODO(sigmund): check also static methods marked with @initMethod.
201 // This is blocked on two bugs: 207 // This is blocked on two bugs:
202 // - dartbug.com/12133 (static methods are incorrectly listed as top-level 208 // - dartbug.com/12133 (static methods are incorrectly listed as top-level
203 // in dart2js, so they end up being called twice) 209 // in dart2js, so they end up being called twice)
204 // - dartbug.com/12134 (sometimes "method.metadata" throws an exception, 210 // - dartbug.com/12134 (sometimes "method.metadata" throws an exception,
205 // we could wrap and hide those exceptions, but it's not ideal). 211 // we could wrap and hide those exceptions, but it's not ideal).
206 } 212 }
207 } 213 }
208 214
209 void _maybeInvoke(ObjectMirror obj, MethodMirror method) { 215 void _addInitMethod(ObjectMirror obj, MethodMirror method,
216 List<Function> initializers) {
210 var annotationFound = false; 217 var annotationFound = false;
211 for (var meta in method.metadata) { 218 for (var meta in method.metadata) {
212 if (identical(meta.reflectee, initMethod)) { 219 if (identical(meta.reflectee, initMethod)) {
213 annotationFound = true; 220 annotationFound = true;
214 break; 221 break;
215 } 222 }
216 } 223 }
217 if (!annotationFound) return; 224 if (!annotationFound) return;
218 if (!method.isStatic) { 225 if (!method.isStatic) {
219 print("warning: methods marked with @initMethod should be static," 226 print("warning: methods marked with @initMethod should be static,"
220 " ${method.simpleName} is not."); 227 " ${method.simpleName} is not.");
221 return; 228 return;
222 } 229 }
223 if (!method.parameters.where((p) => !p.isOptional).isEmpty) { 230 if (!method.parameters.where((p) => !p.isOptional).isEmpty) {
224 print("warning: methods marked with @initMethod should take no " 231 print("warning: methods marked with @initMethod should take no "
225 "arguments, ${method.simpleName} expects some."); 232 "arguments, ${method.simpleName} expects some.");
226 return; 233 return;
227 } 234 }
228 obj.invoke(method.simpleName, const []); 235 initializers.add(() => obj.invoke(method.simpleName, const []));
229 } 236 }
230 237
231 class _InitMethodAnnotation { 238 class _InitMethodAnnotation {
232 const _InitMethodAnnotation(); 239 const _InitMethodAnnotation();
233 } 240 }
OLDNEW
« no previous file with comments | « pkg/polymer/lib/src/build/script_compactor.dart ('k') | pkg/polymer/pubspec.yaml » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698