-
Notifications
You must be signed in to change notification settings - Fork 6k
Implement browser history class for router widget #20794
Conversation
It looks like this pull request may not have tests. Please make sure to add tests before merging. If you need an exemption to this rule, contact Hixie on the #hackers channel in Chat. Reviewers: Read the Tree Hygiene page and make sure this patch meets those guidelines before LGTMing. |
hi @goderbauer @mdebbar, I have this draft to implement engine side changes for router widget. Unfortunately I have to change the API of BrowserHistory a bit so that i can switch between two mechanisms when it receive different notifications. Let me know if this is the direction we want to go, i will write test later if so. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Overall, this is heading in a good direction.
I had one concern about tearing off location strategies. If the app pushes route names /foo
and /bar
, the hash location strategy will push 2 history entries with route names /#/foo
and /#/bar
. Now let's say the app switches to a different location strategy. The entire browser history will be lost.
But after I gave it some thought, I realized that that's okay. We don't expect apps to suddenly change their location strategy. The app should configure the location strategy before the app runs, and that's it. So maybe we should assert somewhere that the location strategy doesn't change anymore?
Another question is: do we even want to keep the SingleEntryBrowserHistory
? Should we just replace it with MultiEntriesBrowserHistory
for all apps (and in that case, we don't have to worry about switching between history implementations)?
@mdebbar If we remove the single entry one, we may need to figure out what to do with the information when backward button is pressed. I have an idea that may work except forward. When the backward button is pushed, we can calculate how many states were poped by using the _flutterHistoryCount and just issue that many of pop to the framework (we may still need a way to figure out whether we are currently using router or navigator). However, I haven't come up with a way to deal forward button. If we forward more than one state, we need to have a way to know all the intermediate urls to push new routes onto navigator which i am not sure if it is possible? edit: I think we can keep an internal copy of states list so that we can figure out all the intermediate urls when doing forward. I think that will work, I will try to update this pr with the new design |
d998767
to
df5c426
Compare
Hi @mdebbar, this is ready for another look! |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is looking really good! All my comments are minor/non-blocking.
/// a Router for routing. | ||
class MultiEntriesBrowserHistory extends BrowserHistory { | ||
int _lastSeenSerialCount = 0; | ||
int get _getCurrentSerialCount { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Suggestion: remove the get
prefix from _getCurrentSerialCount
.
|
||
@override | ||
void setRouteName(String? routeName, {dynamic? state}) { | ||
if (locationStrategy != null && routeName != null) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could you add a comment here explaining why we are ignoring null route names?
@override | ||
Future<void> tearDown() async { | ||
// Restores the html browser history. | ||
if (_hasSerialCount(currentState)) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If everything goes well, this condition should always be true right? If it's false, that means someone other than us is modifying history state. What do you think about doing an assert
instead?
} | ||
// Unwrap state. | ||
locationStrategy!.replaceState( | ||
currentState['state'], |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is it possible for currentState
to be null here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
it is impossible otherwise the _hasSerialCount(currentState) will be false
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
currentState
here is different from the one we passed to _hasSerialCount
above.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ah yes, you are right, but it still shouldn't be null because we also wrap it with serial count 0.
I will add some assert
final LocationStrategy? strategy = _browserHistory.locationStrategy; | ||
await _browserHistory.setLocationStrategy(null); | ||
_browserHistory = MultiEntriesBrowserHistory(); | ||
await _browserHistory.setLocationStrategy(strategy); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No need to do this if strategy
is null?
This pull request is not suitable for automatic merging in its current state.
|
@chunhtai @mdebbar I'm on the latest master with Navigator 2.0 and I am getting the following when running chrome in debug mode when I navigate to a link. The app continues to work but the url doesn't update. ══╡ EXCEPTION CAUGHT BY FLUTTER FRAMEWORK ╞═════════════════════════════════════════════════════════
The following assertion was thrown:
Assertion failed: org-dartlang-sdk:///flutter_web_sdk/lib/_engine/engine/window.dart:102:16
browserHistory is MultiEntriesBrowserHistory
is not true
When the exception was thrown, this was the stack:
dart-sdk/lib/_internal/js_dev_runtime/private/ddc_runtime/errors.dart 216:49 throw_
dart-sdk/lib/_internal/js_dev_runtime/private/ddc_runtime/errors.dart 24:3 assertFailed
lib/_engine/engine/window.dart 102:16 handleNavigationMessage
dart-sdk/lib/_internal/js_dev_runtime/patch/async_patch.dart 84:54 runBody
dart-sdk/lib/_internal/js_dev_runtime/patch/async_patch.dart 123:12 _async
lib/_engine/engine/window.dart 90:39 handleNavigationMessage
lib/_engine/engine/platform_dispatcher.dart 411:19 [_sendPlatformMessage]
lib/_engine/engine/platform_dispatcher.dart 216:5 sendPlatformMessage
packages/flutter/src/services/binding.dart 259:36 [_sendPlatformMessage]
packages/flutter/src/services/binding.dart 308:12 send
packages/flutter/src/services/platform_channel.dart 149:52 _invokeMethod
dart-sdk/lib/_internal/js_dev_runtime/patch/async_patch.dart 84:54 runBody
dart-sdk/lib/_internal/js_dev_runtime/patch/async_patch.dart 123:12 _async
packages/flutter/src/services/platform_channel.dart 147:30 [_invokeMethod]
packages/flutter/src/services/platform_channel.dart 475:3 [_invokeMethod]
packages/flutter/src/services/platform_channel.dart 462:18 invokeMethod
dart-sdk/lib/_internal/js_dev_runtime/patch/async_patch.dart 84:54 runBody
dart-sdk/lib/_internal/js_dev_runtime/patch/async_patch.dart 123:12 _async
packages/flutter/src/services/platform_channel.dart 461:29 invokeMethod
packages/flutter/src/services/system_navigator.dart 45:31 routeInformationUpdated
packages/flutter/src/widgets/router.dart 1192:21 routerReportsNewRouteInformation
packages/flutter/src/widgets/router.dart 468:20 [_reportRouteInformation]
packages/flutter/src/scheduler/binding.dart 1119:15 [_invokeFrameCallback]
packages/flutter/src/scheduler/binding.dart 1065:9 handleDrawFrame
packages/flutter/src/scheduler/binding.dart 973:5 [_handleDrawFrame]
lib/_engine/engine/platform_dispatcher.dart 892:13 invoke
lib/_engine/engine/platform_dispatcher.dart 145:5 invokeOnDrawFrame
lib/_engine/engine.dart 244:45 <fn>
dart-sdk/lib/async/zone.dart 1202:13 _rootRunUnary
dart-sdk/lib/async/zone.dart 1097:19 runUnary
dart-sdk/lib/async/zone.dart 1002:7 runUnaryGuarded
dart-sdk/lib/async/zone.dart 1039:26 <fn> If I build the app with
Any ideas what might be causing the issue and what to investigate further? Should I create this as a separate issue? I ran into this thread by searching for MultiEntriesBrowserHistory. |
@venkatd this happen when you have a router and a navigator that send message to engine at the same time. |
@chunhtai thanks for clarifying. Just so I understand, I should not instantiate a I have removed all references to return MaterialApp.router(
title: 'Turtle',
debugShowCheckedModeBanner: false,
theme: turtleMaterialTheme,
routerDelegate: routerDelegate,
routeInformationParser: TurtleRouteInfoParser(),
); However, I continue to get the exception in debug mode. |
Using navigator should be fine, as long as they don't have https://api.flutter.dev/flutter/widgets/Navigator/reportsRouteUpdateToEngine.html set to true. |
Sure let me try to create a reproducible example and I will file a bug report. (And FYI I don't have that reportsRouteUpdateToEngine set to true explicitly anywhere and it looks like it defaults to false if unset.) Edit @chunhtai turns out it was a bug on my end as I was mistakenly instantiating a Navigator instance. Would you like me to create an issue to improve the error message? |
Description
Refactor the existing BrowserHistory class and implements a new class to handle the router widget.
Related Issues
Fixes flutter/flutter#64494
Tests
I added the following tests:
TBD after people agree with this approach
Checklist
Before you create this PR confirm that it meets all requirements listed below by checking the relevant checkboxes (
[x]
). This will ensure a smooth and quick review process.Breaking Change
Did any tests fail when you ran them? Please read handling breaking changes.