-
Notifications
You must be signed in to change notification settings - Fork 28.6k
[web] fix hot restart in entrypoint generated by flutter create
#110229
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
Conversation
fab0d39
to
40c4758
Compare
flutter create
flutter create
} | ||
|
||
Future<void> _generateEntrypoint() async { | ||
final Directory tempDirectory = Directory.systemTemp.createTempSync('flutter_web_generated_entrypoint.'); |
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 the trailing .
in the directory name intended or a typo?
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's intended. I stole it from another test from test.dart
. I'm now considering it a "convention" :)
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.
yeah, i think a hash gets appended, so the trailing .
looks cleaner
@@ -0,0 +1,2 @@ | |||
# This file is generated by a test. It should not be committed to source control. | |||
generated_entrypoint.html |
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.
Why not git-ignore the entire directory flutter_web_generated_entrypoint/
?
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.
flutter_web_generated_entrypoint
is a temp directory outside the source tree that's created then deleted (see Directory.systemTemp.createTempSync
). It's only used as a temporary space to dump an entire project. The test actually only needs the index.html
. It doesn't need the "counter app" Dart code.
onEntrypointLoaded: function(engineInitializer) { | ||
engineInitializer.initializeEngine().then(function(appRunner) { | ||
appRunner.runApp(); | ||
}); |
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 a potential race condition. I would suggest adding a global counter then doing:
onEntrypointLoaded: function(engineInitializer) { | |
engineInitializer.initializeEngine().then(function(appRunner) { | |
appRunner.runApp(); | |
}); | |
onEntrypointLoaded: function(engineInitializer) { | |
currentCounter++; | |
final int storedCounter = currentCounter; | |
engineInitializer.initializeEngine().then(function(appRunner) { | |
// Make sure this is not a stale promise. | |
if (storedCounter == currentCounter) { | |
appRunner.runApp(); | |
} | |
}); |
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.
I'd like to understand more about the race condition. What is racing against what? I think if there is one, we should definitely handle it. However, I think we should avoid relying on user code to fix it (this code is generated once then it can be edited by the app developer), and instead fix the race in flutter.js
itself.
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.
I was thinking of the case when onEntrypointLoaded
is invoked again before the previous engine initialization promise was resolved. I don't know if this case is possible or not. Maybe if the user hot-reloads multiple times in a row?
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, yeah, that's a legitimate concern. However, I think it should be addressed at the flutter.js
level, if it isn't already. flutter.js
should be aware of which phase the loading process the app is in. For example, if onEntrypointLoaded
has been called, engineInitializer.initializeEngine()
has been called, but the promise hasn't resolved yet, and the user hot-restarts now, then the Promise
from initializeEngine
should not be resolved (or perhaps it should be rejected).
OTOH, something tells me that if our initialization process is interrupted by hot restart, then all bets are off. We have so much intricate async initialization logic - root DOM nodes, fonts, CanvasKit, service worker - that there are many places that would be easily corrupted by such interruption. Perhaps what we need is some collaboration between the framework and the tool, where the tool first sends an "intent" to hot restart, and the framework sends back a signal when it's safe to do so. I'm not sure it's practical for us to try and support hot restarts at completely random points in time.
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.
That's fair. If possible, we should at least print a warning (in flutter.js
) when this race condition is detected, and ask the user to refresh the page instead.
That said, I think this race condition has existed for a while (and nobody complained) so it's probably not as important as I thought it was.
Fix entrypoint generated by
flutter create
to support hot restart. #108776 fixed hot restart, but it requires an update toindex.html
. Soflutter create
should have been updated.Fixes #109093
Pre-launch Checklist
///
).If you need help, consider asking for advice on the #hackers-new channel on Discord.