This directory contains the source code for the Web Engine.
If you are setting up a workspace for the first time, start by following the instructions at Setting up the Engine development environment. In addition, it is useful to add the following to your PATH
environment variable:
ENGINE_ROOT/src/flutter/lib/web_ui/dev
, so you can run the felt
command from anywhere.FLUTTER_ROOT/bin
, so you can run dart
and flutter
commands from anywhere.felt
felt
(stands for “Flutter Engine Local Tester”) is a command-line tool that aims to make development in the Flutter web engine more productive and pleasant.
To tell felt
to do anything you call felt SUBCOMMAND
, where SUBCOMMAND
is one of the available subcommands, which can be listed by running felt help
. To get help for a specific subcommand, run felt help SUBCOMMAND
.
felt build
The build
subcommand builds web engine gn/ninja targets. Targets can be individually specified in the command line invocation, or if none are specified, all web engine targets are built. Common targets are as follows:
sdk
- The flutter_web_sdk itself.canvaskit
- Flutter's version of canvakit.canvaskit_chromium
- A version of canvaskit optimized for use with chromium-based browsers.skwasm
- Builds experimental skia wasm module renderer. The output of these steps is used in unit tests, and can be used with the flutter command via the --local-web-sdk=wasm_release
command.The build
command also accepts either the --profile
or --debug
flags, which can be used to change the build profile of the artifacts.
Builds all web engine targets, then runs a Flutter app using it:
felt build cd path/to/some/app flutter --local-web-sdk=wasm_release run -d chrome
Builds only the sdk
and the canvaskit
targets:
felt build sdk canvaskit
felt test
The test
subcommand will compile and/or run web engine unit test suites. For information on how test suites are structured, see the test configuration readme.
By default, felt test
compiles and runs all suites that are compatible with the host system. Some useful flags supported by this command:
--compile
performs compilation of the test bundles.--run
runs the unit tests--copy-artifacts
will copy build artifacts needed for the tests to run.--profile
or --debug
flags can be specified to copy over artifacts from the profile or debug build folders instead of release.--list
will list all the test suites and test bundles and exit without compiling or running anything.--verbose
will output some extra information that may be useful for debugging.--start-paused
will open a browser window and pause the tests before starting so that breakpoints can be set before starting the test suites.Several other flags can be passed that filter which test suites should be run:
--browser
runs only the test suites that test on the browsers passed. Valid values for this are chrome
, firefox
, safari
, or edge
.--compiler
runs only the test suites that use a particular compiler. Valid values for this are dart2js
or dart2wasm
--renderer
runs only the test suites that use a particular renderer. Valid values for this are html
, canvakit
, or skwasm
--suite
runs a suite by name.--bundle
runs suites that target a particular test bundle.Filters of different types are logically ANDed together, but multiple filter flags of the same type are logically ORed together.
The test
command will also accept a list of paths to specific test files to be compiled and run. If none of these paths are specified, all tests are run, otherwise only the tests that are specified will run.
Runs all test suites in all compatible browsers:
felt test
Runs a specific test on all compatible browsers:
felt test test/engine/util_test.dart
Runs multiple specific tests on all compatible browsers:
felt test test/engine/util_test.dart test/engine/alarm_clock_test.dart
Runs only test suites that compile via dart2wasm:
felt test --compiler dart2wasm
Runs only test suites that run in Chrome and Safari:
felt test --browser chrome --browser safari
Concurrency of various build steps can be configured via environment variables:
FELT_COMPILE_CONCURRENCY
specifies the number of concurrent compiler processes used to compile tests. Default value is 8.If you are a Google employee, you can use an internal instance of Goma (go/ma) to parallelize your ninja builds. Because Goma compiles code on remote servers, this option is particularly effective for building on low-powered laptops.
Chromium, Firefox, and Safari for iOS are version-locked using the browser_lock.yaml configuration file. Safari for macOS is supplied by the computer's operating system. Tests can be run in Edge locally, but Edge is not enabled on LUCI. Chromium is used as a proxy for Chrome, Edge, and other Chromium-based browsers.
Changing parameters in the browser lock is effective immediately when running tests locally. To make changes effective on LUCI follow instructions in [Rolling Browsers][#rolling-browsers].
When running tests on LUCI using Chromium, LUCI uses the version of Chromium fetched from CIPD.
Since the engine code and infra recipes do not live in the same repository there are few steps to follow in order to upgrade a browser's version.
To generate new fallback font data and push the fallback fonts into a CIPD package for engine unit tests to consume, run the following felt command:
cipd auth-login felt roll-fallback-fonts --key=<Google Fonts API key>
This will take the following steps:
font_fallback_data.dart
file that is used in the engineflutter/flutter_font_fallbacks
DEPS
file in the engine to use the new version of the packageTo perform all these steps except actually uploading the package to CIPD, pass the --dry-run
flag to the felt command.
NOTE: Because this script uses fc-config
, this roll step only actually works on Linux, not on macOS or Windows.
Chromium is an independent project that gets rolled into Flutter manually, and as needed. Flutter consumes a pre-built Chromium version from chromium.org. When a new version of Chromium (check here) is needed, follow these steps to roll the new version:
depot_tools
installed (if you are regularly hacking on the engine code, you probably do).cipd auth-login
and follow instructions (this step requires sufficient privileges; contact #hackers-infra-🌡 on Flutter's Discord server).dev/browser_lock.yaml
and update the following values under chrome
:Windows
, Mac
and Linux
to the branch_base_position
s given in this table. (Pick from linux
, mac
and win
as os
, and the stable
channel.)version
to a string composed of the Major Version of the browser, and the number of times that major version has been uploaded to CIPD. For example, start with '99'
for version 99.0.4844.51 of Chromium, and update to '99.1'
, '99.2'
and so on if you need to upload newer bundles of the same major version. (This is required because tags can't be repeated in CIPD).dart dev/browser_roller.dart
and make sure it completes successfully. The script uploads the specified versions of Chromium (and Chromedriver) to the right locations in CIPD: Chrome, Chromedriver.If you have questions, contact the Flutter Web team on Flutter Discord on the #hackers-web-🌍 channel.
We test with Firefox on LUCI in the Linux Web Engine builder. The process for rolling Firefox is even easier than Chromium. Simply update browser_lock.yaml
with the latest version of Firefox, and run browser_roller.dart
.
After rolling Chrome and/or Firefox, also update the CI dependencies in .ci.yaml
to make use of the new versions. The lines look like
dependencies: >- [ {"dependency": "chrome_and_driver", "version": "version:107.0"}, {"dependency": "firefox", "version": "version:83.0"}, {"dependency": "goldctl", "version": "git_revision:3a77d0b12c697a840ca0c7705208e8622dc94603"} ]
The script has the following command-line options:
--dry-run
- The script will stop before uploading artifacts to CIPD. The location of the data will be reported at the end of the script, if the script finishes successfullyThe output of the script will be visible in /tmp/browser-roll-RANDOM_STRING--verbose
- Greatly increase the amount of information printed to stdout
by the script.Try the following!
dart ./dev/browser_roller.dart --dry-run --verbose
In general, the manual process goes like this:
browser_lock.yaml
file.Resources:
browser_lock.yaml
contains the version of browsers we use to test Flutter for web. Versions are not automatically updated whenever a new release is available. Instead, we update this file manually once in a while.
canvaskit_lock.yaml
locks the version of CanvasKit for tests and production use.
To build CanvasKit locally, you must first set up your gclient config to activate the Emscripten SDK, which is the toolchain used to build CanvasKit. To do this, replace the contents of your .gclient file at the root of the project (i.e. in the parent directory of the src
directory) with:
solutions = [ { "managed": False, "name": "src/flutter", "url": "git@github.com:<your_username_here>/engine.git", "custom_deps": {}, "deps_file": "DEPS", "safesync_url": "", "custom_vars": { "download_emsdk": True, }, }, ]
Now run gclient sync
and it should pull in the Emscripten SDK and activate it.
To build CanvasKit with felt
, run:
felt build --build-canvaskit
This will build CanvasKit in out/wasm_debug
. If you now run
felt test
it will detect that you have built CanvasKit and use that instead of the one from CIPD to run the tests against.
The version of the Emscripten SDK should be kept up to date with the version used in the Skia build. That version can be found in third_party/skia/bin/activate-emsdk
. It will probably also be necessary to roll the dependency on third_party/emsdk
in DEPS to the same version as in third_party/skia/DEPS
.
Once you know the version for the Emscripten SDK, change the line in tools/activate_emsdk.py
which defines EMSDK_VERSION
to match Skia.
We pull the unicode properties we need from third_party/web_unicode
. See third_party/web_unicode/README.md
for more details on how we generate Dart code from unicode properties.