Customizing web app initialization

You can customize how a Flutter app is initialized on the web using the _flutter.loader JavaScript API provided by flutter.js. This API can be used to display a loading indicator in CSS, prevent the app from loading based on a condition, or wait until the user presses a button before showing the app.

The initialization process is split into the following stages:

Loading the entrypoint script
Fetches the main.dart.js script and initializes the service worker.
Initializing the Flutter engine
Initializes Flutter’s web engine by downloading required resources such as assets, fonts, and CanvasKit.
Running the app
Prepares the DOM for your Flutter app and runs it.

This page shows how to customize the behavior at each stage of the initialization process.

Getting started

By default, the index.html file generated by the flutter create command contains a script tag that calls loadEntrypoint from the flutter.js file:

<html>
  <head>
    <!-- ... -->
    <script src="flutter.js" defer></script>
  </head>
  <body>
    <script>
      window.addEventListener('load', function (ev) {
        // Download main.dart.js
        _flutter.loader.loadEntrypoint({
          serviceWorker: {
            serviceWorkerVersion: serviceWorkerVersion,
          },
          onEntrypointLoaded: async function(engineInitializer) {
            // Initialize the Flutter engine
            let appRunner = await engineInitializer.initializeEngine();
            // Run the app
            await appRunner.runApp();
          }
        });
      });
    </script>
  </body>
</html>

The loadEntrypoint function calls the onEntrypointLoaded callback once the Service Worker is initialized, and the main.dart.js entrypoint has been downloaded and run by the browser. Flutter also calls onEntrypointLoaded on every hot restart during development.

The onEntrypointLoaded callback receives an engine initializer object as its only parameter. Use the engine initializer to set the run-time configuration, and start the Flutter Web engine.

The initializeEngine() function returns a Promise that resolves with an app runner object. The app runner has a single method, runApp(), that runs the Flutter app.

Customizing web app initialization

In this section, learn how to customize each stage of your app’s initialization.

Loading the entrypoint

The loadEntrypoint method accepts these parameters:

Name Description JS Type
entrypointUrl The URL of your Flutter app’s entrypoint. Defaults to "main.dart.js". String
onEntrypointLoaded The function called when the engine is ready to be initialized. Receives an engineInitializer object as its only parameter. Function
serviceWorker The configuration for the flutter_service_worker.js loader. (If not set, the service worker won’t be used.) Object

The serviceWorker JavaScript object accepts the following properties:

Name Description JS Type
serviceWorkerUrl The URL of the Service Worker JS file. The serviceWorkerVersion is appended to the URL. Defaults to "flutter_service_worker.js?v=" String
serviceWorkerVersion Pass the serviceWorkerVersion variable set by the build process in your index.html file. String
timeoutMillis The timeout value for the service worker load. Defaults to 4000. Number

Initializing the engine

As of Flutter 3.7.0, you can use the initializeEngine method to configure several run-time options of the Flutter web engine through a plain JavaScript object.

You can add any of the following optional parameters:

Name Description Dart Type
assetBase The base URL of the assets directory of the app. Add this when Flutter loads from a different domain or subdirectory than the actual web app. You may need this when you embed Flutter web into another app, or when you deploy its assets to a CDN. String
canvasKitBaseUrl The base URL from where canvaskit.wasm is downloaded. String
canvasKitVariant The CanvasKit variant to download. Your options cover:

1. auto: Downloads the optimal variant for the browser. The option defaults to this value.
2. full: Downloads the full variant of CanvasKit that works in all browsers.
3. chromium: Downloads a smaller variant of CanvasKit that uses Chromium compatible APIs. Warning: Don’t use the chromium option unless you plan on only using Chromium-based browsers.
String
canvasKitForceCpuOnly When true, forces CPU-only rendering in CanvasKit (the engine won’t use WebGL). bool
canvasKitMaximumSurfaces The maximum number of overlay surfaces that the CanvasKit renderer can use. double
debugShowSemanticNodes If true, Flutter visibly renders the semantics tree onscreen (for debugging). bool
hostElement HTML Element into which Flutter renders the app. When not set, Flutter web takes over the whole page. HtmlElement
renderer Specifies the web renderer for the current Flutter application, either "canvaskit" or "html". String

Engine configuration example

The initializeEngine method lets you pass any of the configuration parameters described above to your Flutter app.

Consider the following example.

Your Flutter app should target an HTML element with id="flutter_app" and use the canvaskit renderer. The resulting JavaScript code would resemble the following:

onEntrypointLoaded: async function(engineInitializer) {
  let appRunner = await engineInitializer.initializeEngine({
    hostElement: document.querySelector("#flutter_app"),
    renderer: "canvaskit"
  });
  appRunner.runApp();
}

For a more detailed explanation of each parameter, take a look at the “Runtime parameters” documentation section of the configuration.dart file of the web engine.

Skipping this step

Instead of calling initializeEngine() on the engine initializer (and then runApp() on the application runner), you can call autoStart() to initialize the engine with its default configuration, and then start the app immediately after the initialization is complete:

_flutter.loader.loadEntrypoint({
  serviceWorker: {
    serviceWorkerVersion: serviceWorkerVersion,
  },
  onEntrypointLoaded: async function(engineInitializer) {
    await engineInitializer.autoStart();
  }
});

Example: Display a progress indicator

To give the user of your application feedback during the initialization process, use the hooks provided for each stage to update the DOM:

<html>
  <head>
    <!-- ... -->
    <script src="flutter.js" defer></script>
  </head>
  <body>
    <div id="loading"></div>
    <script>
      window.addEventListener('load', function(ev) {
        var loading = document.querySelector('#loading');
        loading.textContent = "Loading entrypoint...";
        _flutter.loader.loadEntrypoint({
          serviceWorker: {
            serviceWorkerVersion: serviceWorkerVersion,
          },
          onEntrypointLoaded: async function(engineInitializer) {
            loading.textContent = "Initializing engine...";
            let appRunner = await engineInitializer.initializeEngine();

            loading.textContent = "Running app...";
            await appRunner.runApp();
          }
        });
      });
    </script>
  </body>
</html>

For a more practical example using CSS animations, see the initialization code for the Flutter Gallery.

Upgrading an older project

If your project was created in Flutter 2.10 or earlier, you can create a new index.html file with the latest initialization template by running flutter create as follows.

First, remove the files from your /web directory.

Then, from your project directory, run the following:

$ flutter create . --platforms=web