Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.

[web] Unify JS configuration. Make it available from initEngine. #37187

Merged
merged 15 commits into from
Nov 4, 2022

Conversation

ditman
Copy link
Member

@ditman ditman commented Nov 1, 2022

Changes

This PR does most of the configuration work (including a stretch goal) described in this document.

In particular, it extends the currently existing plumbing to pass and store Flutter engine configuration from JS (through the initializeEngine method).

The configuration system now behaves like this:

  1. The already existing JsFlutterConfiguration JS-interop class is reused in the flutter.js EngineInitializer object so config passing from HTML -> Flutter stays the same across: the global variable, and initEngine call.
  2. Users are warned that the old JS global variables (window.flutterConfiguration and window.flutterWebRenderer) are now deprecated, and that they should use engineInitializer.initializeEngine(config) instead.
  3. An assertion is thrown in apps that use BOTH configuration methods, so users remember to clean-up the globals in their index.html (in release, it uses whatever comes from the initializeEngine call).

Demo

This PR, not only adds a hostElement parameter (unused for now), but also all the properties defined in the configuration.dart file. For now:

  • renderer
  • canvasKitBaseUrl
  • canvasKitMaximumSurfaces
  • canvasKitForceCpuOnly
  • hostElement
  • debugShowSemanticsNodes

Here's a demo of an app running this code, and configuring everything from its index.html.

Note that the demo has a warning, because it's using a deprecated configuration style:

Screen Shot 2022-11-02 at 6 33 11 PM

The demo does fail with an assertion in development mode:

Screen Shot 2022-11-02 at 6 41 02 PM

TL;DR API:

//...
onEntrypointLoaded: async function(engineInitializer) {
  let appRunner = await engineInitializer.initializeEngine({
    renderer: 'canvaskit',
    canvasKitBaseUrl: 'canvaskit/',
    canvasKitMaximumSurfaces: 64,
    targetElement: document.querySelector('#flutter_target'),
     // ... other config ...
  });
  appRunner.runApp();
}

Issues

Testing

  • Manually deployed: https://dit-tests.web.app
  • Added some unit tests:
    • configuration object new features
    • initialization process accepts and stores configuration

Pre-launch Checklist

  • I read the Contributor Guide and followed the process outlined there for submitting PRs.
  • I read the Tree Hygiene wiki page, which explains my responsibilities.
  • I read and followed the Flutter Style Guide and the C++, Objective-C, Java style guides.
  • I listed at least one issue that this PR fixes in the description above.
  • I added new tests to check the change I am making or feature I am adding, or Hixie said the PR is test-exempt. See testing the engine for instructions on writing and running engine tests.
  • I updated/added relevant documentation (doc comments with ///).
  • I signed the CLA.
  • All existing and new tests are passing.

If you need help, consider asking for advice on the #hackers-new channel on Discord.

@flutter-dashboard flutter-dashboard bot added the platform-web Code specifically for the web engine label Nov 1, 2022
@ditman ditman changed the title [web][wip] Unify JS configuration. Make it available on initEngine. [web][wip] Unify JS configuration. Make it available from initEngine. Nov 1, 2022
@ditman ditman changed the title [web][wip] Unify JS configuration. Make it available from initEngine. [web] Unify JS configuration. Make it available from initEngine. Nov 2, 2022
Copy link
Contributor

@eyebrowsoffire eyebrowsoffire left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good, with a small nitpick.

One suggestion, take it or leave it: It might be nice if FlutterConfiguration and JSFlutterConfiguration shared the same base class with the different configuration getters on it. That way, if a new field is added to the configuration, the analyzer will tell you that you need to add it to both classes. I'm not sure if this gets weird with the static interop stuff, so if it's too much of a pain feel free to ignore.

import 'js_interop/js_loader.dart';
import 'js_interop/js_promise.dart';

/// The type of a function that initializes an engine (in Dart)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: end dartdocs with a period.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ditman
Copy link
Member Author

ditman commented Nov 3, 2022

It might be nice if FlutterConfiguration and JSFlutterConfiguration shared the same base class with the different configuration getters on it. That way, if a new field is added to the configuration, the analyzer will tell you that you need to add it to both classes. I'm not sure if this gets weird with the static interop stuff, so if it's too much of a pain feel free to ignore.

@eyebrowsoffire I think that extending js-interop classes with dart classes (and vice versa?) is a big no-no. (Maybe that's why the FlutterConfiguration currently just wraps the JsFlutterConfiguration?)

This is a great suggestion, though! (I'd try it if I didn't have the suspicion that it can break wasm interop :P) One drawback: wouldn't that mean that people need to specify the getter name in 3 places, rather than 2? Also, if they forget to set it in the base class, but not in the JS/Dart implementations, everything would Still Work™.

If I could define the getters somehow ONCE, I'd be 100% sold.

@ditman
Copy link
Member Author

ditman commented Nov 3, 2022

I think I addressed all the comments in the PR. PTAL @yjbanov, @eyebrowsoffire! And thanks for the review!

@ditman
Copy link
Member Author

ditman commented Nov 3, 2022

Please, do make sure we like the names for the new JsFlutterConfiguration values that this PR is adding:

  external DomElement? get hostElement;
  external String? get renderer;

once this lands, they become public API (the other 4 values already existed in the object).

Copy link
Contributor

@mdebbar mdebbar left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

///
/// Both methods are **disallowed** to be used at the same time.
///
/// Example (Before):
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd remove the "before" parts, let's boldly step into the new world! :)

Copy link
Member Author

@ditman ditman Nov 4, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I disagree, I'll remove these docs when we clean up the deprecated code. What I'm going to do, however, is move the new style to the top (and not call it "after"/"new" or anything), and move the legacy style underneath.

@yjbanov
Copy link
Contributor

yjbanov commented Nov 4, 2022

It might be nice if FlutterConfiguration and JSFlutterConfiguration shared the same base class

@eyebrowsoffire @ditman I've always been suspicious about using inheritance for classes used to pass data, as opposed to delivering behavior. There are some expectations that come with inheritance that may not be appropriate. For example, there's the Liskov substitution principle which doesn't make sense for this case. I've always preferred composition for data over inheritance.

@ditman ditman self-assigned this Nov 4, 2022
* Extend configuration.dart
* Reuse JsFlutterConfiguration JS-interop as the configuration source
  both for initEngine, and the window.flutterConfig object.
* Add 'renderer' and 'targetElement' fields to the
  JsFlutterConfiguration object.
* Modify the `FlutterConfiguration` object so that it supports more
  than one configuration source. Return the first non-null value that
  was most recently set, or fall back to a default.
* runtimeConfig -> configuration (as unnamed function parameter)
* runtimeConfiguration -> jsConfiguration (as named function parameter,
to prevent clashes with the configuration singleton in the engine code)
* initEngine -> initializeEngine (because no need to abbreviate that)
@ditman ditman force-pushed the js-configuration-replumbing branch from 7ab4b89 to 86f663d Compare November 4, 2022 19:00
@ditman
Copy link
Member Author

ditman commented Nov 4, 2022

Rebased to see if it heals the failing "impeller" tests.

@ditman ditman added the autosubmit Merge PR when tree becomes green via auto submit App label Nov 4, 2022
@auto-submit auto-submit bot merged commit ba390f2 into flutter:main Nov 4, 2022
@ditman ditman deleted the js-configuration-replumbing branch November 4, 2022 22:36
engine-flutter-autoroll added a commit to engine-flutter-autoroll/flutter that referenced this pull request Nov 5, 2022
auto-submit bot pushed a commit to flutter/flutter that referenced this pull request Nov 5, 2022
…114728)

* 24c3a9f51 fix recursive self calls (flutter/engine#37321)

* 2a1be6d4d Roll Skia from dc49f35e1ac6 to 7a98accb20d5 (6 revisions) (flutter/engine#37328)

* ba390f2a7 [web] Unify JS configuration. Make it available from initEngine. (flutter/engine#37187)
schwa423 pushed a commit to schwa423/engine that referenced this pull request Nov 16, 2022
…tter#37187)

* Add the 'windows' parameter to the initializeEngine function.

* Wire the initEngine configuration into the engine.

* Extend configuration.dart
* Reuse JsFlutterConfiguration JS-interop as the configuration source
  both for initEngine, and the window.flutterConfig object.
* Add 'renderer' and 'targetElement' fields to the
  JsFlutterConfiguration object.
* Modify the `FlutterConfiguration` object so that it supports more
  than one configuration source. Return the first non-null value that
  was most recently set, or fall back to a default.

* Silence bootstrap initialization log to debug level.

* targetElement to hostElement

* jsParams -> runtimeConfiguration

* Add configuration_test.dart

* Add test to check init stores config.

* Renamed test so it actually runs.

* Update configuration object. Make it throwy at init/override.

* Use new config object, tweak some docs.

* Tweak warn/assert messages.

* Some renaming:

* runtimeConfig -> configuration (as unnamed function parameter)
* runtimeConfiguration -> jsConfiguration (as named function parameter,
to prevent clashes with the configuration singleton in the engine code)
* initEngine -> initializeEngine (because no need to abbreviate that)

* Ensure init test does not use global config.

* Sort JsFlutterConfiguration getters alphabetically.

* Addresses PR comments.
shogohida pushed a commit to shogohida/flutter that referenced this pull request Dec 7, 2022
…lutter#114728)

* 24c3a9f51 fix recursive self calls (flutter/engine#37321)

* 2a1be6d4d Roll Skia from dc49f35e1ac6 to 7a98accb20d5 (6 revisions) (flutter/engine#37328)

* ba390f2a7 [web] Unify JS configuration. Make it available from initEngine. (flutter/engine#37187)
gspencergoog pushed a commit to gspencergoog/flutter that referenced this pull request Jan 19, 2023
…lutter#114728)

* 24c3a9f51 fix recursive self calls (flutter/engine#37321)

* 2a1be6d4d Roll Skia from dc49f35e1ac6 to 7a98accb20d5 (6 revisions) (flutter/engine#37328)

* ba390f2a7 [web] Unify JS configuration. Make it available from initEngine. (flutter/engine#37187)
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
autosubmit Merge PR when tree becomes green via auto submit App platform-web Code specifically for the web engine
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[web] Unify configuration into a single entrypoint. [web] Allow passing a hostElement via JS config to the engine.
4 participants