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
<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:

NameDescriptionJS Type
entrypointUrlThe URL of your Flutter app's entrypoint. Defaults to "main.dart.js".String
onEntrypointLoadedThe function called when the engine is ready to be initialized. Receives an engineInitializer object as its only parameter.Function
serviceWorkerThe 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:

NameDescriptionJS Type
serviceWorkerUrlThe URL of the Service Worker JS file. The serviceWorkerVersion is appended to the URL. Defaults to "flutter_service_worker.js?v="String
serviceWorkerVersionPass the serviceWorkerVersion variable set by the build process in your index.html file.String
timeoutMillisThe 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:

NameDescriptionDart Type
assetBaseThe 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 might need this when you embed Flutter web into another app, or when you deploy its assets to a CDN.String
canvasKitBaseUrlThe base URL from where canvaskit.wasm is downloaded.String
canvasKitVariantThe 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
canvasKitForceCpuOnlyWhen true, forces CPU-only rendering in CanvasKit (the engine won't use WebGL).bool
canvasKitMaximumSurfacesThe maximum number of overlay surfaces that the CanvasKit renderer can use.double
debugShowSemanticNodesIf true, Flutter visibly renders the semantics tree onscreen (for debugging).bool
hostElementHTML Element into which Flutter renders the app. When not set, Flutter web takes over the whole page.HtmlElement
rendererSpecifies 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:

js
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:

js
_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
<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