Repository: flutter
Issue: [web] Optimize network requests on page load
Labels: engine,platform-web,c: proposal,P2,team-web,triaged-web

In this issue, I wanted to analyze the network activity that happens during page load of a sample flutter web app.

## <ins>Problem</ins>

![image](https://user-images.githubusercontent.com/1278212/211086852-36737dc1-cd9e-4e19-94a6-47005213e466.png)

Bigger apps typically have more fonts and/or assets (more requests), but the basic dependency tree between these requests looks something like this:
```
                                          +--> canvaskit.js --> canvaskit.wasm
                                          |
index.html -> flutter.js -> main.dart.js -+                       +--> MaterialIcons-Regular.otf
                                          |                       |
                                          +--> FontManifest.json -+--> CupertinoIcons.ttf
                                                                  |
                                                                  +--> Roboto.ttf
```

This tree is not ideal, for 2 main reasons:

1. We are loading too many things for a basic app!
2. The tree is narrow and deep, i.e. leaf nodes have a long chain of dependencies before they can be loaded.

## <ins>Better?</ins>

A better tree should be wider and shallower to get more parallelization and fewer dependencies:
```
                         +--> main.dart.js ---> canvaskit.js
                         |
-------------------\     +--> canvaskit.wasm
index.html          \    |
(flutter.js)         +---+--> MaterialIcons-Regular.otf
(FontManifest.json) /    |
-------------------/     +--> CupertinoIcons.ttf
                         |
                         +--> Roboto.ttf
```

## <ins>How?</ins>

The idea can be split into 2 parts:

### 1. Inlining

There's no reason to load `flutter.js` and `FontManifest.json` (and potentially others) from the network. They could be inlined into `index.html` so that they are available immediately and don't require an extra hop to the server.

Flutter generates the `index.html` file but we don't own it anymore after creation. The app developer owns the file and can change it as they see fit. This means we can't make any assumptions about the structure of the file, and we can't force-inline anything. The flutter tools should support inlining but the user should have full control.

One way to achieve this is to use placeholders, similar to `$FLUTTER_BASE_HREF`:
https://github.com/flutter/flutter/blob/507062032fa44678100c46250712f6b9dc07ba4b/packages/flutter_tools/templates/app_shared/web/index.html.tmpl#L4-L17

We can define a set of placeholders that the user can put in. The flutter tool substitutes the placeholders at build-time. The placeholders may look something like this:
```html
<script>$FLUTTER_JS_SCRIPT</script>
```

They can be placed anywhere the user chooses. E.g:
```html
<script>
  const fontManifest = $$FLUTTER_FONT_MANIFEST; // This will be replaced with the actual json.

  _flutter.loader.loadEntrypoint({
    fontManifest: fontManifest,
    serviceWorker: {
      serviceWorkerVersion: serviceWorkerVersion,
    },
    onEntrypointLoaded: async function(engineInitializer) {
      const appRunner = await engineInitializer.initializeEngine({
        fontManifest: fontManifest,
      });
      appRunner.runApp();
    }
  });
</script>
```

### 2. Auto prefetching

Since `flutter.js` is now inlined in `index.html`, it runs immediately. It can fire requests for `main.dart.js` and `canvaskit.wasm` in parallel.

At the same time, it can also prefetch all the needed fonts since it has immediate access  to the inlined `FontManifest.json`.

This ensures maximum parallelization. All the requests are sent immediately as `index.html` loads.