-
Notifications
You must be signed in to change notification settings - Fork 215
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Simplify the communication between the browser host and iframe #2065
Comments
I do not plan to have local tests validating backwards compatibility at any step here since I don't expect any step to be long lived. I plan on manually verifying cross compatibility as we go. Existing tests within each of the three relevant repositories will ensure that the used set of cross compatibilities are working as we use them, so the risk is only that some steps might need multiple PRs if a problem surfaces trying to land it in the next repo. |
Add a `parent` getter on `window`. Use it to post a parent message instead of a private copy of the JS interop for the same. This had been using `@JS()` locally as a workaround for a bug in `dart:html`, and now that we aren't using `dart:html` anywhere in this code we can drop the extra copy. Expose the `source` field on `MessageEvent`. Use `js_util` to read the properties which may be missing to get to the `href` for the message. Trying to read the field through `dart:html` could throw, but after the migration to `@JS()` style interop the difference interfaces for the event source can be handled safely. Even though the host is no longer reading the href key from the messages they are still sent from the frame side for backwards compatibility with other host implementations. See #2065
We saw in a recent issue changing some code in |
Add a `parent` getter on `window`. Use it to post a parent message instead of a private copy of the JS interop for the same. This had been using `@JS()` locally as a workaround for a bug in `dart:html`, and now that we aren't using `dart:html` anywhere in this code we can drop the extra copy. Expose the `source` field on `MessageEvent`. Use `js_util` to read the properties which may be missing to get to the `href` for the message. Trying to read the field through `dart:html` could throw, but after the migration to `@JS()` style interop the difference interfaces for the event source can be handled safely. Even though the host is no longer reading the href key from the messages they are still sent from the frame side for backwards compatibility with other host implementations. See #2065
Towards #2065 Refactor the current implementation to reduce complexity and keep the code for the current behavior within the condition body. This will allow the new behavior to be implemented in another branch of the conditional. - Remove the `readyCompleter`. Don't start listening on the server channel until the frame communication is ready instead of eagerly listening and holding the messages callbacks awaiting the ready future. - Keep only the long-term message channel in the stored subscriptions. We only expect a single message on the window channel from each frame, so we can cancel the subscription after we receive it.
Towards #2065 Refactor the current implementation to reduce complexity and keep the code for the current behavior within the condition body. This will allow the new behavior to be implemented in another branch of the conditional. - Remove the `readyCompleter`. Don't start listening on the server channel until the frame communication is ready instead of eagerly listening and holding the messages callbacks awaiting the ready future. - Keep only the long-term message channel in the stored subscriptions. We only expect a single message on the window channel from each frame, so we can cancel the subscription after we receive it.
Towards #2065 Handle the new communication pattern from the host side. Allows the frame to send a single `'port'` message with a read `MessageChannel` in stead of the `{'ready': true}` message signalling that the host should send a message port. This will remove one hop in the communication pattern. Retains handling of the current pattern and does not update the frame side yet. There are multiple implementations of both the host and the frame behavior. All host implementations will be updated to allow either pattern before the frame implementations are updated. Change from a `if/else` chain to a `switch`. Use pattern matching to destructure the `'data'` field in the case of exceptions.
Towards #2065 Handle the new communication pattern from the host side. Allows the frame to send a single `'port'` message with a read `MessageChannel` in stead of the `{'ready': true}` message signalling that the host should send a message port. This will remove one hop in the communication pattern. Retains handling of the current pattern and does not update the frame side yet. There are multiple implementations of both the host and the frame behavior. All host implementations will be updated to allow either pattern before the frame implementations are updated. Change from a `if/else` chain to a `switch`. Use pattern matching to destructure the `'data'` field in the case of exceptions. Don't append the frame to the dom until the window message listener is listening.
Towards #2065 All host implementations are updated to allow either the legacy format, or this new format. Simplify the communication and avoid a listener on the frame window message events. Upon startup replace the `{'ready': true}` message with a `'port'` message and the `MessagePort` for a channel created on the frame side. Omit the manual 'href' field, no host implementations would read it.
Towards dart-lang/test#2065 The flutter test runner uses the copy of `host.dart.js` from the copy of `package:test` that surfaces in the pub solve for `flutter_tool`. This copy has been updated to allow either the old pattern of communication, or this new pattern. The new pattern removes an extra hop and use of the frame `window.onMessage` messages.
Towards #2065 All host implementations are updated to allow either the legacy format, or this new format. Simplify the communication and avoid a listener on the frame window message events. Upon startup replace the `{'ready': true}` message with a `'port'` message and the `MessagePort` for a channel created on the frame side. Omit the manual 'href' field, no host implementations would read it.
Towards dart-lang/test#2065 The flutter test runner uses the copy of `host.dart.js` from the copy of `package:test` that surfaces in the pub solve for `flutter_tool`. This copy has been updated to allow either the old pattern of communication, or this new pattern. The new pattern removes an extra hop and use of the frame `window.onMessage` messages.
Closes #2065 All known iframe side implementations have been updated to send the `'port'` message with an immediately available channel over the map and the extra window message. Move some still relevant `assert` into the implementation for the current approach.
Closes #2065 All known iframe side implementations have been updated to send the `'port'` message with an immediately available channel over the map and the extra window message. Move some still relevant `assert` into the implementation for the current approach.
See dart-lang/test#2065 Multiple copies of the host and iframe side implementations have been updated, but this copy of `host.dart` was missed. Apply some of the changes from the linked test issue to this copy. - Add `MessageEventSource` and `MessageEventSourceLocation` interop classes. The frame side communication no longer includes an `href` field in the map, read it through `message.source.location`. - Move the `DomMessageChannel` initiation into the handler for the `{'ready': true}` event. This removes the need for the `readyCompleter` since we do not start forwarding messages until the port is ready for use. - Add handling for the new pattern, when the iframe sends a message with the string `'port'` instead of a Map.
- Update the pinned version of `test` to the latest published. - Add support for reading the `source.location` of messages to the JS interop library. - Update `host.dart` to support the new communication pattern with the test frame. See dart-lang/test#2065 - Use `Runtime.edge` for the edge browser. We may deprecate or remove the constant. Edge is a more appropriate value for this usage.
- Update the pinned version of `test` to the latest published. - Add support for reading the `source.location` of messages to the JS interop library. - Update `host.dart` to support the new communication pattern with the test frame. See dart-lang/test#2065 - Use `Runtime.edge` for the edge browser. We may deprecate or remove the constant. Edge is a more appropriate value for this usage.
Currently there are 3 hops during startup.
This communication all happens an an opaque way, especially on remote CI infrastructure, and may be involved with some flakes that we see in a few places where browser tests never start. We should simplify the communication, and add some logging to see if we can get any insight into the cause of the flakes.
A better pattern would be
MessageChannelPort
to the parent and wires it up to the channel.Separately, we have some unnecessary legacy behavior with extra messages that turned out to be a no-op round trip sending a signal back to the calling code to continue. We can clean that up in the same pass - I've already removed the usage in source but have not yet released that version internally.
#2061 does the full refactoring, and would be safe to land if this was the only test runner. As mentioned in #2061 (comment) we will need to do this in multiple steps with backwards compatibility along the way because there is another copy of both sides of the implementation, and we cannot roll them all atomically.
Somewhat interesting side note - Even though the flutter use case doesn't pin
package:test
as adependency
, they reach into the pub solve within the flutter SDK to find the version oftest
pinned through adev_dependency
and use that version of the compiled host js.My plan is to:
host.dart
side to handle either behavior - it receives the first message and can know what version of the iframe it is communicating with.postMessageChannel
to the new behavior.postMessageChannel
to the new behavior.host.dart
.@jakemac53 - do you have any concerns?
The text was updated successfully, but these errors were encountered: