Skip to content

Commit 3c30e3c

Browse files
Flutter Web Bootstrapping Improvements (#144434)
This makes several changes to flutter web app bootstrapping. * The build now produces a `flutter_bootstrap.js` file. * By default, this file does the basic streamlined startup of a flutter app with the service worker settings and no user configuration. * The user can also put a `flutter_bootstrap.js` file in the `web` subdirectory in the project directory which can have whatever custom bootstrapping logic they'd like to write instead. This file is also templated, and can use any of the tokens that can be used with the `index.html` (with the exception of `{{flutter_bootstrap_js}}`, see below). * Introduced a few new templating tokens for `index.html`: * `{{flutter_js}}` => inlines the entirety of `flutter.js` * `{{flutter_service_worker_version}}` => replaced directly by the service worker version. This can be used instead of the script that sets the `serviceWorkerVersion` local variable that we used to have by default. * `{{flutter_bootstrap_js}}` => inlines the entirety of `flutter_bootstrap.js` (this token obviously doesn't apply to `flutter_bootstrap.js` itself). * Changed `IndexHtml` to be called `WebTemplate` instead, since it is used for more than just the index.html now. * We now emit warnings at build time for certain deprecated flows: * Warn on the old service worker version pattern (i.e.`(const|var) serviceWorkerVersion = null`) and recommends using `{{flutter_service_worker_version}}` token instead * Warn on use of `FlutterLoader.loadEntrypoint` and recommend using `FlutterLoader.load` instead * Warn on manual loading of `flutter_service_worker.js`. * The default `index.html` on `flutter create` now uses an async script tag with `flutter_bootstrap.js`.
1 parent 5b006bf commit 3c30e3c

31 files changed

+823
-784
lines changed

dev/a11y_assessments/web/index.html

Lines changed: 1 addition & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -41,23 +41,8 @@
4141
const serviceWorkerVersion = null;
4242
</script>
4343
<!-- This script adds the flutter initialization JS code -->
44-
<script src="flutter.js" defer></script>
4544
</head>
4645
<body>
47-
<script>
48-
window.addEventListener('load', function(ev) {
49-
// Download main.dart.js
50-
_flutter.loader.loadEntrypoint({
51-
serviceWorker: {
52-
serviceWorkerVersion: serviceWorkerVersion,
53-
},
54-
onEntrypointLoaded: function(engineInitializer) {
55-
engineInitializer.initializeEngine().then(function(appRunner) {
56-
appRunner.runApp();
57-
});
58-
}
59-
});
60-
});
61-
</script>
46+
<script src="flutter_bootstrap.js" async></script>
6247
</body>
6348
</html>
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
{{flutter_js}}
2+
{{flutter_build_config}}
3+
_flutter.loader.load({
4+
config: {
5+
// Use the local CanvasKit bundle instead of the CDN to reduce test flakiness.
6+
canvasKitBaseUrl: "/canvaskit/",
7+
},
8+
});

dev/benchmarks/macrobenchmarks/web/index.html

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -6,16 +6,8 @@
66
<head>
77
<meta charset="UTF-8">
88
<title>Web Benchmarks</title>
9-
<script src="flutter.js"></script>
109
</head>
1110
<body>
12-
<script>
13-
{{flutter_build_config}}
14-
_flutter.loader.load({
15-
config: {
16-
canvasKitBaseUrl: '/canvaskit/',
17-
}
18-
});
19-
</script>
11+
<script src="flutter_bootstrap.js" async></script>
2012
</body>
2113
</html>

dev/bots/service_worker_test.dart

Lines changed: 31 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -163,7 +163,11 @@ Future<void> _waitForAppToLoad(
163163
print('Waiting for app to load $waitForCounts');
164164
await Future.any(<Future<Object?>>[
165165
() async {
166+
int tries = 1;
166167
while (!waitForCounts.entries.every((MapEntry<String, int> entry) => (requestedPathCounts[entry.key] ?? 0) >= entry.value)) {
168+
if (tries++ % 20 == 0) {
169+
print('Still waiting. Requested so far: $requestedPathCounts');
170+
}
167171
await Future<void>.delayed(const Duration(milliseconds: 100));
168172
}
169173
}(),
@@ -304,15 +308,16 @@ Future<void> runWebServiceWorkerTest({
304308
'flutter.js': 1,
305309
'main.dart.js': 1,
306310
'flutter_service_worker.js': 1,
311+
'flutter_bootstrap.js': 1,
307312
'assets/FontManifest.json': 1,
308313
'assets/AssetManifest.bin.json': 1,
309314
'assets/fonts/MaterialIcons-Regular.otf': 1,
310315
'CLOSE': 1,
311-
// In headless mode Chrome does not load 'manifest.json' and 'favicon.ico'.
316+
// In headless mode Chrome does not load 'manifest.json' and 'favicon.png'.
312317
if (!headless)
313318
...<String, int>{
314319
'manifest.json': 1,
315-
'favicon.ico': 1,
320+
'favicon.png': 1,
316321
},
317322
});
318323
expect(reportedVersion, '1');
@@ -346,12 +351,13 @@ Future<void> runWebServiceWorkerTest({
346351
if (shouldExpectFlutterJs)
347352
'flutter.js': 1,
348353
'flutter_service_worker.js': 2,
354+
'flutter_bootstrap.js': 1,
349355
'main.dart.js': 1,
350356
'assets/AssetManifest.bin.json': 1,
351357
'assets/FontManifest.json': 1,
352358
'CLOSE': 1,
353359
if (!headless)
354-
'favicon.ico': 1,
360+
'favicon.png': 1,
355361
});
356362

357363
expect(reportedVersion, '2');
@@ -377,14 +383,15 @@ Future<void> runWebServiceWorkerTest({
377383
'main.dart.js': 1,
378384
'assets/FontManifest.json': 1,
379385
'flutter_service_worker.js': 1,
386+
'flutter_bootstrap.js': 1,
380387
'assets/AssetManifest.bin.json': 1,
381388
'assets/fonts/MaterialIcons-Regular.otf': 1,
382389
'CLOSE': 1,
383-
// In headless mode Chrome does not load 'manifest.json' and 'favicon.ico'.
390+
// In headless mode Chrome does not load 'manifest.json' and 'favicon.png'.
384391
if (!headless)
385392
...<String, int>{
386393
'manifest.json': 1,
387-
'favicon.ico': 1,
394+
'favicon.png': 1,
388395
},
389396
});
390397

@@ -429,14 +436,15 @@ Future<void> runWebServiceWorkerTest({
429436
if (shouldExpectFlutterJs)
430437
'flutter.js': 1,
431438
'flutter_service_worker.js': 2,
439+
'flutter_bootstrap.js': 1,
432440
'main.dart.js': 1,
433441
'assets/AssetManifest.bin.json': 1,
434442
'assets/FontManifest.json': 1,
435443
'CLOSE': 1,
436444
if (!headless)
437445
...<String, int>{
438446
'manifest.json': 1,
439-
'favicon.ico': 1,
447+
'favicon.png': 1,
440448
},
441449
});
442450

@@ -508,8 +516,8 @@ Future<void> runWebServiceWorkerTestWithCachingResources({
508516
workingDirectory: _testAppWebDirectory,
509517
);
510518

511-
final bool shouldExpectFlutterJs = testType != ServiceWorkerTestType.withoutFlutterJs;
512-
519+
final bool usesFlutterBootstrapJs = testType == ServiceWorkerTestType.generatedEntrypoint;
520+
final bool shouldExpectFlutterJs = !usesFlutterBootstrapJs && testType != ServiceWorkerTestType.withoutFlutterJs;
513521
print('BEGIN runWebServiceWorkerTestWithCachingResources(headless: $headless, testType: $testType)');
514522

515523
try {
@@ -534,14 +542,15 @@ Future<void> runWebServiceWorkerTestWithCachingResources({
534542
'flutter.js': 1,
535543
'main.dart.js': 1,
536544
'flutter_service_worker.js': 1,
545+
'flutter_bootstrap.js': usesFlutterBootstrapJs ? 2 : 1,
537546
'assets/FontManifest.json': 1,
538547
'assets/AssetManifest.bin.json': 1,
539548
'assets/fonts/MaterialIcons-Regular.otf': 1,
540-
// In headless mode Chrome does not load 'manifest.json' and 'favicon.ico'.
549+
// In headless mode Chrome does not load 'manifest.json' and 'favicon.png'.
541550
if (!headless)
542551
...<String, int>{
543552
'manifest.json': 1,
544-
'favicon.ico': 1,
553+
'favicon.png': 1,
545554
},
546555
});
547556

@@ -593,13 +602,14 @@ Future<void> runWebServiceWorkerTestWithCachingResources({
593602
'flutter.js': 1,
594603
'main.dart.js': 1,
595604
'flutter_service_worker.js': 2,
605+
'flutter_bootstrap.js': usesFlutterBootstrapJs ? 2 : 1,
596606
'assets/FontManifest.json': 1,
597607
'assets/AssetManifest.bin.json': 1,
598608
'assets/fonts/MaterialIcons-Regular.otf': 1,
599-
// In headless mode Chrome does not load 'manifest.json' and 'favicon.ico'.
609+
// In headless mode Chrome does not load 'manifest.json' and 'favicon.png'.
600610
if (!headless)
601611
...<String, int>{
602-
'favicon.ico': 1,
612+
'favicon.png': 1,
603613
},
604614
});
605615
} finally {
@@ -682,11 +692,11 @@ Future<void> runWebServiceWorkerTestWithBlockedServiceWorkers({
682692
'assets/FontManifest.json': 1,
683693
'assets/fonts/MaterialIcons-Regular.otf': 1,
684694
'CLOSE': 1,
685-
// In headless mode Chrome does not load 'manifest.json' and 'favicon.ico'.
695+
// In headless mode Chrome does not load 'manifest.json' and 'favicon.png'.
686696
if (!headless)
687697
...<String, int>{
688698
'manifest.json': 1,
689-
'favicon.ico': 1,
699+
'favicon.png': 1,
690700
},
691701
});
692702
} finally {
@@ -770,14 +780,15 @@ Future<void> runWebServiceWorkerTestWithCustomServiceWorkerVersion({
770780
'main.dart.js': 1,
771781
'CLOSE': 1,
772782
'flutter_service_worker.js': 1,
783+
'flutter_bootstrap.js': 1,
773784
'assets/FontManifest.json': 1,
774785
'assets/AssetManifest.bin.json': 1,
775786
'assets/fonts/MaterialIcons-Regular.otf': 1,
776-
// In headless mode Chrome does not load 'manifest.json' and 'favicon.ico'.
787+
// In headless mode Chrome does not load 'manifest.json' and 'favicon.png'.
777788
if (!headless)
778789
...<String, int>{
779790
'manifest.json': 1,
780-
'favicon.ico': 1,
791+
'favicon.png': 1,
781792
},
782793
});
783794

@@ -794,11 +805,11 @@ Future<void> runWebServiceWorkerTestWithCustomServiceWorkerVersion({
794805
'assets/FontManifest.json': 1,
795806
'assets/fonts/MaterialIcons-Regular.otf': 1,
796807
'CLOSE': 1,
797-
// In headless mode Chrome does not load 'manifest.json' and 'favicon.ico'.
808+
// In headless mode Chrome does not load 'manifest.json' and 'favicon.png'.
798809
if (!headless)
799810
...<String, int>{
800811
'manifest.json': 1,
801-
'favicon.ico': 1,
812+
'favicon.png': 1,
802813
},
803814
});
804815

@@ -816,11 +827,11 @@ Future<void> runWebServiceWorkerTestWithCustomServiceWorkerVersion({
816827
'assets/FontManifest.json': 1,
817828
'assets/fonts/MaterialIcons-Regular.otf': 1,
818829
'CLOSE': 1,
819-
// In headless mode Chrome does not load 'manifest.json' and 'favicon.ico'.
830+
// In headless mode Chrome does not load 'manifest.json' and 'favicon.png'.
820831
if (!headless)
821832
...<String, int>{
822833
'manifest.json': 1,
823-
'favicon.ico': 1,
834+
'favicon.png': 1,
824835
},
825836
});
826837
} finally {

dev/integration_tests/web/lib/service_worker_test_cached_resources.dart

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,16 @@
55
import 'package:flutter/material.dart';
66

77
Future<void> main() async {
8-
runApp(const Scaffold(
9-
body: Center(
10-
child: Column(
11-
children: <Widget>[
12-
Icon(Icons.ac_unit),
13-
Text('Hello, World', textDirection: TextDirection.ltr),
14-
],
8+
runApp(const Directionality(
9+
textDirection: TextDirection.ltr,
10+
child: Scaffold(
11+
body: Center(
12+
child: Column(
13+
children: <Widget>[
14+
Icon(Icons.ac_unit),
15+
Text('Hello, World', textDirection: TextDirection.ltr),
16+
],
17+
),
1518
),
16-
),
17-
));
19+
)));
1820
}

dev/integration_tests/web/web/index.html

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,9 @@
1212
<meta name="apple-mobile-web-app-capable" content="yes">
1313
<meta name="apple-mobile-web-app-status-bar-style" content="black">
1414
<meta name="apple-mobile-web-app-title" content="Web Test">
15+
16+
<!-- Favicon -->
17+
<link rel="icon" type="image/png" href="favicon.png"/>
1518
<link rel="manifest" href="manifest.json">
1619
</head>
1720
<body>

dev/integration_tests/web/web/index_with_blocked_service_workers.html

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,9 @@
1212
<meta name="apple-mobile-web-app-capable" content="yes">
1313
<meta name="apple-mobile-web-app-status-bar-style" content="black">
1414
<meta name="apple-mobile-web-app-title" content="Web Test">
15+
16+
<!-- Favicon -->
17+
<link rel="icon" type="image/png" href="favicon.png"/>
1518
<link rel="manifest" href="manifest.json">
1619

1720
<script>

dev/integration_tests/web/web/index_with_flutterjs.html

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,9 @@
1212
<meta name="apple-mobile-web-app-capable" content="yes">
1313
<meta name="apple-mobile-web-app-status-bar-style" content="black">
1414
<meta name="apple-mobile-web-app-title" content="Web Test">
15+
16+
<!-- Favicon -->
17+
<link rel="icon" type="image/png" href="favicon.png"/>
1518
<link rel="manifest" href="manifest.json">
1619
<script>
1720
// The value below is injected by flutter build, do not touch.

dev/integration_tests/web/web/index_with_flutterjs_custom_sw_version.html

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,9 @@
1313
<meta name="apple-mobile-web-app-capable" content="yes">
1414
<meta name="apple-mobile-web-app-status-bar-style" content="black">
1515
<meta name="apple-mobile-web-app-title" content="Web Test">
16+
17+
<!-- Favicon -->
18+
<link rel="icon" type="image/png" href="favicon.png"/>
1619
<link rel="manifest" href="manifest.json">
1720
<script>
1821
// The value below is injected by flutter build, do not touch.

dev/integration_tests/web/web/index_with_flutterjs_el_nonce.html

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,9 @@
1616
<meta name="apple-mobile-web-app-capable" content="yes">
1717
<meta name="apple-mobile-web-app-status-bar-style" content="black">
1818
<meta name="apple-mobile-web-app-title" content="Web Test">
19+
20+
<!-- Favicon -->
21+
<link rel="icon" type="image/png" href="favicon.png"/>
1922
<link rel="manifest" href="manifest.json">
2023
<script nonce="SOME_NONCE">
2124
// The value below is injected by flutter build, do not touch.

dev/integration_tests/web/web/index_with_flutterjs_el_tt_on.html

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,9 @@
1616
<meta name="apple-mobile-web-app-capable" content="yes">
1717
<meta name="apple-mobile-web-app-status-bar-style" content="black">
1818
<meta name="apple-mobile-web-app-title" content="Web Test">
19+
20+
<!-- Favicon -->
21+
<link rel="icon" type="image/png" href="favicon.png"/>
1922
<link rel="manifest" href="manifest.json">
2023
<script>
2124
// The value below is injected by flutter build, do not touch.

dev/integration_tests/web/web/index_with_flutterjs_entrypoint_loaded.html

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,9 @@
1212
<meta name="apple-mobile-web-app-capable" content="yes">
1313
<meta name="apple-mobile-web-app-status-bar-style" content="black">
1414
<meta name="apple-mobile-web-app-title" content="Web Test">
15+
16+
<!-- Favicon -->
17+
<link rel="icon" type="image/png" href="favicon.png"/>
1518
<link rel="manifest" href="manifest.json">
1619
<script>
1720
// The value below is injected by flutter build, do not touch.

dev/integration_tests/web/web/index_with_flutterjs_short.html

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,9 @@
1212
<meta name="apple-mobile-web-app-capable" content="yes">
1313
<meta name="apple-mobile-web-app-status-bar-style" content="black">
1414
<meta name="apple-mobile-web-app-title" content="Web Test">
15+
16+
<!-- Favicon -->
17+
<link rel="icon" type="image/png" href="favicon.png"/>
1518
<link rel="manifest" href="manifest.json">
1619
<script>
1720
// The value below is injected by flutter build, do not touch.

dev/integration_tests/web/web/index_without_flutterjs.html

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,9 @@
1212
<meta name="apple-mobile-web-app-capable" content="yes">
1313
<meta name="apple-mobile-web-app-status-bar-style" content="black">
1414
<meta name="apple-mobile-web-app-title" content="Web Test">
15+
16+
<!-- Favicon -->
17+
<link rel="icon" type="image/png" href="favicon.png"/>
1518
<link rel="manifest" href="manifest.json">
1619
</head>
1720
<body>
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
{{flutter_build_config}}
2+
{{flutter_js}}
3+
_flutter.loader.load({
4+
config: {
5+
// Use the local CanvasKit bundle instead of the CDN to reduce test flakiness.
6+
canvasKitBaseUrl: "/canvaskit/",
7+
},
8+
});

dev/integration_tests/web_e2e_tests/web/index.html

Lines changed: 1 addition & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5,17 +5,8 @@
55
<html>
66
<head>
77
<title>Web Integration Tests</title>
8-
<script src="flutter.js"></script>
98
</head>
109
<body>
11-
<script>
12-
{{flutter_build_config}}
13-
_flutter.loader.load({
14-
config: {
15-
// Use the local CanvasKit bundle instead of the CDN to reduce test flakiness.
16-
canvasKitBaseUrl: "/canvaskit/",
17-
},
18-
});
19-
</script>
10+
<script src="flutter_bootstrap.js" async></script>
2011
</body>
2112
</html>

0 commit comments

Comments
 (0)