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

Side by Side Diff: pkg/dev_compiler/web/stack_trace_mapper.dart

Issue 2735303002: Make all DDC internal stack traces apply source maps. (Closed)
Patch Set: Created 3 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
OLDNEW
(Empty)
1 // Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
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.
4
5 /// Standalone utility that manages loading source maps for all Dart scripts
6 /// on the page compiled with DDC.
7 ///
8 /// Example JavaScript usage:
9 /// $dartStackTraceUtility.addLoadedListener(function() {
10 /// // All Dart source maps are now loaded. It is now safe to start your
11 /// // Dart application compiled with DDC.
12 /// dart_library.start('your_dart_application');
13 /// })
14 ///
15 /// If $dartStackTraceUtility is set, the dart:core StackTrace class calls
16 /// $dartStackTraceUtility.mapper(someJSStackTrace)
17 /// to apply source maps.
18 ///
19 /// This utility can be compiled to JavaScript using Dart2JS while the rest
20 /// of the application is compiled with DDC or could be compiled with DDC.
21
22 @JS()
23 library stack_trace_mapper;
24
25 import 'dart:async';
26 import 'dart:html';
27
28 import 'package:js/js.dart';
29 import 'package:path/path.dart' as path;
30 import 'package:source_map_stack_trace/source_map_stack_trace.dart';
31 import 'package:source_maps/source_maps.dart';
32 import 'package:source_span/source_span.dart';
33 import 'package:stack_trace/stack_trace.dart';
34
35 typedef void ReadyCallback();
36
37 /// Global object DDC uses to see if a stack trace utility has been registed.
vsm 2017/03/08 15:34:44 registed -> registered
Jacob 2017/03/09 02:28:42 Done.
38 @JS(r'$dartStackTraceUtility')
39 external set dartStackTraceUtility(DartStackTraceUtility value);
40
41 typedef String StackTraceMapper(String stackTrace);
42 typedef dynamic AddLoadedListener(ReadyCallback callback);
43
44 @JS()
45 @anonymous
46 class DartStackTraceUtility {
47 external factory DartStackTraceUtility(
48 {StackTraceMapper mapper, AddLoadedListener addLoadedListener});
49 }
50
51 /// Source mapping that is waits to parse source maps until they match the uri
52 /// of a requested source map.
53 ///
54 /// This improves startup performance compared to using MappingBundle directly.
55 /// The unparsed data for the source maps must still be loaded before
56 /// LazyMapping is used.
57 class LazyMapping extends Mapping {
58 MappingBundle _bundle = new MappingBundle();
59
60 /// Map from url to unparsed source map.
61 Map<String, String> _sourceMaps;
62
63 LazyMapping(this._sourceMaps) {}
64
65 List toJson() => _bundle.toJson();
66
67 SourceMapSpan spanFor(int line, int column,
68 {Map<String, SourceFile> files, String uri}) {
69 if (uri == null) {
70 throw new ArgumentError.notNull('uri');
71 }
72 var rawMap = _sourceMaps[uri];
73
74 if (rawMap != null && rawMap.isNotEmpty && !_bundle.containsMapping(uri)) {
75 SingleMapping mapping = parse(rawMap);
76 mapping
77 ..targetUrl = uri
78 ..sourceRoot = '${path.dirname(uri)}/';
79 _bundle.addMapping(mapping);
80 }
81
82 return _bundle.spanFor(line, column, files: files, uri: uri);
83 }
84 }
85
86 String _toSourceMapLocation(String url) {
87 // The url may have cache busting query parameters which we need to maintain
88 // in the source map url.
89 // For example:
90 // http://localhost/foo.js?cachebusting=23419
91 // Should get source map
92 // http://localhost/foo.js.map?cachebusting=23419
93 var uri = Uri.parse(url);
94 return uri.replace(path: '${uri.path}.map').toString();
95 }
96
97 /// Load a source map for the specified url.
98 ///
99 /// Returns a null string rather than reporting an error if the file cannot be
100 /// found as we don't want to throw errors if a few source maps are missing.
101 Future<String> loadSourceMap(String url) async {
102 try {
103 return await HttpRequest.getString(_toSourceMapLocation(url));
104 } catch (e) {
105 return null;
106 }
107 }
108
109 LazyMapping _mapping;
110
111 String mapper(String rawStackTrace) {
112 if (_mapping == null) {
113 // This should not happen if the user has waited for the ReadyCallback
114 // to start the application.
115 throw new StateError('Souce maps are not done loading.');
vsm 2017/03/08 15:34:44 Souce -> Source
Jacob 2017/03/09 02:28:42 Done. Clealy my compute keyboad 'r' key needs to
116 }
117 return mapStackTrace(_mapping, new Trace.parse(rawStackTrace)).toString();
118 }
119
120 Future<Null> addLoadedListener(ReadyCallback callback) async {
121 var scripts = document.querySelectorAll('script');
122 var sourceMapFutures = <Future<String>>[];
123 var urls = <String>[];
124 for (ScriptElement script in scripts) {
vsm 2017/03/08 15:34:44 Would it make more sense to do this in the bootstr
Jacob 2017/03/09 02:28:42 Good point. I've switched up the code so the API
125 // By convention only attempt to load source maps for scripts tagged with
126 // the data attribute loadSourceMap avoiding triggering 404 errors for
127 // regular JS scripts on the page and Dart scripts that we should not load
128 // source maps for.
129 if (!script.dataset.containsKey('loadSourceMap')) continue;
130 var src = script.src;
131 if (src.isEmpty) continue;
132 urls.add(src);
133 sourceMapFutures.add(loadSourceMap(src));
134 }
135 List<String> sourceMaps = await Future.wait(sourceMapFutures);
136 _mapping = new LazyMapping(new Map.fromIterables(urls, sourceMaps));
137 callback();
138 }
139
140 main() {
141 // Register with DDC.
142 dartStackTraceUtility = new DartStackTraceUtility(
143 mapper: allowInterop(mapper),
144 addLoadedListener: allowInterop(addLoadedListener));
145 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698