mirror of https://github.com/flutter/samples.git
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.
152 lines
4.6 KiB
152 lines
4.6 KiB
9 months ago
|
// 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),
|
||
|
),
|
||
|
);
|
||
|
}
|
||
|
}
|