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

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
« no previous file with comments | « pkg/polymer/lib/src/loader.dart ('k') | pkg/polymer/lib/src/static_loader.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) 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; 14 import 'dart:collection' show LinkedHashMap;
10 const CustomTag(this.tagName);
11 }
12 15
13 /// Metadata used to label static or top-level methods that are called 16 // Technically, we shouldn't need any @MirrorsUsed, since this is for
14 /// automatically when loading the library of a custom element. 17 // development only, but our test bots don't yet run pub-build. See more details
15 const initMethod = const _InitMethodAnnotation(); 18 // on the comments of the mirrors import in `lib/polymer.dart`.
19 @MirrorsUsed(metaTargets:
20 const [CustomTag, InitMethodAnnotation],
21 override: const ['smoke.mirrors', 'polymer.src.mirror_loader'])
22 import 'dart:mirrors';
16 23
17 /// Initializes a polymer application as follows: 24 import 'package:logging/logging.dart' show Logger;
18 /// * set up up polling for observable changes 25 import 'package:polymer/polymer.dart' show
19 /// * initialize Model-Driven Views 26 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 27
33 // In deployment mode, we rely on change notifiers instead of dirty checking.
34 if (!_deployMode) {
35 return dirtyCheckZone()..run(initPolymerOptimized);
36 }
37 28
38 return initPolymerOptimized(); 29 /// Set of initializers that are invoked by `initPolymer`. This is computed the
39 } 30 /// 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 31 /// 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 32 /// top-level method annotated with [initMethod].
72 /// assigned programatically by the code generated from the polymer deploy 33 List<Function> initializers = _discoverInitializers();
73 /// scripts.
74 List<Function> _initializers;
75 34
76 /// True if we're in deployment mode. 35 /// True if we're in deployment mode.
77 bool _deployMode = false; 36 bool deployMode = false;
78 37
38 /// Discovers what script tags are loaded from HTML pages and collects the
39 /// initializers of their corresponding libraries.
79 List<Function> _discoverInitializers() { 40 List<Function> _discoverInitializers() {
80 var initializers = []; 41 var initializers = [];
81 var librariesToLoad = _discoverScripts(document, window.location.href); 42 var librariesToLoad = _discoverScripts(document, window.location.href);
82 for (var lib in librariesToLoad) { 43 for (var lib in librariesToLoad) {
83 try { 44 try {
84 _loadLibrary(lib, initializers); 45 _loadLibrary(lib, initializers);
85 } catch (e, s) { 46 } catch (e, s) {
86 // Deliver errors async, so if a single library fails it doesn't prevent 47 // Deliver errors async, so if a single library fails it doesn't prevent
87 // other things from loading. 48 // other things from loading.
88 new Completer().completeError(e, s); 49 new Completer().completeError(e, s);
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after
125 return scripts; 86 return scripts;
126 } 87 }
127 88
128 /// All libraries in the current isolate. 89 /// All libraries in the current isolate.
129 final _libs = currentMirrorSystem().libraries; 90 final _libs = currentMirrorSystem().libraries;
130 91
131 // TODO(sigmund): explore other (cheaper) ways to resolve URIs relative to the 92 // TODO(sigmund): explore other (cheaper) ways to resolve URIs relative to the
132 // root library (see dartbug.com/12612) 93 // root library (see dartbug.com/12612)
133 final _rootUri = currentMirrorSystem().isolate.rootLibrary.uri; 94 final _rootUri = currentMirrorSystem().isolate.rootLibrary.uri;
134 95
135 final Logger _loaderLog = new Logger('polymer.loader'); 96 final Logger _loaderLog = new Logger('polymer.src.mirror_loader');
136 97
137 bool _isHttpStylePackageUrl(Uri uri) { 98 bool _isHttpStylePackageUrl(Uri uri) {
138 var uriPath = uri.path; 99 var uriPath = uri.path;
139 return uri.scheme == _rootUri.scheme && 100 return uri.scheme == _rootUri.scheme &&
140 // Don't process cross-domain uris. 101 // Don't process cross-domain uris.
141 uri.authority == _rootUri.authority && 102 uri.authority == _rootUri.authority &&
142 uriPath.endsWith('.dart') && 103 uriPath.endsWith('.dart') &&
143 (uriPath.contains('/packages/') || uriPath.startsWith('packages/')); 104 (uriPath.contains('/packages/') || uriPath.startsWith('packages/'));
144 } 105 }
145 106
(...skipping 98 matching lines...) Expand 10 before | Expand all | Expand 10 after
244 " ${method.simpleName} is not."); 205 " ${method.simpleName} is not.");
245 return; 206 return;
246 } 207 }
247 if (!method.parameters.where((p) => !p.isOptional).isEmpty) { 208 if (!method.parameters.where((p) => !p.isOptional).isEmpty) {
248 print("warning: methods marked with @initMethod should take no " 209 print("warning: methods marked with @initMethod should take no "
249 "arguments, ${method.simpleName} expects some."); 210 "arguments, ${method.simpleName} expects some.");
250 return; 211 return;
251 } 212 }
252 initializers.add(() => obj.invoke(method.simpleName, const [])); 213 initializers.add(() => obj.invoke(method.simpleName, const []));
253 } 214 }
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
« no previous file with comments | « pkg/polymer/lib/src/loader.dart ('k') | pkg/polymer/lib/src/static_loader.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698