Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Stack trace mapping works for dart2js and dart2wasm
  • Loading branch information
elliette committed Oct 1, 2024
commit 54b0add23a73ffe8438ae3f37e257699b8376dbd
2 changes: 1 addition & 1 deletion flutter-candidate.txt
Copy link
Member Author

@elliette elliette Oct 1, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the latest candidate in g3. It contains flutter/flutter#155846 which is required so that we can pull in the latest version of package:stack_trace

Original file line number Diff line number Diff line change
@@ -1 +1 @@
8925e1ffdfe880b06a8bc5877f017083d6652f5b
d59499988ac50c18a3d492f953c71efcc101b1a5
95 changes: 70 additions & 25 deletions packages/devtools_app/lib/src/framework/app_error_handling.dart
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,6 @@ import '../shared/globals.dart';

final _log = Logger('app_error_handling');

SingleMapping? _sourceMap;

/// Set up error handling for the app.
///
/// This method will hook into both the zone error handling and the Flutter
Expand All @@ -28,25 +26,15 @@ SingleMapping? _sourceMap;
///
/// [appStartCallback] should be a callback that creates the main Flutter
/// application.
Future<void> setupErrorHandling(Future Function() appStartCallback) async {
try {
final sourceMapUri = Uri.parse('main.dart.js.map');
final sourceMapFile = await get(sourceMapUri);
_sourceMap = SingleMapping.fromJson(
jsonDecode(sourceMapFile.body),
mapUrl: sourceMapUri,
);
} catch (_) {
// Ignore any errors getting the source map.
}

void setupErrorHandling(Future Function() appStartCallback) {
// First, run all our code in a new zone.
unawaited(
runZonedGuarded<Future<void>>(
// ignore: avoid-passing-async-when-sync-expected this ignore should be fixed.
() {
() async {
WidgetsFlutterBinding.ensureInitialized();

await _initializeSourceMapping();

final FlutterExceptionHandler? oldHandler = FlutterError.onError;

FlutterError.onError = (FlutterErrorDetails details) {
Expand Down Expand Up @@ -87,13 +75,29 @@ void reportError(
bool notifyUser = false,
StackTrace? stack,
}) {
stack = _maybeMapStackTrace(stack ?? StackTrace.empty);

final terseStackTrace = stack_trace.Trace.from(stack).terse.toString();
unawaited(
_reportError(
error,
errorType: errorType,
notifyUser: notifyUser,
stack: stack,
).catchError((_) {
// Ignore errors.
}),
);
}

_log.severe('[$errorType]: ${error.toString()}', error, stack);
Future<void> _reportError(
Object error, {
String errorType = 'DevToolsError',
bool notifyUser = false,
StackTrace? stack,
}) async {
final terseStackTrace = await _mapAndTersify(stack);
final errorMessage = '$error\n$terseStackTrace';

ga.reportError('$error\n$terseStackTrace');
_log.severe('[$errorType]: $errorMessage', error, stack);
ga.reportError(errorMessage);

// Show error message in a notification pop-up:
if (notifyUser) {
Expand All @@ -104,11 +108,52 @@ void reportError(
}
}

StackTrace _maybeMapStackTrace(StackTrace stack) {
final sourceMap = _sourceMap;
return sourceMap != null
SingleMapping? _cachedJsSourceMapping;
SingleMapping? _cachedWasmSourceMapping;

Future<SingleMapping?> _fetchSourceMapping() async {
final cachedSourceMapping = preferences.wasmEnabled.value
? _cachedWasmSourceMapping
: _cachedJsSourceMapping;

return cachedSourceMapping ?? (await _initializeSourceMapping());
}

Future<SingleMapping?> _initializeSourceMapping() async {
try {
final wasmEnabled = preferences.wasmEnabled.value;
final sourceMapUri = Uri.parse(
'main.dart.${wasmEnabled ? 'wasm' : 'js'}.map',
);
final sourceMapFile = await get(sourceMapUri);

return SingleMapping.fromJson(
jsonDecode(sourceMapFile.body),
mapUrl: sourceMapUri,
);
} catch (_) {
// Ignore any errors loading the source map.
return Future.value();
}
}

Future<String> _mapAndTersify(StackTrace? stack) async {
final originalStackTrace = stack;
if (originalStackTrace == null) return '';

final mappedStackTrace = await _maybeMapStackTrace(originalStackTrace);
// If mapping fails, revert back to the original source map:
final stackTrace = mappedStackTrace.toString().isEmpty
? originalStackTrace
: mappedStackTrace;
return stack_trace.Trace.from(stackTrace).terse.toString();
}

Future<StackTrace> _maybeMapStackTrace(StackTrace stack) async {
final sourceMapping = await _fetchSourceMapping();
return sourceMapping != null
? mapStackTrace(
sourceMap,
sourceMapping,
stack,
minified: true,
)
Expand Down
2 changes: 1 addition & 1 deletion packages/devtools_app/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ dependencies:
source_map_stack_trace: ^2.1.2
source_maps: ^0.10.12
sse: ^4.1.2
stack_trace: ^1.10.0
stack_trace: ^1.12.0
stream_channel: ^2.1.1
string_scanner: ^1.1.0
unified_analytics: ^6.1.3
Expand Down
1 change: 1 addition & 0 deletions tool/build_release.sh
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ rm -rf build/web
flutter pub get

flutter build web \
--source-maps \
--wasm \
--pwa-strategy=offline-first \
--release \
Expand Down
1 change: 1 addition & 0 deletions tool/lib/commands/build.dart
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@ class BuildCommand extends Command {
[
'build',
'web',
'--source-maps',
if (useWasm) ...[
BuildCommandArgs.wasm.asArg(),
if (noStripWasm) BuildCommandArgs.noStripWasm.asArg(),
Expand Down