Flutter web 应用的初始化

This page details the initialization process for Flutter web apps, and how this process can be customized.

flutter_bootstrap.js

#

When building your flutter app, the flutter build web command produces a script called flutter_bootstrap.js in the build output directory (build/web). This file contains the JavaScript code needed to initialize and run your Flutter app. You can use this script by placing an async-script tag for it in your index.html file in the web subdirectory of your Flutter app:

html
<html>
  <body>
    <script src="flutter_bootstrap.js" async></script>
  </body>
</html>

Alternatively, you can inline the entire contents of the flutter_bootstrap.js file by inserting the template token {{flutter_bootstrap_js}} in your index.html file:

html
<html>
  <body>
    <script>
      {{flutter_bootstrap_js}}
    </script>
  </body>
</html>

The {{flutter_bootstrap_js}} token is replaced with the contents of the flutter_bootstrap.js file when the index.html file is copied to the output directory (build/web) during the build step.

自定义初始化

#

By default, flutter build web generates a flutter_bootstrap.js file that does a simple initialization of your Flutter app. However, in some scenarios, you might have a reason to customize this initialization process, such as:

  • Setting a custom Flutter configuration for your app.
  • Changing the settings for the Flutter service worker.
  • Writing custom JavaScript code to run at different stages of the startup process.

To write your own custom bootstrapping logic instead of using the default script produced by the build step, you can place a flutter_bootstrap.js file in the web subdirectory of your project, which is copied over and used instead of the default script produced by the build. This file is also templated, and you can insert several special tokens that the build step substitutes at build time when copying the flutter_bootstrap.js file to the output directory. The following table lists the tokens that the build step will substitute in either the flutter_bootstrap.js or index.html files:

Token Replaced with
{{flutter_js}} The JavaScript code that makes the FlutterLoader object available in the _flutter.loader global variable. (See the _flutter.loader.load() API section below for more details.)
{{flutter_build_config}} A JavaScript statement that sets metadata produced by the build process which gives the FlutterLoader information needed to properly bootstrap your application.
{{flutter_service_worker_version}} A unique number representing the build version of the service worker, which can be passed as part of the service worker configuration (see the "Service Worker Settings" table below).
{{flutter_bootstrap_js}} As mentioned above, this inlines the contents of the flutter_bootstrap.js file directly into the index.html file. Note that this token can only be used in the index.html and not the flutter_bootstrap.js file itself.

编写自定义的 flutter_bootstrap.js

#

Any custom flutter_bootstrap.js script needs to have three components in order to successfully start your Flutter app:

  • A {{flutter_js}} token, to make _flutter.loader available.
  • A {{flutter_build_config}} token, which provides information about the build to the FlutterLoader needed to start your app.
  • A call to _flutter.loader.load(), which actually starts the app.

The most basic flutter_bootstrap.js file would look something like this:

js
{{flutter_js}}
{{flutter_build_config}}

_flutter.loader.load();

The _flutter.loader.load() API

#

可以使用以下可选参数调用 _flutter.loader.load() JavaScript API,来自定义初始化行为:

参数名称 描述 JS 类型
config 应用程序的 Flutter 配置 Object
onEntrypointLoaded 当引擎准备初始化时调用的函数。该函数的唯一参数是一个 engineInitializer 对象。 Function
serviceWorkerSettings flutter_service_worker.js 加载器的配置。(如果未设置,则不会使用 service worker。) Object

config 是一个对象,你可以添加以下任何可选参数:

参数名称 描述 Dart 类型
assetBase 应用程序 assets 目录的根 URL。当 Flutter 从实际 web 应用不同的域或子目录加载时,请添加此 URL。当你将 Flutter web 嵌入另一个应用程序,或将其静态资源部署到 CDN 时,可能需要使用此 URL。 String
canvasKitBaseUrl 下载 canvaskit.wasm 的根 URL。 String
canvasKitVariant 下载 CanvasKit。你的可选值:

1. auto:为浏览器下载最佳版本。(默认值)
2. full:下载适用于所有浏览器的 CanvasKit 完整版。
3. chromium:下载较小的 CanvasKit,该版本使用与 Chromium 兼容的 API。警告:除非你只打算使用基于 Chromium 的浏览器,否则不要使用 chromium 值。
String
canvasKitForceCpuOnly true 时,强制在 CanvasKit 中只使用 CPU 进行渲染(引擎不会使用 WebGL)。 bool
canvasKitMaximumSurfaces CanvasKit 渲染器可使用的最大覆盖层数。 double
debugShowSemanticNodes 如果为 true,Flutter 会在屏幕上明显呈现 semantics 语义树(用于调试)。 bool
entryPointBaseUrl Flutter 应用入口的根 URL。默认为 "/"。 String
hostElement 用于 Flutter 渲染应用程序的 HTML 元素。未设置时,Flutter web 会占据整个页面。 HtmlElement
renderer 指定当前 Flutter 应用程序的 web 渲染器,可选 "canvaskit""skwasm" String

serviceWorkerSettings 有以下可选参数。

属性名称 描述 JS 类型
serviceWorkerUrl Service Worker JS 文件的 URL。serviceWorkerVersion 会附加到 URL 中。默认为 "flutter_service_worker.js?v=" String
serviceWorkerVersion 构建过程会赋值 serviceWorkerVersion 变量 并在 index.html 中运用。 String
timeoutMillis service worker 负载的超时时间(毫秒)。默认为 4000 Number

示例:根据 URL 查询参数自定义 Flutter 配置

#

下面的示例演示了一个自定义的 flutter_bootstrap.js,他允许用户在网站 URL 中提供一个 ?force_canvaskit=true 的查询参数,从而强制应用使用 CanvasKit 渲染器:

js
{{flutter_js}}
{{flutter_build_config}}

const searchParams = new URLSearchParams(window.location.search);
const renderer = searchParams.get('renderer');
const userConfig = renderer ? {'renderer': renderer} : {};
_flutter.loader.load({
  config: userConfig,
  serviceWorkerSettings: {
    serviceWorkerVersion: {{flutter_service_worker_version}},
  },
});

This script evaluates the URLSearchParams of the page to determine whether the user passed a renderer query parameter and then changes the user configuration of the Flutter app. It also passes the service worker settings to use the flutter service worker, along with the service worker version.

The onEntrypointLoaded callback

#

You can also pass an onEntrypointLoaded callback into the load API in order to perform custom logic at different parts of the initialization process. The initialization process is split into the following stages:

Loading the entrypoint script
The load 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.
Initializing the Flutter engine
The onEntrypointLoaded callback receives an engine initializer object as its only parameter. Use the engine initializer initializeEngine() function to set the run-time configuration, like multiViewEnabled: true, and start the Flutter web engine.
Running the app
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.
Adding views to (or removing views from) an app
The runApp() method returns a flutter app object. In multi-view mode, the addView and removeView methods can be used to manage app views from the host app. To learn more, check out Embedded mode.

示例:显示进度指示器

#

为了在应用程序初始化过程中向用户提供反馈,请使用各个阶段提供的钩子来更新 DOM:

js
{{flutter_js}}
{{flutter_build_config}}

const loading = document.createElement('div');
document.body.appendChild(loading);
loading.textContent = "Loading Entrypoint...";
_flutter.loader.load({
  onEntrypointLoaded: async function(engineInitializer) {
    loading.textContent = "Initializing engine...";
    const appRunner = await engineInitializer.initializeEngine();

    loading.textContent = "Running app...";
    await appRunner.runApp();
  }
});

升级旧项目

#

如果你的项目是在 Flutter 3.21 或更早版本中创建的,你可以通过运行 flutter create 指令创建一个带有最新初始化模板的 index.html 文件,方法如下。

首先,删除 /web 目录中的文件。

然后,在项目目录下运行以下指令:

flutter create . --platforms=web