You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
samples/web/_packages/web_startup_analyzer/example/lib/main.dart

152 lines
4.6 KiB

// 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:convert';
import 'package:flutter/material.dart';
import 'package:web_startup_analyzer/web_startup_analyzer.dart';
main() async {
var analyzer = WebStartupAnalyzer(additionalFrameCount: 10);
print(json.encode(analyzer.startupTiming));
analyzer.onFirstFrame.addListener(() {
print(json.encode({'firstFrame': analyzer.onFirstFrame.value}));
});
analyzer.onFirstPaint.addListener(() {
print(json.encode({
'firstPaint': analyzer.onFirstPaint.value?.$1,
'firstContentfulPaint': analyzer.onFirstPaint.value?.$2,
}));
});
analyzer.onAdditionalFrames.addListener(() {
print(json.encode({
'additionalFrames': analyzer.onAdditionalFrames.value,
}));
});
runApp(
WebStartupAnalyzerSample(
analyzer: analyzer,
),
);
}
class WebStartupAnalyzerSample extends StatelessWidget {
final WebStartupAnalyzer analyzer;
const WebStartupAnalyzerSample({super.key, required this.analyzer});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter web app timing',
theme: ThemeData(
colorScheme: ColorScheme.fromSeed(seedColor: Colors.green.shade100),
),
home: WebStartupAnalyzerScreen(analyzer: analyzer),
);
}
}
class WebStartupAnalyzerScreen extends StatefulWidget {
final WebStartupAnalyzer analyzer;
const WebStartupAnalyzerScreen({super.key, required this.analyzer});
@override
State<WebStartupAnalyzerScreen> createState() =>
_WebStartupAnalyzerScreenState();
}
class _WebStartupAnalyzerScreenState extends State<WebStartupAnalyzerScreen> {
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.amber.shade50,
body: Align(
alignment: Alignment.topCenter,
child: Container(
margin: const EdgeInsets.all(8.0),
constraints: const BoxConstraints(maxWidth: 400),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(8.0),
),
child: ListenableBuilder(
listenable: widget.analyzer.onChange,
builder: (BuildContext context, child) {
return ListView(
shrinkWrap: true,
children: [
TimingWidget(
name: 'DCL',
timingMs: widget.analyzer.domContentLoaded,
),
TimingWidget(
name: 'Load entrypoint',
timingMs: widget.analyzer.loadEntrypoint,
),
TimingWidget(
name: 'Initialize engine',
timingMs: widget.analyzer.initializeEngine,
),
TimingWidget(
name: 'Run app',
timingMs: widget.analyzer.appRunnerRunApp,
),
if (widget.analyzer.firstFrame != null)
TimingWidget(
name: 'First frame',
timingMs: widget.analyzer.firstFrame!,
),
if (widget.analyzer.firstPaint != null)
TimingWidget(
name: 'First paint',
timingMs: widget.analyzer.firstPaint!),
if (widget.analyzer.firstContentfulPaint != null)
TimingWidget(
name: 'First contentful paint',
timingMs: widget.analyzer.firstContentfulPaint!),
if (widget.analyzer.additionalFrames != null) ...[
for (var i in widget.analyzer.additionalFrames!)
TimingWidget(name: 'Frame', timingMs: i.toDouble()),
] else
TextButton(
child: const Text('Trigger frames'),
onPressed: () {},
),
],
);
},
),
),
),
);
}
}
class TimingWidget extends StatelessWidget {
final String name;
final double timingMs;
const TimingWidget({
super.key,
required this.name,
required this.timingMs,
});
@override
Widget build(BuildContext context) {
return ListTile(
title: Text(
name,
style: const TextStyle(fontSize: 18),
overflow: TextOverflow.ellipsis,
),
trailing: Text(
'${timingMs.truncate()}ms',
style: const TextStyle(fontSize: 18),
),
);
}
}