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

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

Issue 189213003: Refactoring two pieces of polymer: (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 6 years, 9 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) 2014, 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 /// Contains logic to initialize polymer apps during development. This
6 /// implementation uses dart:mirrors to load each library as they are discovered
7 /// through HTML imports. This is only meant to be during development in
8 /// dartium, and the polymer transformers replace this implementation with
9 /// codege generation in the polymer-build steps.
10 library polymer.src.mirror_loader;
6 11
7 /// Annotation used to automatically register polymer elements. 12 import 'dart:async';
8 class CustomTag { 13 import 'dart:html';
9 final String tagName;
10 const CustomTag(this.tagName);
11 }
12 14
13 /// Metadata used to label static or top-level methods that are called 15 // Technically, we shouldn't need any @MirrorsUsed, since this is for
14 /// automatically when loading the library of a custom element. 16 // development only, but our test bots don't yet run pub-build. See more details
15 const initMethod = const _InitMethodAnnotation(); 17 // on the comments of the mirrors import in `lib/polymer.dart`.
18 @MirrorsUsed(metaTargets:
19 const [CustomTag, InitMethodAnnotation],
20 override: const ['smoke.mirrors', 'polymer.src.mirror_loader'])
21 import 'dart:mirrors';
16 22
17 /// Initializes a polymer application as follows: 23 import 'package:logging/logging.dart' show Logger;
18 /// * set up up polling for observable changes 24 import 'package:polymer/polymer.dart' show
19 /// * initialize Model-Driven Views 25 InitMethodAnnotation, CustomTag, initMethod, Polymer;
20 /// * Include some style to prevent flash of unstyled content (FOUC)
21 /// * for each library included transitively from HTML and HTML imports,
22 /// register custom elements declared there (labeled with [CustomTag]) and
23 /// invoke the initialization method on it (top-level functions annotated with
24 /// [initMethod]).
25 Zone initPolymer() {
26 // We use this pattern, and not the inline lazy initialization pattern, so we
27 // can help dart2js detect that _discoverInitializers can be tree-shaken for
28 // deployment (and hence all uses of dart:mirrors from this loading logic).
29 // TODO(sigmund): fix polymer's transformers so they can replace initPolymer
30 // by initPolymerOptimized.
31 if (_initializers == null) _initializers = _discoverInitializers();
32 26
33 // In deployment mode, we rely on change notifiers instead of dirty checking.
34 if (!_deployMode) {
35 return dirtyCheckZone()..run(initPolymerOptimized);
36 }
37 27
38 return initPolymerOptimized(); 28 /// Set of initializers that are invoked by `initPolymer`. This is computed the
39 } 29 /// list by crawling HTML imports, searching for script tags, and including an
40
41 /// Same as [initPolymer], but runs the version that is optimized for deployment
42 /// to the internet. The biggest difference is it omits the [Zone] that
43 /// automatically invokes [Observable.dirtyCheck], and the list of initializers
44 /// must be supplied instead of being dynamically searched for at runtime using
45 /// mirrors.
46 Zone initPolymerOptimized() {
47 // TODO(sigmund): refactor this so we can replace it by codegen.
48 smoke.useMirrors();
49 _hookJsPolymer();
50
51 for (var initializer in _initializers) {
52 initializer();
53 }
54
55 return Zone.current;
56 }
57
58 /// Configures [initPolymer] making it optimized for deployment to the internet.
59 /// With this setup the initializer list is supplied instead of searched for
60 /// at runtime. Additionally, after this method is called [initPolymer] omits
61 /// the [Zone] that automatically invokes [Observable.dirtyCheck].
62 void configureForDeployment(List<Function> initializers) {
63 _initializers = initializers;
64 _deployMode = true;
65 }
66
67 /// List of initializers that by default will be executed when calling
68 /// initPolymer. If null, initPolymer will compute the list of initializers by
69 /// crawling HTML imports, searchfing for script tags, and including an
70 /// initializer for each type tagged with a [CustomTag] annotation and for each 30 /// initializer for each type tagged with a [CustomTag] annotation and for each
71 /// top-level method annotated with [initMethod]. The value of this field is 31 /// top-level method annotated with [initMethod].
72 /// assigned programatically by the code generated from the polymer deploy 32 List<Function> initializers = _discoverInitializers();
73 /// scripts.
74 List<Function> _initializers;
75 33
76 /// True if we're in deployment mode. 34 /// True if we're in deployment mode.
77 bool _deployMode = false; 35 bool deployMode = false;
78 36
37 /// Discovers what script tags are loaded from HTML pages and collects the
38 /// initializers of their corresponding libraries.
79 List<Function> _discoverInitializers() { 39 List<Function> _discoverInitializers() {
80 var initializers = []; 40 var initializers = [];
81 var librariesToLoad = _discoverScripts(document, window.location.href); 41 var librariesToLoad = _discoverScripts(document, window.location.href);
82 for (var lib in librariesToLoad) { 42 for (var lib in librariesToLoad) {
83 try { 43 try {
84 _loadLibrary(lib, initializers); 44 _loadLibrary(lib, initializers);
85 } catch (e, s) { 45 } catch (e, s) {
86 // Deliver errors async, so if a single library fails it doesn't prevent 46 // Deliver errors async, so if a single library fails it doesn't prevent
87 // other things from loading. 47 // other things from loading.
88 new Completer().completeError(e, s); 48 new Completer().completeError(e, s);
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after
125 return scripts; 85 return scripts;
126 } 86 }
127 87
128 /// All libraries in the current isolate. 88 /// All libraries in the current isolate.
129 final _libs = currentMirrorSystem().libraries; 89 final _libs = currentMirrorSystem().libraries;
130 90
131 // TODO(sigmund): explore other (cheaper) ways to resolve URIs relative to the 91 // TODO(sigmund): explore other (cheaper) ways to resolve URIs relative to the
132 // root library (see dartbug.com/12612) 92 // root library (see dartbug.com/12612)
133 final _rootUri = currentMirrorSystem().isolate.rootLibrary.uri; 93 final _rootUri = currentMirrorSystem().isolate.rootLibrary.uri;
134 94
135 final Logger _loaderLog = new Logger('polymer.loader'); 95 final Logger _loaderLog = new Logger('polymer.src.mirror_loader');
136 96
137 bool _isHttpStylePackageUrl(Uri uri) { 97 bool _isHttpStylePackageUrl(Uri uri) {
138 var uriPath = uri.path; 98 var uriPath = uri.path;
139 return uri.scheme == _rootUri.scheme && 99 return uri.scheme == _rootUri.scheme &&
140 // Don't process cross-domain uris. 100 // Don't process cross-domain uris.
141 uri.authority == _rootUri.authority && 101 uri.authority == _rootUri.authority &&
142 uriPath.endsWith('.dart') && 102 uriPath.endsWith('.dart') &&
143 (uriPath.contains('/packages/') || uriPath.startsWith('packages/')); 103 (uriPath.contains('/packages/') || uriPath.startsWith('packages/'));
144 } 104 }
145 105
(...skipping 98 matching lines...) Expand 10 before | Expand all | Expand 10 after
244 " ${method.simpleName} is not."); 204 " ${method.simpleName} is not.");
245 return; 205 return;
246 } 206 }
247 if (!method.parameters.where((p) => !p.isOptional).isEmpty) { 207 if (!method.parameters.where((p) => !p.isOptional).isEmpty) {
248 print("warning: methods marked with @initMethod should take no " 208 print("warning: methods marked with @initMethod should take no "
249 "arguments, ${method.simpleName} expects some."); 209 "arguments, ${method.simpleName} expects some.");
250 return; 210 return;
251 } 211 }
252 initializers.add(() => obj.invoke(method.simpleName, const [])); 212 initializers.add(() => obj.invoke(method.simpleName, const []));
253 } 213 }
254
255 class _InitMethodAnnotation {
256 const _InitMethodAnnotation();
257 }
258
259 /// To ensure Dart can interoperate with polymer-element registered by
260 /// polymer.js, we need to be able to execute Dart code if we are registering
261 /// a Dart class for that element. We trigger Dart logic by patching
262 /// polymer-element's register function and:
263 ///
264 /// * if it has a Dart class, run PolymerDeclaration's register.
265 /// * otherwise it is a JS prototype, run polymer-element's normal register.
266 void _hookJsPolymer() {
267 var polymerJs = js.context['Polymer'];
268 if (polymerJs == null) {
269 throw new StateError('polymer.js must be loaded before polymer.dart, please'
270 ' add <link rel="import" href="packages/polymer/polymer.html"> to your'
271 ' <head> before any Dart scripts. Alternatively you can get a different'
272 ' version of polymer.js by following the instructions at'
273 ' http://www.polymer-project.org; if you do that be sure to include'
274 ' the platform polyfills.');
275 }
276
277 // TODO(jmesserly): dart:js appears to not callback in the correct zone:
278 // https://code.google.com/p/dart/issues/detail?id=17301
279 var zone = Zone.current;
280
281 polymerJs.callMethod('whenPolymerReady',
282 [zone.bindCallback(() => Polymer._ready.complete())]);
283
284 var jsPolymer = new JsObject.fromBrowserObject(
285 document.createElement('polymer-element'));
286
287 var proto = js.context['Object'].callMethod('getPrototypeOf', [jsPolymer]);
288 if (proto is Node) {
289 proto = new JsObject.fromBrowserObject(proto);
290 }
291
292 JsFunction originalRegister = proto['register'];
293 if (originalRegister == null) {
294 throw new StateError('polymer.js must expose "register" function on '
295 'polymer-element to enable polymer.dart to interoperate.');
296 }
297
298 registerDart(jsElem, String name, String extendee) {
299 // By the time we get here, we'll know for sure if it is a Dart object
300 // or not, because polymer-element will wait for us to notify that
301 // the @CustomTag was found.
302 final type = _getRegisteredType(name);
303 if (type != null) {
304 final extendsDecl = _getDeclaration(extendee);
305 return zone.run(() =>
306 new PolymerDeclaration(jsElem, name, type, extendsDecl).register());
307 }
308 // It's a JavaScript polymer element, fall back to the original register.
309 return originalRegister.apply([name, extendee], thisArg: jsElem);
310 }
311
312 proto['register'] = new JsFunction.withThis(registerDart);
313 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698