mirror of https://github.com/flutter/samples.git
Add web_startup_analyzer to material_3_demo (#2152)
parent
6c10c75e2b
commit
b05384a4a6
@ -0,0 +1,103 @@
|
||||
// Copyright 2021 The Flutter team. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
import 'dart:async';
|
||||
import 'dart:js_interop';
|
||||
import 'dart:js_interop_unsafe';
|
||||
|
||||
import 'package:flutter/widgets.dart';
|
||||
import 'package:web_startup_analyzer/src/web_startup_analyzer_base.dart';
|
||||
|
||||
import 'frame_analyzer.dart';
|
||||
import 'startup_analyzer.dart';
|
||||
|
||||
class WebStartupAnalyzer extends WebStartupAnalyzerBase {
|
||||
final WidgetsBinding _widgetsBinding;
|
||||
late final FrameAnalyzer _frameAnalyzer;
|
||||
List<int>? _additionalFrames;
|
||||
|
||||
@override
|
||||
Map<String, dynamic> startupTiming = {};
|
||||
|
||||
@override
|
||||
double get domContentLoaded =>
|
||||
(flutterWebStartupAnalyzer.timings['domContentLoaded'] as JSNumber)
|
||||
.toDartDouble;
|
||||
@override
|
||||
double get loadEntrypoint =>
|
||||
(flutterWebStartupAnalyzer.timings['loadEntrypoint'] as JSNumber)
|
||||
.toDartDouble;
|
||||
@override
|
||||
double get initializeEngine =>
|
||||
(flutterWebStartupAnalyzer.timings['initializeEngine'] as JSNumber)
|
||||
.toDartDouble;
|
||||
@override
|
||||
double get appRunnerRunApp =>
|
||||
(flutterWebStartupAnalyzer.timings['appRunnerRunApp'] as JSNumber)
|
||||
.toDartDouble;
|
||||
@override
|
||||
double? get firstFrame =>
|
||||
(flutterWebStartupAnalyzer.timings['firstFrame'] as JSNumber?)
|
||||
?.toDartDouble;
|
||||
@override
|
||||
double? get firstPaint =>
|
||||
(flutterWebStartupAnalyzer.timings['first-paint'] as JSNumber?)
|
||||
?.toDartDouble;
|
||||
@override
|
||||
double? get firstContentfulPaint =>
|
||||
(flutterWebStartupAnalyzer.timings['first-contentful-paint'] as JSNumber?)
|
||||
?.toDartDouble;
|
||||
@override
|
||||
List<int>? get additionalFrames => _additionalFrames;
|
||||
|
||||
WebStartupAnalyzer({int additionalFrameCount = 5})
|
||||
: _widgetsBinding = WidgetsFlutterBinding.ensureInitialized() {
|
||||
_frameAnalyzer =
|
||||
FrameAnalyzer(_widgetsBinding, additionalFrames: additionalFrameCount);
|
||||
_captureStartupMetrics();
|
||||
startupTiming = {
|
||||
'domContentLoaded': domContentLoaded,
|
||||
'loadEntrypoint': loadEntrypoint,
|
||||
'initializeEngine': initializeEngine,
|
||||
'appRunnerRunApp': appRunnerRunApp,
|
||||
};
|
||||
_captureFirstFrame().then((value) {
|
||||
flutterWebStartupAnalyzer.captureAll();
|
||||
onFirstFrame.value = firstFrame;
|
||||
|
||||
// Capture first-paint and first-contentful-paint
|
||||
Future.delayed(const Duration(milliseconds: 200)).then((_) {
|
||||
flutterWebStartupAnalyzer.capturePaint();
|
||||
onFirstPaint.value = (firstPaint!, firstContentfulPaint!);
|
||||
});
|
||||
});
|
||||
captureFlutterFrameData().then((value) {
|
||||
_additionalFrames = value;
|
||||
onAdditionalFrames.value = value;
|
||||
});
|
||||
onChange =
|
||||
Listenable.merge([onFirstFrame, onFirstPaint, onAdditionalFrames]);
|
||||
}
|
||||
|
||||
_captureStartupMetrics() {
|
||||
flutterWebStartupAnalyzer.markFinished('appRunnerRunApp');
|
||||
flutterWebStartupAnalyzer.captureAll();
|
||||
}
|
||||
|
||||
Future<void> _captureFirstFrame() {
|
||||
final completer = Completer();
|
||||
flutterWebStartupAnalyzer.markStart('firstFrame');
|
||||
_widgetsBinding.addPostFrameCallback((timeStamp) {
|
||||
flutterWebStartupAnalyzer.markFinished('firstFrame');
|
||||
flutterWebStartupAnalyzer.capture('firstFrame');
|
||||
completer.complete();
|
||||
});
|
||||
return completer.future;
|
||||
}
|
||||
|
||||
Future<List<int>> captureFlutterFrameData() async {
|
||||
await _frameAnalyzer.captureAdditionalFrames();
|
||||
return _frameAnalyzer.additionalFrameTimes;
|
||||
}
|
||||
}
|
@ -0,0 +1,25 @@
|
||||
// Copyright 2021 The Flutter team. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
import 'package:flutter/foundation.dart';
|
||||
|
||||
// Base class for the web (real) implementation and dart:io (stub)
|
||||
// implementation.
|
||||
abstract class WebStartupAnalyzerBase {
|
||||
late final Listenable onChange;
|
||||
ValueNotifier<double?> onFirstFrame = ValueNotifier(null);
|
||||
ValueNotifier<(double, double)?> onFirstPaint = ValueNotifier(null);
|
||||
ValueNotifier<List<int>?> onAdditionalFrames = ValueNotifier(null);
|
||||
|
||||
double get domContentLoaded;
|
||||
double get loadEntrypoint;
|
||||
double get initializeEngine;
|
||||
double get appRunnerRunApp;
|
||||
double? get firstFrame;
|
||||
double? get firstPaint;
|
||||
double? get firstContentfulPaint;
|
||||
List<int>? get additionalFrames;
|
||||
|
||||
Map<String, dynamic> get startupTiming;
|
||||
}
|
@ -0,0 +1,37 @@
|
||||
// Copyright 2021 The Flutter team. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
import 'web_startup_analyzer_base.dart';
|
||||
|
||||
// This class is a stub so that unit tests can run without importing
|
||||
// dart:js_interop and related packages.
|
||||
class WebStartupAnalyzer extends WebStartupAnalyzerBase {
|
||||
WebStartupAnalyzer({int additionalFrameCount = 0});
|
||||
|
||||
List<int>? get additionalFrames => [];
|
||||
|
||||
@override
|
||||
double get appRunnerRunApp => 0.0;
|
||||
|
||||
@override
|
||||
double get domContentLoaded => 0.0;
|
||||
|
||||
@override
|
||||
double? get firstContentfulPaint => 0.0;
|
||||
|
||||
@override
|
||||
double? get firstFrame => 0.0;
|
||||
|
||||
@override
|
||||
double? get firstPaint => 0.0;
|
||||
|
||||
@override
|
||||
double get initializeEngine => 0.0;
|
||||
|
||||
@override
|
||||
double get loadEntrypoint => 0.0;
|
||||
|
||||
@override
|
||||
Map<String, dynamic> get startupTiming => {};
|
||||
}
|
Loading…
Reference in new issue