Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Sign in
Toggle navigation
F
Front-End
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
abdullh.alsoleman
Front-End
Commits
cc51ad5d
Unverified
Commit
cc51ad5d
authored
Nov 08, 2019
by
Jonah Williams
Committed by
GitHub
Nov 08, 2019
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Reland: enable usage of experimental web compiler (#44400)
parent
8f2ea9d0
Changes
21
Hide whitespace changes
Inline
Side-by-side
Showing
21 changed files
with
973 additions
and
312 deletions
+973
-312
linux_chrome_dev_mode.dart
dev/devicelab/bin/tasks/linux_chrome_dev_mode.dart
+1
-1
macos_chrome_dev_mode.dart
dev/devicelab/bin/tasks/macos_chrome_dev_mode.dart
+1
-1
web_incremental_test.dart
dev/devicelab/bin/tasks/web_incremental_test.dart
+10
-0
windows_chrome_dev_mode.dart
dev/devicelab/bin/tasks/windows_chrome_dev_mode.dart
+1
-1
web_dev_mode_tests.dart
dev/devicelab/lib/tasks/web_dev_mode_tests.dart
+43
-9
manifest.yaml
dev/devicelab/manifest.yaml
+7
-0
artifacts.dart
packages/flutter_tools/lib/src/artifacts.dart
+1
-1
resident_web_runner.dart
...utter_tools/lib/src/build_runner/resident_web_runner.dart
+488
-243
daemon.dart
packages/flutter_tools/lib/src/commands/daemon.dart
+1
-1
run.dart
packages/flutter_tools/lib/src/commands/run.dart
+1
-1
compile.dart
packages/flutter_tools/lib/src/compile.dart
+0
-1
devfs.dart
packages/flutter_tools/lib/src/devfs.dart
+7
-0
features.dart
packages/flutter_tools/lib/src/features.dart
+5
-0
bootstrap.dart
packages/flutter_tools/lib/src/web/bootstrap.dart
+12
-8
chrome.dart
packages/flutter_tools/lib/src/web/chrome.dart
+5
-0
devfs_web.dart
packages/flutter_tools/lib/src/web/devfs_web.dart
+199
-11
web_runner.dart
packages/flutter_tools/lib/src/web/web_runner.dart
+1
-1
build_web_test.dart
...er_tools/test/commands.shard/hermetic/build_web_test.dart
+2
-1
resident_web_runner_cold_test.dart
...ols/test/general.shard/resident_web_runner_cold_test.dart
+7
-3
resident_web_runner_test.dart
...er_tools/test/general.shard/resident_web_runner_test.dart
+155
-16
devfs_web_test.dart
.../flutter_tools/test/general.shard/web/devfs_web_test.dart
+26
-13
No files found.
dev/devicelab/bin/tasks/linux_chrome_dev_mode.dart
View file @
cc51ad5d
...
...
@@ -6,5 +6,5 @@ import 'package:flutter_devicelab/framework/framework.dart';
import
'package:flutter_devicelab/tasks/web_dev_mode_tests.dart'
;
Future
<
void
>
main
()
async
{
await
task
(
createWebDevModeTest
());
await
task
(
createWebDevModeTest
(
WebDevice
.
webServer
,
false
));
}
dev/devicelab/bin/tasks/macos_chrome_dev_mode.dart
View file @
cc51ad5d
...
...
@@ -6,5 +6,5 @@ import 'package:flutter_devicelab/framework/framework.dart';
import
'package:flutter_devicelab/tasks/web_dev_mode_tests.dart'
;
Future
<
void
>
main
()
async
{
await
task
(
createWebDevModeTest
());
await
task
(
createWebDevModeTest
(
WebDevice
.
webServer
,
false
));
}
dev/devicelab/bin/tasks/web_incremental_test.dart
0 → 100644
View file @
cc51ad5d
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import
'package:flutter_devicelab/framework/framework.dart'
;
import
'package:flutter_devicelab/tasks/web_dev_mode_tests.dart'
;
Future
<
void
>
main
()
async
{
await
task
(
createWebDevModeTest
(
WebDevice
.
chrome
,
true
));
}
dev/devicelab/bin/tasks/windows_chrome_dev_mode.dart
View file @
cc51ad5d
...
...
@@ -6,5 +6,5 @@ import 'package:flutter_devicelab/framework/framework.dart';
import
'package:flutter_devicelab/tasks/web_dev_mode_tests.dart'
;
Future
<
void
>
main
()
async
{
await
task
(
createWebDevModeTest
());
await
task
(
createWebDevModeTest
(
WebDevice
.
webServer
,
false
));
}
dev/devicelab/lib/tasks/web_dev_mode_tests.dart
View file @
cc51ad5d
...
...
@@ -20,12 +20,21 @@ const String kFirstRecompileTime = 'FirstRecompileTime';
const
String
kSecondStartupTime
=
'SecondStartupTime'
;
const
String
kSecondRestartTime
=
'SecondRestartTime'
;
TaskFunction
createWebDevModeTest
(
)
{
abstract
class
WebDevice
{
static
const
String
chrome
=
'chrome'
;
static
const
String
webServer
=
'web-server'
;
}
TaskFunction
createWebDevModeTest
(
String
webDevice
,
bool
enableIncrementalCompiler
)
{
return
()
async
{
final
List
<
String
>
options
=
<
String
>[
'--hot'
,
'-d'
,
'web-server'
,
'--verbose'
,
'--resident'
,
'--target=lib/main.dart'
,
'--hot'
,
'-d'
,
webDevice
,
'--verbose'
,
'--resident'
,
'--target=lib/main.dart'
,
];
int
hotRestartCount
=
0
;
final
String
expectedMessage
=
webDevice
==
WebDevice
.
webServer
?
'Recompile complete'
:
'Reloaded application'
;
final
Map
<
String
,
int
>
measurements
=
<
String
,
int
>{};
await
inDirectory
<
void
>(
flutterDirectory
,
()
async
{
rmTree
(
_editedFlutterGalleryDir
);
...
...
@@ -38,6 +47,8 @@ TaskFunction createWebDevModeTest() {
<
String
>[
'packages'
,
'get'
],
environment:
<
String
,
String
>{
'FLUTTER_WEB'
:
'true'
,
if
(
enableIncrementalCompiler
)
'WEB_INCREMENTAL_COMPILER'
:
'true'
,
},
);
await
packagesGet
.
exitCode
;
...
...
@@ -46,16 +57,26 @@ TaskFunction createWebDevModeTest() {
flutterCommandArgs
(
'run'
,
options
),
environment:
<
String
,
String
>{
'FLUTTER_WEB'
:
'true'
,
if
(
enableIncrementalCompiler
)
'WEB_INCREMENTAL_COMPILER'
:
'true'
,
},
);
final
Completer
<
void
>
stdoutDone
=
Completer
<
void
>();
final
Completer
<
void
>
stderrDone
=
Completer
<
void
>();
final
Stopwatch
sw
=
Stopwatch
()..
start
();
bool
restarted
=
false
;
process
.
stdout
.
transform
<
String
>(
utf8
.
decoder
)
.
transform
<
String
>(
const
LineSplitter
())
.
listen
((
String
line
)
{
// TODO(jonahwilliams): non-dwds builds do not know when the browser is loaded.
if
(
line
.
contains
(
'Ignoring terminal input'
))
{
Future
<
void
>.
delayed
(
const
Duration
(
seconds:
1
)).
then
((
void
_
)
{
process
.
stdin
.
write
(
restarted
?
'q'
:
'r'
);
});
return
;
}
if
(
line
.
contains
(
'To hot restart'
))
{
// measure clean start-up time.
sw
.
stop
();
...
...
@@ -63,9 +84,10 @@ TaskFunction createWebDevModeTest() {
sw
..
reset
()
..
start
();
process
.
stdin
.
write
(
'R'
);
process
.
stdin
.
write
(
'r'
);
return
;
}
if
(
line
.
contains
(
'Recompile complete'
))
{
if
(
line
.
contains
(
expectedMessage
))
{
if
(
hotRestartCount
==
0
)
{
measurements
[
kFirstRestartTime
]
=
sw
.
elapsedMilliseconds
;
// Update the file and reload again.
...
...
@@ -80,9 +102,10 @@ TaskFunction createWebDevModeTest() {
sw
..
reset
()
..
start
();
process
.
stdin
.
writeln
(
'
R
'
);
process
.
stdin
.
writeln
(
'
r
'
);
++
hotRestartCount
;
}
else
{
restarted
=
true
;
measurements
[
kFirstRecompileTime
]
=
sw
.
elapsedMilliseconds
;
// Quit after second hot restart.
process
.
stdin
.
writeln
(
'q'
);
...
...
@@ -119,24 +142,35 @@ TaskFunction createWebDevModeTest() {
flutterCommandArgs
(
'run'
,
options
),
environment:
<
String
,
String
>{
'FLUTTER_WEB'
:
'true'
,
if
(
enableIncrementalCompiler
)
'WEB_INCREMENTAL_COMPILER'
:
'true'
,
},
);
final
Completer
<
void
>
stdoutDone
=
Completer
<
void
>();
final
Completer
<
void
>
stderrDone
=
Completer
<
void
>();
bool
restarted
=
false
;
process
.
stdout
.
transform
<
String
>(
utf8
.
decoder
)
.
transform
<
String
>(
const
LineSplitter
())
.
listen
((
String
line
)
{
// TODO(jonahwilliams): non-dwds builds do not know when the browser is loaded.
if
(
line
.
contains
(
'Ignoring terminal input'
))
{
Future
<
void
>.
delayed
(
const
Duration
(
seconds:
1
)).
then
((
void
_
)
{
process
.
stdin
.
write
(
restarted
?
'q'
:
'r'
);
});
return
;
}
if
(
line
.
contains
(
'To hot restart'
))
{
measurements
[
kSecondStartupTime
]
=
sw
.
elapsedMilliseconds
;
sw
..
reset
()
..
start
();
process
.
stdin
.
write
(
'R'
);
process
.
stdin
.
write
(
'r'
);
return
;
}
if
(
line
.
contains
(
'Recompile complete'
))
{
measurements
[
kSecondRestartTime
]
=
sw
.
elapsedMilliseconds
;
if
(
line
.
contains
(
expectedMessage
))
{
restarted
=
true
;
measurements
[
kSecondRestartTime
]
=
sw
.
elapsedMilliseconds
;
process
.
stdin
.
writeln
(
'q'
);
}
print
(
'stdout:
$line
'
);
...
...
dev/devicelab/manifest.yaml
View file @
cc51ad5d
...
...
@@ -112,6 +112,13 @@ tasks:
stage
:
devicelab
required_agent_capabilities
:
[
"
linux/android"
]
web_incremental_test
:
description
:
>
Verify that the experimental frontend server support is functional.
stage
:
devicelab
required_agent_capabilities
:
[
"
linux/android"
]
flaky
:
true
flutter_gallery_ios__compile
:
description
:
>
Collects various performance metrics of compiling the Flutter
...
...
packages/flutter_tools/lib/src/artifacts.dart
View file @
cc51ad5d
...
...
@@ -28,7 +28,7 @@ enum Artifact {
platformLibrariesJson
,
flutterPatchedSdkPath
,
frontendServerSnapshotForEngineDartSdk
,
/// The root directory of the dart
k
SDK.
/// The root directory of the dart SDK.
engineDartSdkPath
,
/// The dart binary used to execute any of the required snapshots.
engineDartBinary
,
...
...
packages/flutter_tools/lib/src/build_runner/resident_web_runner.dart
View file @
cc51ad5d
...
...
@@ -8,7 +8,8 @@ import 'package:build_daemon/client.dart';
import
'package:dwds/dwds.dart'
;
import
'package:meta/meta.dart'
;
import
'package:vm_service/vm_service.dart'
as
vmservice
;
import
'package:webkit_inspection_protocol/webkit_inspection_protocol.dart'
hide
StackTrace
;
import
'package:webkit_inspection_protocol/webkit_inspection_protocol.dart'
hide
StackTrace
;
import
'../application_package.dart'
;
import
'../base/async_guard.dart'
;
...
...
@@ -16,16 +17,21 @@ import '../base/common.dart';
import
'../base/file_system.dart'
;
import
'../base/io.dart'
;
import
'../base/logger.dart'
;
import
'../base/os.dart'
;
import
'../base/terminal.dart'
;
import
'../base/utils.dart'
;
import
'../build_info.dart'
;
import
'../convert.dart'
;
import
'../devfs.dart'
;
import
'../device.dart'
;
import
'../features.dart'
;
import
'../globals.dart'
;
import
'../project.dart'
;
import
'../reporting/reporting.dart'
;
import
'../resident_runner.dart'
;
import
'../run_hot.dart'
;
import
'../web/chrome.dart'
;
import
'../web/devfs_web.dart'
;
import
'../web/web_device.dart'
;
import
'../web/web_runner.dart'
;
import
'web_fs.dart'
;
...
...
@@ -34,14 +40,24 @@ import 'web_fs.dart';
class
DwdsWebRunnerFactory
extends
WebRunnerFactory
{
@override
ResidentRunner
createWebRunner
(
Device
device
,
{
Flutter
Device
device
,
{
String
target
,
@required
bool
stayResident
,
@required
FlutterProject
flutterProject
,
@required
bool
ipv6
,
@required
DebuggingOptions
debuggingOptions
,
})
{
return
ResidentWebRunner
(
if
(
featureFlags
.
isWebIncrementalCompilerEnabled
)
{
return
_ExperimentalResidentWebRunner
(
device
,
target:
target
,
flutterProject:
flutterProject
,
debuggingOptions:
debuggingOptions
,
ipv6:
ipv6
,
stayResident:
stayResident
,
);
}
return
_DwdsResidentWebRunner
(
device
,
target:
target
,
flutterProject:
flutterProject
,
...
...
@@ -53,8 +69,9 @@ class DwdsWebRunnerFactory extends WebRunnerFactory {
}
/// A hot-runner which handles browser specific delegation.
class
ResidentWebRunner
extends
ResidentRunner
{
ResidentWebRunner
(
this
.
device
,
{
abstract
class
ResidentWebRunner
extends
ResidentRunner
{
ResidentWebRunner
(
this
.
device
,
{
String
target
,
@required
this
.
flutterProject
,
@required
bool
ipv6
,
...
...
@@ -68,22 +85,27 @@ class ResidentWebRunner extends ResidentRunner {
stayResident:
stayResident
,
);
final
Device
device
;
final
Flutter
Device
device
;
final
FlutterProject
flutterProject
;
DateTime
firstBuildTime
;
// Only the debug builds of the web support the service protocol.
@override
bool
get
supportsServiceProtocol
=>
isRunningDebug
&&
device
is
!
WebServerDevice
;
bool
get
supportsServiceProtocol
=>
isRunningDebug
&&
device
.
device
is
!
WebServerDevice
;
@override
bool
get
debuggingEnabled
=>
isRunningDebug
&&
device
is
!
WebServerDevice
;
bool
get
debuggingEnabled
=>
isRunningDebug
&&
device
.
device
is
!
WebServerDevice
;
WebFs
_webFs
;
ConnectionResult
_connectionResult
;
StreamSubscription
<
vmservice
.
Event
>
_stdOutSub
;
bool
_exited
=
false
;
WipConnection
_wipConnection
;
vmservice
.
VmService
get
_vmService
=>
_connectionResult
?.
debugConnection
?.
vmService
;
vmservice
.
VmService
get
_vmService
=>
_connectionResult
?.
debugConnection
?.
vmService
;
@override
bool
get
canHotRestart
{
...
...
@@ -95,7 +117,8 @@ class ResidentWebRunner extends ResidentRunner {
String
method
,
{
Map
<
String
,
dynamic
>
params
,
})
async
{
final
vmservice
.
Response
response
=
await
_vmService
.
callServiceExtension
(
method
,
args:
params
);
final
vmservice
.
Response
response
=
await
_vmService
.
callServiceExtension
(
method
,
args:
params
);
return
response
.
toJson
();
}
...
...
@@ -115,7 +138,7 @@ class ResidentWebRunner extends ResidentRunner {
}
await
_stdOutSub
?.
cancel
();
await
_webFs
?.
stop
();
await
device
.
stopApp
(
null
);
await
device
.
device
.
stopApp
(
null
);
if
(
ChromeLauncher
.
hasChromeInstance
)
{
final
Chrome
chrome
=
await
ChromeLauncher
.
connectedInstance
;
await
chrome
.
close
();
...
...
@@ -134,13 +157,15 @@ class ResidentWebRunner extends ResidentRunner {
return
printHelpDetails
();
}
const
String
fire
=
'🔥'
;
const
String
rawMessage
=
' To hot restart changes while running, press "r". '
'To hot restart (and refresh the browser), press "R".'
;
const
String
rawMessage
=
' To hot restart changes while running, press "r". '
'To hot restart (and refresh the browser), press "R".'
;
final
String
message
=
terminal
.
color
(
fire
+
terminal
.
bolden
(
rawMessage
),
TerminalColor
.
red
,
);
printStatus
(
'Warning: Flutter
\'
s support for web development is not stable yet and hasn
\'
t'
);
printStatus
(
'Warning: Flutter
\'
s support for web development is not stable yet and hasn
\'
t'
);
printStatus
(
'been thoroughly tested in production environments.'
);
printStatus
(
'For more information see https://flutter.dev/web'
);
printStatus
(
''
);
...
...
@@ -149,18 +174,202 @@ class ResidentWebRunner extends ResidentRunner {
printStatus
(
'For a more detailed help message, press "h".
$quitMessage
'
);
}
@override
Future
<
void
>
debugDumpApp
()
async
{
try
{
await
_vmService
?.
callServiceExtension
(
'ext.flutter.debugDumpApp'
,
);
}
on
vmservice
.
RPCError
{
return
;
}
}
@override
Future
<
void
>
debugDumpRenderTree
()
async
{
try
{
await
_vmService
?.
callServiceExtension
(
'ext.flutter.debugDumpRenderTree'
,
);
}
on
vmservice
.
RPCError
{
return
;
}
}
@override
Future
<
void
>
debugDumpLayerTree
()
async
{
try
{
await
_vmService
?.
callServiceExtension
(
'ext.flutter.debugDumpLayerTree'
,
);
}
on
vmservice
.
RPCError
{
return
;
}
}
@override
Future
<
void
>
debugDumpSemanticsTreeInTraversalOrder
()
async
{
try
{
await
_vmService
?.
callServiceExtension
(
'ext.flutter.debugDumpSemanticsTreeInTraversalOrder'
);
}
on
vmservice
.
RPCError
{
return
;
}
}
@override
Future
<
void
>
debugTogglePlatform
()
async
{
try
{
final
vmservice
.
Response
response
=
await
_vmService
?.
callServiceExtension
(
'ext.flutter.platformOverride'
);
final
String
currentPlatform
=
response
.
json
[
'value'
];
String
nextPlatform
;
switch
(
currentPlatform
)
{
case
'android'
:
nextPlatform
=
'iOS'
;
break
;
case
'iOS'
:
nextPlatform
=
'android'
;
break
;
}
if
(
nextPlatform
==
null
)
{
return
;
}
await
_vmService
?.
callServiceExtension
(
'ext.flutter.platformOverride'
,
args:
<
String
,
Object
>{
'value'
:
nextPlatform
,
});
printStatus
(
'Switched operating system to
$nextPlatform
'
);
}
on
vmservice
.
RPCError
{
return
;
}
}
@override
Future
<
void
>
debugDumpSemanticsTreeInInverseHitTestOrder
()
async
{
try
{
await
_vmService
?.
callServiceExtension
(
'ext.flutter.debugDumpSemanticsTreeInInverseHitTestOrder'
);
}
on
vmservice
.
RPCError
{
return
;
}
}
@override
Future
<
void
>
debugToggleDebugPaintSizeEnabled
()
async
{
try
{
final
vmservice
.
Response
response
=
await
_vmService
?.
callServiceExtension
(
'ext.flutter.debugPaint'
,
);
await
_vmService
?.
callServiceExtension
(
'ext.flutter.debugPaint'
,
args:
<
dynamic
,
dynamic
>{
'enabled'
:
!(
response
.
json
[
'enabled'
]
==
'true'
)
},
);
}
on
vmservice
.
RPCError
{
return
;
}
}
@override
Future
<
void
>
debugToggleDebugCheckElevationsEnabled
()
async
{
try
{
final
vmservice
.
Response
response
=
await
_vmService
?.
callServiceExtension
(
'ext.flutter.debugCheckElevationsEnabled'
,
);
await
_vmService
?.
callServiceExtension
(
'ext.flutter.debugCheckElevationsEnabled'
,
args:
<
dynamic
,
dynamic
>{
'enabled'
:
!(
response
.
json
[
'enabled'
]
==
'true'
)
},
);
}
on
vmservice
.
RPCError
{
return
;
}
}
@override
Future
<
void
>
debugTogglePerformanceOverlayOverride
()
async
{
try
{
final
vmservice
.
Response
response
=
await
_vmService
?.
callServiceExtension
(
'ext.flutter.showPerformanceOverlay'
);
await
_vmService
?.
callServiceExtension
(
'ext.flutter.showPerformanceOverlay'
,
args:
<
dynamic
,
dynamic
>{
'enabled'
:
!(
response
.
json
[
'enabled'
]
==
'true'
)
},
);
}
on
vmservice
.
RPCError
{
return
;
}
}
@override
Future
<
void
>
debugToggleWidgetInspector
()
async
{
try
{
final
vmservice
.
Response
response
=
await
_vmService
?.
callServiceExtension
(
'ext.flutter.debugToggleWidgetInspector'
);
await
_vmService
?.
callServiceExtension
(
'ext.flutter.debugToggleWidgetInspector'
,
args:
<
dynamic
,
dynamic
>{
'enabled'
:
!(
response
.
json
[
'enabled'
]
==
'true'
)
},
);
}
on
vmservice
.
RPCError
{
return
;
}
}
@override
Future
<
void
>
debugToggleProfileWidgetBuilds
()
async
{
try
{
final
vmservice
.
Response
response
=
await
_vmService
?.
callServiceExtension
(
'ext.flutter.profileWidgetBuilds'
);
await
_vmService
?.
callServiceExtension
(
'ext.flutter.profileWidgetBuilds'
,
args:
<
dynamic
,
dynamic
>{
'enabled'
:
!(
response
.
json
[
'enabled'
]
==
'true'
)
},
);
}
on
vmservice
.
RPCError
{
return
;
}
}
}
class
_ExperimentalResidentWebRunner
extends
ResidentWebRunner
{
_ExperimentalResidentWebRunner
(
FlutterDevice
device
,
{
String
target
,
@required
FlutterProject
flutterProject
,
@required
bool
ipv6
,
@required
DebuggingOptions
debuggingOptions
,
bool
stayResident
=
true
,
})
:
super
(
device
,
flutterProject:
flutterProject
,
target:
target
??
fs
.
path
.
join
(
'lib'
,
'main.dart'
),
debuggingOptions:
debuggingOptions
,
ipv6:
ipv6
,
stayResident:
stayResident
,
);
@override
Future
<
int
>
run
({
Completer
<
DebugConnectionInfo
>
connectionInfoCompleter
,
Completer
<
void
>
appStartedCompleter
,
String
route
,
})
async
{
firstBuildTime
=
DateTime
.
now
();
final
ApplicationPackage
package
=
await
ApplicationPackageFactory
.
instance
.
getPackageForPlatform
(
TargetPlatform
.
web_javascript
,
applicationBinary:
null
,
);
if
(
package
==
null
)
{
printError
(
'
No application found for TargetPlatform.web_javascript
.'
);
printError
(
'
This application is not configured to build on the web
.'
);
printError
(
'To add web support to a project, run `flutter create .`.'
);
return
1
;
}
...
...
@@ -174,7 +383,200 @@ class ResidentWebRunner extends ResidentRunner {
return
1
;
}
final
String
modeName
=
debuggingOptions
.
buildInfo
.
friendlyModeName
;
printStatus
(
'Launching
${getDisplayPath(target)}
on
${device.name}
in
$modeName
mode...'
);
printStatus
(
'Launching
${getDisplayPath(target)}
on
${device.device.name}
in
$modeName
mode...'
);
final
String
effectiveHostname
=
debuggingOptions
.
hostname
??
'localhost'
;
final
int
hostPort
=
debuggingOptions
.
port
==
null
?
await
os
.
findFreePort
()
:
int
.
tryParse
(
debuggingOptions
.
port
);
device
.
devFS
=
WebDevFS
(
effectiveHostname
,
hostPort
,
packagesFilePath
,
);
await
device
.
devFS
.
create
();
await
_updateDevFS
(
fullRestart:
true
);
device
.
generator
.
accept
();
await
device
.
device
.
startApp
(
package
,
mainPath:
target
,
debuggingOptions:
debuggingOptions
,
platformArgs:
<
String
,
Object
>{
'uri'
:
'http://
$effectiveHostname
:
$hostPort
'
,
},
);
return
attach
(
connectionInfoCompleter:
connectionInfoCompleter
,
appStartedCompleter:
appStartedCompleter
,
);
}
@override
Future
<
OperationResult
>
restart
({
bool
fullRestart
=
false
,
bool
pauseAfterRestart
=
false
,
String
reason
,
bool
benchmarkMode
=
false
,
})
async
{
final
Stopwatch
timer
=
Stopwatch
()..
start
();
final
Status
status
=
logger
.
startProgress
(
'Performing hot restart...'
,
timeout:
supportsServiceProtocol
?
timeoutConfiguration
.
fastOperation
:
timeoutConfiguration
.
slowOperation
,
progressId:
'hot.restart'
,
);
final
UpdateFSReport
report
=
await
_updateDevFS
(
fullRestart:
fullRestart
);
if
(
report
.
success
)
{
device
.
generator
.
accept
();
}
else
{
await
device
.
generator
.
reject
();
}
final
String
modules
=
report
.
invalidatedModules
.
map
((
String
module
)
=>
'"
$module
"'
)
.
join
(
','
);
try
{
if
(
fullRestart
)
{
await
_wipConnection
.
sendCommand
(
'Page.reload'
);
}
else
{
await
_wipConnection
.
debugger
.
sendCommand
(
'Runtime.evaluate'
,
params:
<
String
,
Object
>{
'expression'
:
'window.
\
$hotReloadHook
([
$modules
])'
,
'awaitPromise'
:
true
,
'returnByValue'
:
true
,
});
}
}
on
WipError
catch
(
err
)
{
printError
(
err
.
toString
());
return
OperationResult
(
1
,
err
.
toString
());
}
finally
{
status
.
stop
();
}
final
String
verb
=
fullRestart
?
'Restarted'
:
'Reloaded'
;
printStatus
(
'
$verb
application in
${getElapsedAsMilliseconds(timer.elapsed)}
.'
);
if
(!
fullRestart
)
{
flutterUsage
.
sendTiming
(
'hot'
,
'web-incremental-restart'
,
timer
.
elapsed
);
}
HotEvent
(
'restart'
,
targetPlatform:
getNameForTargetPlatform
(
TargetPlatform
.
web_javascript
),
sdkName:
await
device
.
device
.
sdkNameAndVersion
,
emulator:
false
,
fullRestart:
true
,
reason:
reason
,
).
send
();
return
OperationResult
.
ok
;
}
Future
<
UpdateFSReport
>
_updateDevFS
({
bool
fullRestart
=
false
})
async
{
final
bool
isFirstUpload
=
!
assetBundle
.
wasBuiltOnce
();
final
bool
rebuildBundle
=
assetBundle
.
needsBuild
();
if
(
rebuildBundle
)
{
printTrace
(
'Updating assets'
);
final
int
result
=
await
assetBundle
.
build
();
if
(
result
!=
0
)
{
return
UpdateFSReport
(
success:
false
);
}
}
final
List
<
Uri
>
invalidatedFiles
=
await
projectFileInvalidator
.
findInvalidated
(
lastCompiled:
device
.
devFS
.
lastCompiled
,
urisToMonitor:
device
.
devFS
.
sources
,
packagesPath:
packagesFilePath
,
);
final
Status
devFSStatus
=
logger
.
startProgress
(
'Syncing files to device
${device.device.name}
...'
,
timeout:
timeoutConfiguration
.
fastOperation
,
);
final
UpdateFSReport
report
=
await
device
.
devFS
.
update
(
mainPath:
mainPath
,
target:
target
,
bundle:
assetBundle
,
firstBuildTime:
firstBuildTime
,
bundleFirstUpload:
isFirstUpload
,
generator:
device
.
generator
,
fullRestart:
fullRestart
,
dillOutputPath:
dillOutputPath
,
projectRootPath:
projectRootPath
,
pathToReload:
getReloadPath
(
fullRestart:
fullRestart
),
invalidatedFiles:
invalidatedFiles
,
trackWidgetCreation:
true
,
);
devFSStatus
.
stop
();
printTrace
(
'Synced
${getSizeAsMB(report.syncedBytes)}
.'
);
return
report
;
}
@override
Future
<
int
>
attach
({
Completer
<
DebugConnectionInfo
>
connectionInfoCompleter
,
Completer
<
void
>
appStartedCompleter
,
})
async
{
final
Chrome
chrome
=
await
ChromeLauncher
.
connectedInstance
;
final
ChromeTab
chromeTab
=
await
chrome
.
chromeConnection
.
getTab
((
ChromeTab
chromeTab
)
{
return
chromeTab
.
url
.
contains
(
debuggingOptions
.
hostname
);
});
_wipConnection
=
await
chromeTab
.
connect
();
appStartedCompleter
?.
complete
();
connectionInfoCompleter
?.
complete
();
if
(
stayResident
)
{
await
waitForAppToFinish
();
}
else
{
await
stopEchoingDeviceLog
();
await
exitApp
();
}
await
cleanupAtFinish
();
return
0
;
}
}
class
_DwdsResidentWebRunner
extends
ResidentWebRunner
{
_DwdsResidentWebRunner
(
FlutterDevice
device
,
{
String
target
,
@required
FlutterProject
flutterProject
,
@required
bool
ipv6
,
@required
DebuggingOptions
debuggingOptions
,
bool
stayResident
=
true
,
})
:
super
(
device
,
flutterProject:
flutterProject
,
target:
target
??
fs
.
path
.
join
(
'lib'
,
'main.dart'
),
debuggingOptions:
debuggingOptions
,
ipv6:
ipv6
,
stayResident:
stayResident
,
);
@override
Future
<
int
>
run
({
Completer
<
DebugConnectionInfo
>
connectionInfoCompleter
,
Completer
<
void
>
appStartedCompleter
,
String
route
,
})
async
{
firstBuildTime
=
DateTime
.
now
();
final
ApplicationPackage
package
=
await
ApplicationPackageFactory
.
instance
.
getPackageForPlatform
(
TargetPlatform
.
web_javascript
,
applicationBinary:
null
,
);
if
(
package
==
null
)
{
printError
(
'This application is not configured to build on the web.'
);
printError
(
'To add web support to a project, run `flutter create .`.'
);
return
1
;
}
if
(!
fs
.
isFileSync
(
mainPath
))
{
String
message
=
'Tried to run
$mainPath
, but that file does not exist.'
;
if
(
target
==
null
)
{
message
+=
'
\n
Consider using the -t option to specify the Dart file to start.'
;
}
printError
(
message
);
return
1
;
}
final
String
modeName
=
debuggingOptions
.
buildInfo
.
friendlyModeName
;
printStatus
(
'Launching
${getDisplayPath(target)}
on
${device.device.name}
in
$modeName
mode...'
);
Status
buildStatus
;
bool
statusActive
=
false
;
try
{
...
...
@@ -204,7 +606,8 @@ class ResidentWebRunner extends ResidentRunner {
);
statusActive
=
true
;
}
await
device
.
startApp
(
package
,
await
device
.
device
.
startApp
(
package
,
mainPath:
target
,
debuggingOptions:
debuggingOptions
,
platformArgs:
<
String
,
Object
>{
...
...
@@ -229,42 +632,38 @@ class ResidentWebRunner extends ResidentRunner {
}
on
VersionSkew
{
// Thrown if an older build daemon is already running.
throwToolExit
(
'Another build daemon is already running with an older version.
\n
'
'Try exiting other Flutter processes in this project and try again.'
);
'Another build daemon is already running with an older version.
\n
'
'Try exiting other Flutter processes in this project and try again.'
);
}
on
OptionsSkew
{
// Thrown if a build daemon is already running with different configuration.
throwToolExit
(
'Another build daemon is already running with different configuration.
\n
'
'Try exiting other Flutter processes in this project and try again.'
);
'Another build daemon is already running with different configuration.
\n
'
'Exit other Flutter processes running in this project and try again.'
);
}
on
WebSocketException
{
throwToolExit
(
'Failed to connect to WebSocket.'
);
}
on
BuildException
{
throwToolExit
(
'Failed to build application for the Web.'
);
}
on
ChromeDebugException
catch
(
err
,
stackTrace
)
{
throwToolExit
(
'Failed to establish connection with Chrome. Try running the application again.
\n
'
'If this problem persists, please file an issue with the details below:
\n
$err
\n
$stackTrace
'
);
'Failed to establish connection with Chrome. Try running the application again.
\n
'
'If this problem persists, please file an issue with the details below:
\n
$err
\n
$stackTrace
'
);
}
on
AppConnectionException
{
throwToolExit
(
'Failed to establish connection with the application instance in Chrome.
\n
'
'This can happen if the websocket connection used by the web tooling is '
'unabled to correctly establish a connection, for example due to a firewall.'
);
}
on
MissingPortFile
{
'Failed to establish connection with the application instance in Chrome.
\n
'
'This can happen if the websocket connection used by the web tooling is '
'unabled to correctly establish a connection, for example due to a firewall.'
);
}
on
MissingPortFile
{
throwToolExit
(
'Failed to connect to build daemon.
\n
The daemon either failed to '
'start or was killed by another process.'
);
'Failed to connect to build daemon.
\n
The daemon either failed to '
'start or was killed by another process.'
);
}
on
SocketException
catch
(
err
)
{
throwToolExit
(
err
.
toString
());
}
on
StateError
catch
(
err
)
{
final
String
message
=
err
.
toString
();
if
(
message
.
contains
(
'Unable to start build daemon'
))
{
throwToolExit
(
'Failed to start build daemon. The process might have '
'exited unexpectedly during startup. Try running the application '
'again.'
);
throwToolExit
(
'Failed to start build daemon. The process might have '
'exited unexpectedly during startup. Try running the application '
'again.'
);
}
rethrow
;
}
finally
{
...
...
@@ -275,61 +674,6 @@ class ResidentWebRunner extends ResidentRunner {
return
1
;
}
@override
Future
<
int
>
attach
({
Completer
<
DebugConnectionInfo
>
connectionInfoCompleter
,
Completer
<
void
>
appStartedCompleter
,
})
async
{
Uri
websocketUri
;
if
(
supportsServiceProtocol
)
{
// Cleanup old subscriptions. These will throw if there isn't anything
// listening, which is fine because that is what we want to ensure.
try
{
await
_vmService
.
streamCancel
(
'Stdout'
);
}
on
vmservice
.
RPCError
{
// Ignore this specific error.
}
try
{
await
_vmService
.
streamListen
(
'Stdout'
);
}
on
vmservice
.
RPCError
{
// Ignore this specific error.
}
_stdOutSub
=
_vmService
.
onStdoutEvent
.
listen
((
vmservice
.
Event
log
)
{
final
String
message
=
utf8
.
decode
(
base64
.
decode
(
log
.
bytes
)).
trim
();
printStatus
(
message
);
});
unawaited
(
_vmService
.
registerService
(
'reloadSources'
,
'FlutterTools'
));
websocketUri
=
Uri
.
parse
(
_connectionResult
.
debugConnection
.
uri
);
// Always run main after connecting because start paused doesn't work yet.
if
(!
debuggingOptions
.
startPaused
||
!
supportsServiceProtocol
)
{
_connectionResult
.
appConnection
.
runMain
();
}
else
{
StreamSubscription
<
void
>
resumeSub
;
resumeSub
=
_connectionResult
.
debugConnection
.
vmService
.
onDebugEvent
.
listen
((
vmservice
.
Event
event
)
{
if
(
event
.
type
==
vmservice
.
EventKind
.
kResume
)
{
_connectionResult
.
appConnection
.
runMain
();
resumeSub
.
cancel
();
}
});
}
}
if
(
websocketUri
!=
null
)
{
printStatus
(
'Debug service listening on
$websocketUri
'
);
}
connectionInfoCompleter
?.
complete
(
DebugConnectionInfo
(
wsUri:
websocketUri
)
);
if
(
stayResident
)
{
await
waitForAppToFinish
();
}
else
{
await
stopEchoingDeviceLog
();
await
exitApp
();
}
await
cleanupAtFinish
();
return
0
;
}
@override
Future
<
OperationResult
>
restart
({
bool
fullRestart
=
false
,
...
...
@@ -356,10 +700,11 @@ class ResidentWebRunner extends ResidentRunner {
flutterUsage
.
sendTiming
(
'hot'
,
'web-recompile'
,
recompileDuration
);
try
{
final
vmservice
.
Response
reloadResponse
=
fullRestart
?
await
_vmService
.
callServiceExtension
(
'fullReload'
)
:
await
_vmService
.
callServiceExtension
(
'hotRestart'
);
?
await
_vmService
.
callServiceExtension
(
'fullReload'
)
:
await
_vmService
.
callServiceExtension
(
'hotRestart'
);
final
String
verb
=
fullRestart
?
'Restarted'
:
'Reloaded'
;
printStatus
(
'
$verb
application in
${getElapsedAsMilliseconds(timer.elapsed)}
.'
);
printStatus
(
'
$verb
application in
${getElapsedAsMilliseconds(timer.elapsed)}
.'
);
// Send timing analytics for full restart and for refresh.
final
bool
wasSuccessful
=
reloadResponse
.
type
==
'Success'
;
...
...
@@ -375,9 +720,10 @@ class ResidentWebRunner extends ResidentRunner {
return
OperationResult
(
1
,
'Page requires refresh.'
);
}
finally
{
status
.
stop
();
HotEvent
(
'restart'
,
HotEvent
(
'restart'
,
targetPlatform:
getNameForTargetPlatform
(
TargetPlatform
.
web_javascript
),
sdkName:
await
device
.
sdkNameAndVersion
,
sdkName:
await
device
.
device
.
sdkNameAndVersion
,
emulator:
false
,
fullRestart:
true
,
reason:
reason
,
...
...
@@ -405,159 +751,58 @@ class ResidentWebRunner extends ResidentRunner {
}
@override
Future
<
void
>
debugDumpApp
()
async
{
try
{
await
_vmService
.
callServiceExtension
(
'ext.flutter.debugDumpApp'
,
);
}
on
vmservice
.
RPCError
{
return
;
}
}
@override
Future
<
void
>
debugDumpRenderTree
()
async
{
try
{
await
_vmService
.
callServiceExtension
(
'ext.flutter.debugDumpRenderTree'
,
);
}
on
vmservice
.
RPCError
{
return
;
}
}
@override
Future
<
void
>
debugDumpLayerTree
()
async
{
try
{
await
_vmService
.
callServiceExtension
(
'ext.flutter.debugDumpLayerTree'
,
);
}
on
vmservice
.
RPCError
{
return
;
}
}
@override
Future
<
void
>
debugDumpSemanticsTreeInTraversalOrder
()
async
{
try
{
await
_vmService
.
callServiceExtension
(
'ext.flutter.debugDumpSemanticsTreeInTraversalOrder'
);
}
on
vmservice
.
RPCError
{
return
;
}
}
@override
Future
<
void
>
debugTogglePlatform
()
async
{
try
{
final
vmservice
.
Response
response
=
await
_vmService
.
callServiceExtension
(
'ext.flutter.platformOverride'
);
final
String
currentPlatform
=
response
.
json
[
'value'
];
String
nextPlatform
;
switch
(
currentPlatform
)
{
case
'android'
:
nextPlatform
=
'iOS'
;
break
;
case
'iOS'
:
nextPlatform
=
'android'
;
break
;
Future
<
int
>
attach
({
Completer
<
DebugConnectionInfo
>
connectionInfoCompleter
,
Completer
<
void
>
appStartedCompleter
,
})
async
{
Uri
websocketUri
;
if
(
supportsServiceProtocol
)
{
// Cleanup old subscriptions. These will throw if there isn't anything
// listening, which is fine because that is what we want to ensure.
try
{
await
_vmService
.
streamCancel
(
'Stdout'
);
}
on
vmservice
.
RPCError
{
// It is safe to ignore this error because we expect an error to be
// thrown if we're not already subscribed.
}
if
(
nextPlatform
==
null
)
{
return
;
try
{
await
_vmService
.
streamListen
(
'Stdout'
);
}
on
vmservice
.
RPCError
{
// It is safe to ignore this error because we expect an error to be
// thrown if we're not already subscribed.
}
await
_vmService
.
callServiceExtension
(
'ext.flutter.platformOverride'
,
args:
<
String
,
Object
>{
'value'
:
nextPlatform
,
_stdOutSub
=
_vmService
.
onStdoutEvent
.
listen
((
vmservice
.
Event
log
)
{
final
String
message
=
utf8
.
decode
(
base64
.
decode
(
log
.
bytes
)).
trim
();
printStatus
(
message
);
});
unawaited
(
_vmService
.
registerService
(
'reloadSources'
,
'FlutterTools'
));
websocketUri
=
Uri
.
parse
(
_connectionResult
.
debugConnection
.
uri
);
// Always run main after connecting because start paused doesn't work yet.
if
(!
debuggingOptions
.
startPaused
||
!
supportsServiceProtocol
)
{
_connectionResult
.
appConnection
.
runMain
();
}
else
{
StreamSubscription
<
void
>
resumeSub
;
resumeSub
=
_connectionResult
.
debugConnection
.
vmService
.
onDebugEvent
.
listen
((
vmservice
.
Event
event
)
{
if
(
event
.
type
==
vmservice
.
EventKind
.
kResume
)
{
_connectionResult
.
appConnection
.
runMain
();
resumeSub
.
cancel
();
}
});
printStatus
(
'Switched operating system to
$nextPlatform
'
);
}
on
vmservice
.
RPCError
{
return
;
}
}
@override
Future
<
void
>
debugDumpSemanticsTreeInInverseHitTestOrder
()
async
{
try
{
await
_vmService
.
callServiceExtension
(
'ext.flutter.debugDumpSemanticsTreeInInverseHitTestOrder'
);
}
on
vmservice
.
RPCError
{
return
;
}
}
@override
Future
<
void
>
debugToggleDebugPaintSizeEnabled
()
async
{
try
{
final
vmservice
.
Response
response
=
await
_vmService
.
callServiceExtension
(
'ext.flutter.debugPaint'
,
);
await
_vmService
.
callServiceExtension
(
'ext.flutter.debugPaint'
,
args:
<
dynamic
,
dynamic
>{
'enabled'
:
!(
response
.
json
[
'enabled'
]
==
'true'
)},
);
}
on
vmservice
.
RPCError
{
return
;
}
}
@override
Future
<
void
>
debugToggleDebugCheckElevationsEnabled
()
async
{
try
{
final
vmservice
.
Response
response
=
await
_vmService
.
callServiceExtension
(
'ext.flutter.debugCheckElevationsEnabled'
,
);
await
_vmService
.
callServiceExtension
(
'ext.flutter.debugCheckElevationsEnabled'
,
args:
<
dynamic
,
dynamic
>{
'enabled'
:
!(
response
.
json
[
'enabled'
]
==
'true'
)},
);
}
on
vmservice
.
RPCError
{
return
;
}
}
@override
Future
<
void
>
debugTogglePerformanceOverlayOverride
()
async
{
try
{
final
vmservice
.
Response
response
=
await
_vmService
.
callServiceExtension
(
'ext.flutter.showPerformanceOverlay'
);
await
_vmService
.
callServiceExtension
(
'ext.flutter.showPerformanceOverlay'
,
args:
<
dynamic
,
dynamic
>{
'enabled'
:
!(
response
.
json
[
'enabled'
]
==
'true'
)},
);
}
on
vmservice
.
RPCError
{
return
;
}
}
}
@override
Future
<
void
>
debugToggleWidgetInspector
()
async
{
try
{
final
vmservice
.
Response
response
=
await
_vmService
.
callServiceExtension
(
'ext.flutter.debugToggleWidgetInspector'
);
await
_vmService
.
callServiceExtension
(
'ext.flutter.debugToggleWidgetInspector'
,
args:
<
dynamic
,
dynamic
>{
'enabled'
:
!(
response
.
json
[
'enabled'
]
==
'true'
)},
);
}
on
vmservice
.
RPCError
{
return
;
if
(
websocketUri
!=
null
)
{
printStatus
(
'Debug service listening on
$websocketUri
'
);
}
}
connectionInfoCompleter
?.
complete
(
DebugConnectionInfo
(
wsUri:
websocketUri
));
@override
Future
<
void
>
debugToggleProfileWidgetBuilds
()
async
{
try
{
final
vmservice
.
Response
response
=
await
_vmService
.
callServiceExtension
(
'ext.flutter.profileWidgetBuilds'
);
await
_vmService
.
callServiceExtension
(
'ext.flutter.profileWidgetBuilds'
,
args:
<
dynamic
,
dynamic
>{
'enabled'
:
!(
response
.
json
[
'enabled'
]
==
'true'
)},
);
}
on
vmservice
.
RPCError
{
return
;
if
(
stayResident
)
{
await
waitForAppToFinish
();
}
else
{
await
stopEchoingDeviceLog
();
await
exitApp
();
}
await
cleanupAtFinish
();
return
0
;
}
}
packages/flutter_tools/lib/src/commands/daemon.dart
View file @
cc51ad5d
...
...
@@ -430,7 +430,7 @@ class AppDomain extends Domain {
if
(
await
device
.
targetPlatform
==
TargetPlatform
.
web_javascript
)
{
runner
=
webRunnerFactory
.
createWebRunner
(
d
evice
,
flutterD
evice
,
flutterProject:
flutterProject
,
target:
target
,
debuggingOptions:
options
,
...
...
packages/flutter_tools/lib/src/commands/run.dart
View file @
cc51ad5d
...
...
@@ -453,7 +453,7 @@ class RunCommand extends RunCommandBase {
);
}
else
if
(
webMode
)
{
runner
=
webRunnerFactory
.
createWebRunner
(
d
evices
.
single
,
flutterD
evices
.
single
,
target:
targetFile
,
flutterProject:
flutterProject
,
ipv6:
ipv6
,
...
...
packages/flutter_tools/lib/src/compile.dart
View file @
cc51ad5d
...
...
@@ -201,7 +201,6 @@ class PackageUriMapper {
PackageUriMapper
(
String
scriptPath
,
String
packagesPath
,
String
fileSystemScheme
,
List
<
String
>
fileSystemRoots
)
{
final
Map
<
String
,
Uri
>
packageMap
=
PackageMap
(
fs
.
path
.
absolute
(
packagesPath
)).
map
;
final
String
scriptUri
=
Uri
.
file
(
scriptPath
,
windows:
platform
.
isWindows
).
toString
();
for
(
String
packageName
in
packageMap
.
keys
)
{
final
String
prefix
=
packageMap
[
packageName
].
toString
();
// Only perform a multi-root mapping if there are multiple roots.
...
...
packages/flutter_tools/lib/src/devfs.dart
View file @
cc51ad5d
...
...
@@ -349,12 +349,19 @@ class UpdateFSReport {
int
get
invalidatedSourcesCount
=>
_invalidatedSourcesCount
;
int
get
syncedBytes
=>
_syncedBytes
;
/// JavaScript modules produced by the incremental compiler in `dartdevc`
/// mode.
///
/// Only used for JavaScript compilation.
List
<
String
>
invalidatedModules
;
void
incorporateResults
(
UpdateFSReport
report
)
{
if
(!
report
.
_success
)
{
_success
=
false
;
}
_invalidatedSourcesCount
+=
report
.
_invalidatedSourcesCount
;
_syncedBytes
+=
report
.
_syncedBytes
;
invalidatedModules
??=
report
.
invalidatedModules
;
}
bool
_success
;
...
...
packages/flutter_tools/lib/src/features.dart
View file @
cc51ad5d
...
...
@@ -151,10 +151,15 @@ const Feature flutterAndroidEmbeddingV2Feature = Feature(
const
Feature
flutterWebIncrementalCompiler
=
Feature
(
name:
'Enable the incremental compiler for web builds'
,
configSetting:
'enable-web-incremental-compiler'
,
environmentOverride:
'WEB_INCREMENTAL_COMPILER'
,
master:
FeatureChannelSetting
(
available:
true
,
enabledByDefault:
false
,
),
dev:
FeatureChannelSetting
(
available:
true
,
enabledByDefault:
false
,
),
);
/// A [Feature] is a process for conditionally enabling tool features.
...
...
packages/flutter_tools/lib/src/web/bootstrap.dart
View file @
cc51ad5d
...
...
@@ -75,21 +75,25 @@ define("main_module", ["$entrypoint", "dart_sdk"], function(app, dart_sdk) {
dart_sdk.dart.setStartAsyncSynchronously(true);
dart_sdk._isolate_helper.startRootIsolate(() => {}, []);
dart_sdk._debugger.registerDevtoolsFormatter();
dart_sdk.ui.webOnlyInitializePlatform
();
let voidToNull = () => (voidToNull = dart_sdk.dart.constFn(dart_sdk.dart.fnType(dart_sdk.core.Null, [dart_sdk.dart.void])))
();
// Attach the main entrypoint and hot reload functionality to the window.
window.
\
$mainEntrypoint
= app.main.main;
if (window.
\
$hotReload
== null) {
window.
\
$hotReload
= function(cb) {
dart_sdk.developer.invokeExtension("ext.flutter.disassemble", "{}");
dart_sdk.dart.hotRestart();
window.
\
$mainEntrypoint
();
if (cb != null) {
cb();
}
dart_sdk.developer.invokeExtension("ext.flutter.disassemble", "{}").then((_) => {
dart_sdk.dart.hotRestart();
dart_sdk.ui.webOnlyInitializePlatform().then(dart_sdk.core.Null, dart_sdk.dart.fn(_ => {
window.
\
$mainEntrypoint
();
window.requestAnimationFrame(cb);
}, voidToNull()));
});
}
}
app.main.main();
dart_sdk.ui.webOnlyInitializePlatform().then(dart_sdk.core.Null, dart_sdk.dart.fn(_ => {
app.main.main();
}, voidToNull()));
});
// Require JS configuration.
...
...
packages/flutter_tools/lib/src/web/chrome.dart
View file @
cc51ad5d
...
...
@@ -71,6 +71,11 @@ void resetChromeForTesting() {
ChromeLauncher
.
_currentCompleter
=
Completer
<
Chrome
>();
}
@visibleForTesting
void
launchChromeInstance
(
Chrome
chrome
)
{
ChromeLauncher
.
_currentCompleter
.
complete
(
chrome
);
}
/// Responsible for launching chrome with devtools configured.
class
ChromeLauncher
{
const
ChromeLauncher
();
...
...
packages/flutter_tools/lib/src/web/devfs_web.dart
View file @
cc51ad5d
...
...
@@ -7,12 +7,18 @@ import 'dart:typed_data';
import
'package:meta/meta.dart'
;
import
'package:mime/mime.dart'
as
mime
;
import
'../artifacts.dart'
;
import
'../asset.dart'
;
import
'../base/common.dart'
;
import
'../base/file_system.dart'
;
import
'../base/io.dart'
;
import
'../build_info.dart'
;
import
'../bundle.dart'
;
import
'../compile.dart'
;
import
'../convert.dart'
;
import
'../devfs.dart'
;
import
'../globals.dart'
;
import
'bootstrap.dart'
;
/// A web server which handles serving JavaScript and assets.
///
...
...
@@ -49,7 +55,10 @@ class WebAssetServer {
}
final
HttpServer
_httpServer
;
// If holding these in memory is too much overhead, this can be switched to a
// RandomAccessFile and read on demand.
final
Map
<
String
,
Uint8List
>
_files
=
<
String
,
Uint8List
>{};
final
Map
<
String
,
Uint8List
>
_sourcemaps
=
<
String
,
Uint8List
>{};
// handle requests for JavaScript source, dart sources maps, or asset files.
Future
<
void
>
_handleRequest
(
HttpRequest
request
)
async
{
...
...
@@ -71,8 +80,7 @@ class WebAssetServer {
}
// If this is a JavaScript file, it must be in the in-memory cache.
// Attempt to look up the file by URI, returning a 404 if it is not
// found.
// Attempt to look up the file by URI.
if
(
_files
.
containsKey
(
request
.
uri
.
path
))
{
final
List
<
int
>
bytes
=
_files
[
request
.
uri
.
path
];
response
.
headers
...
...
@@ -82,6 +90,18 @@ class WebAssetServer {
await
response
.
close
();
return
;
}
// If this is a sourcemap file, then it might be in the in-memory cache.
// Attempt to lookup the file by URI.
if
(
_sourcemaps
.
containsKey
(
request
.
uri
.
path
))
{
final
List
<
int
>
bytes
=
_sourcemaps
[
request
.
uri
.
path
];
response
.
headers
..
add
(
'Content-Length'
,
bytes
.
length
)
..
add
(
'Content-Type'
,
'application/json'
);
response
.
add
(
bytes
);
await
response
.
close
();
return
;
}
// If this is a dart file, it must be on the local file system and is
// likely coming from a source map request. Attempt to look in the
// local filesystem for it, and return a 404 if it is not found. The tool
...
...
@@ -95,6 +115,18 @@ class WebAssetServer {
file
=
fs
.
file
(
fs
.
path
.
join
(
getAssetBuildDirectory
(),
fs
.
path
.
relative
(
assetPath
)));
}
// If it isn't a project source or an asset, it must be a dart SDK source.
// or a flutter web SDK source.
if
(!
file
.
existsSync
())
{
final
Directory
dartSdkParent
=
fs
.
directory
(
artifacts
.
getArtifactPath
(
Artifact
.
engineDartSdkPath
)).
parent
;
file
=
fs
.
file
(
fs
.
path
.
joinAll
(<
String
>[
dartSdkParent
.
path
,
...
request
.
uri
.
pathSegments
]));
}
if
(!
file
.
existsSync
())
{
final
String
flutterWebSdk
=
artifacts
.
getArtifactPath
(
Artifact
.
flutterWebSdk
);
file
=
fs
.
file
(
fs
.
path
.
joinAll
(<
String
>[
flutterWebSdk
,
...
request
.
uri
.
pathSegments
]));
}
if
(!
file
.
existsSync
())
{
response
.
statusCode
=
HttpStatus
.
notFound
;
await
response
.
close
();
...
...
@@ -131,30 +163,186 @@ class WebAssetServer {
/// Update the in-memory asset server with the provided source and manifest files.
///
/// Returns a list of updated modules.
List
<
String
>
write
(
File
sourceFile
,
File
manifest
File
)
{
List
<
String
>
write
(
File
codeFile
,
File
manifestFile
,
File
sourcemap
File
)
{
final
List
<
String
>
modules
=
<
String
>[];
final
Uint8List
bytes
=
sourceFile
.
readAsBytesSync
();
final
Uint8List
codeBytes
=
codeFile
.
readAsBytesSync
();
final
Uint8List
sourcemapBytes
=
sourcemapFile
.
readAsBytesSync
();
final
Map
<
String
,
Object
>
manifest
=
json
.
decode
(
manifestFile
.
readAsStringSync
());
for
(
String
filePath
in
manifest
.
keys
)
{
if
(
filePath
==
null
)
{
printTrace
(
'Invalid manfiest file:
$filePath
'
);
continue
;
}
final
List
<
Object
>
offsets
=
manifest
[
filePath
];
if
(
offsets
.
length
!=
2
)
{
final
Map
<
String
,
Object
>
offsets
=
manifest
[
filePath
];
final
List
<
Object
>
codeOffsets
=
offsets
[
'code'
];
final
List
<
Object
>
sourcemapOffsets
=
offsets
[
'sourcemap'
];
if
(
codeOffsets
.
length
!=
2
||
sourcemapOffsets
.
length
!=
2
)
{
printTrace
(
'Invalid manifest byte offsets:
$offsets
'
);
continue
;
}
final
int
start
=
offsets
[
0
];
final
int
end
=
offsets
[
1
];
if
(
start
<
0
||
end
>
bytes
.
lengthInBytes
)
{
printTrace
(
'Invalid byte index: [
$start
,
$end
]'
);
final
int
codeStart
=
codeOffsets
[
0
];
final
int
codeEnd
=
codeOffsets
[
1
];
if
(
codeStart
<
0
||
codeEnd
>
codeBytes
.
lengthInBytes
)
{
printTrace
(
'Invalid byte index: [
$codeStart
,
$codeEnd
]'
);
continue
;
}
final
Uint8List
byteView
=
Uint8List
.
view
(
bytes
.
buffer
,
start
,
end
-
start
);
final
Uint8List
byteView
=
Uint8List
.
view
(
codeBytes
.
buffer
,
codeStart
,
codeEnd
-
codeStart
,
);
_files
[
filePath
]
=
byteView
;
final
int
sourcemapStart
=
sourcemapOffsets
[
0
];
final
int
sourcemapEnd
=
sourcemapOffsets
[
1
];
if
(
sourcemapStart
<
0
||
sourcemapEnd
>
sourcemapBytes
.
lengthInBytes
)
{
printTrace
(
'Invalid byte index: [
$sourcemapStart
,
$sourcemapEnd
]'
);
continue
;
}
final
Uint8List
sourcemapView
=
Uint8List
.
view
(
sourcemapBytes
.
buffer
,
sourcemapStart
,
sourcemapEnd
-
sourcemapStart
,
);
_sourcemaps
[
'
$filePath
.map'
]
=
sourcemapView
;
modules
.
add
(
filePath
);
}
return
modules
;
}
}
class
WebDevFS
implements
DevFS
{
WebDevFS
(
this
.
hostname
,
this
.
port
,
this
.
_packagesFilePath
);
final
String
hostname
;
final
int
port
;
final
String
_packagesFilePath
;
WebAssetServer
_webAssetServer
;
@override
List
<
Uri
>
sources
=
<
Uri
>[];
@override
DateTime
lastCompiled
;
// We do not evict assets on the web.
@override
Set
<
String
>
get
assetPathsToEvict
=>
const
<
String
>{};
@override
Uri
get
baseUri
=>
null
;
@override
Future
<
Uri
>
create
()
async
{
_webAssetServer
=
await
WebAssetServer
.
start
(
hostname
,
port
);
return
Uri
.
base
;
}
@override
Future
<
void
>
destroy
()
async
{
await
_webAssetServer
.
dispose
();
}
@override
Uri
deviceUriToHostUri
(
Uri
deviceUri
)
{
return
deviceUri
;
}
@override
String
get
fsName
=>
'web_asset'
;
@override
Directory
get
rootDirectory
=>
null
;
@override
Future
<
UpdateFSReport
>
update
({
String
mainPath
,
String
target
,
AssetBundle
bundle
,
DateTime
firstBuildTime
,
bool
bundleFirstUpload
=
false
,
@required
ResidentCompiler
generator
,
String
dillOutputPath
,
@required
bool
trackWidgetCreation
,
bool
fullRestart
=
false
,
String
projectRootPath
,
String
pathToReload
,
List
<
Uri
>
invalidatedFiles
,
})
async
{
assert
(
trackWidgetCreation
!=
null
);
assert
(
generator
!=
null
);
if
(
bundleFirstUpload
)
{
final
File
requireJS
=
fs
.
file
(
fs
.
path
.
join
(
artifacts
.
getArtifactPath
(
Artifact
.
engineDartSdkPath
),
'lib'
,
'dev_compiler'
,
'kernel'
,
'amd'
,
'require.js'
,
));
final
File
dartSdk
=
fs
.
file
(
fs
.
path
.
join
(
artifacts
.
getArtifactPath
(
Artifact
.
flutterWebSdk
),
'kernel'
,
'amd'
,
'dart_sdk.js'
,
));
final
File
dartSdkSourcemap
=
fs
.
file
(
fs
.
path
.
join
(
artifacts
.
getArtifactPath
(
Artifact
.
flutterWebSdk
),
'kernel'
,
'amd'
,
'dart_sdk.js.map'
,
));
final
File
stackTraceMapper
=
fs
.
file
(
fs
.
path
.
join
(
artifacts
.
getArtifactPath
(
Artifact
.
engineDartSdkPath
),
'lib'
,
'dev_compiler'
,
'web'
,
'dart_stack_trace_mapper.js'
,
));
_webAssetServer
.
writeFile
(
'/main.dart.js'
,
generateBootstrapScript
(
requireUrl:
requireJS
.
path
,
mapperUrl:
stackTraceMapper
.
path
,
entrypoint:
'
$mainPath
.js'
,
));
_webAssetServer
.
writeFile
(
'/main_module.js'
,
generateMainModule
(
entrypoint:
'
$mainPath
.js'
,
));
_webAssetServer
.
writeFile
(
'/dart_sdk.js'
,
dartSdk
.
readAsStringSync
());
_webAssetServer
.
writeFile
(
'/dart_sdk.js.map'
,
dartSdkSourcemap
.
readAsStringSync
());
}
final
DateTime
candidateCompileTime
=
DateTime
.
now
();
if
(
fullRestart
)
{
generator
.
reset
();
}
final
CompilerOutput
compilerOutput
=
await
generator
.
recompile
(
mainPath
,
invalidatedFiles
,
outputPath:
dillOutputPath
??
getDefaultApplicationKernelPath
(
trackWidgetCreation:
trackWidgetCreation
),
packagesFilePath
:
_packagesFilePath
,
);
if
(
compilerOutput
==
null
||
compilerOutput
.
errorCount
>
0
)
{
return
UpdateFSReport
(
success:
false
);
}
// Only update the last compiled time if we successfully compiled.
lastCompiled
=
candidateCompileTime
;
// list of sources that needs to be monitored are in [compilerOutput.sources]
sources
=
compilerOutput
.
sources
;
File
codeFile
;
File
manifestFile
;
File
sourcemapFile
;
List
<
String
>
modules
;
try
{
codeFile
=
fs
.
file
(
'
${compilerOutput.outputFilename}
.sources'
);
manifestFile
=
fs
.
file
(
'
${compilerOutput.outputFilename}
.json'
);
sourcemapFile
=
fs
.
file
(
'
${compilerOutput.outputFilename}
.map'
);
modules
=
_webAssetServer
.
write
(
codeFile
,
manifestFile
,
sourcemapFile
);
}
on
FileSystemException
catch
(
err
)
{
throwToolExit
(
'Failed to load recompiled sources:
\n
$err
'
);
}
return
UpdateFSReport
(
success:
true
,
syncedBytes:
codeFile
.
lengthSync
(),
invalidatedSourcesCount:
invalidatedFiles
.
length
)
..
invalidatedModules
=
modules
;
}
}
packages/flutter_tools/lib/src/web/web_runner.dart
View file @
cc51ad5d
...
...
@@ -17,7 +17,7 @@ abstract class WebRunnerFactory {
/// Create a [ResidentRunner] for the web.
ResidentRunner
createWebRunner
(
Device
device
,
{
Flutter
Device
device
,
{
String
target
,
@required
bool
stayResident
,
@required
FlutterProject
flutterProject
,
...
...
packages/flutter_tools/test/commands.shard/hermetic/build_web_test.dart
View file @
cc51ad5d
...
...
@@ -63,11 +63,12 @@ void main() {
test
(
'Refuses to build using runner when missing index.html'
,
()
=>
testbed
.
run
(()
async
{
fs
.
file
(
fs
.
path
.
join
(
'web'
,
'index.html'
)).
deleteSync
();
final
ResidentWebRunner
runner
=
Resident
WebRunner
(
final
ResidentWebRunner
runner
=
DwdsWebRunnerFactory
().
create
WebRunner
(
null
,
flutterProject:
FlutterProject
.
current
(),
ipv6:
false
,
debuggingOptions:
DebuggingOptions
.
enabled
(
BuildInfo
.
debug
),
stayResident:
true
,
);
expect
(
await
runner
.
run
(),
1
);
}));
...
...
packages/flutter_tools/test/general.shard/resident_web_runner_cold_test.dart
View file @
cc51ad5d
...
...
@@ -26,17 +26,21 @@ void main() {
Testbed
testbed
;
MockFlutterWebFs
mockWebFs
;
ResidentWebRunner
residentWebRunner
;
MockFlutterDevice
mockFlutterDevice
;
setUp
(()
{
mockWebFs
=
MockFlutterWebFs
();
final
MockWebDevice
mockWebDevice
=
MockWebDevice
();
mockFlutterDevice
=
MockFlutterDevice
();
when
(
mockFlutterDevice
.
device
).
thenReturn
(
mockWebDevice
);
testbed
=
Testbed
(
setup:
()
{
residentWebRunner
=
Resident
WebRunner
(
mock
Web
Device
,
residentWebRunner
=
residentWebRunner
=
DwdsWebRunnerFactory
().
create
WebRunner
(
mock
Flutter
Device
,
flutterProject:
FlutterProject
.
current
(),
debuggingOptions:
DebuggingOptions
.
disabled
(
BuildInfo
.
release
),
ipv6:
true
,
stayResident:
true
,
);
},
overrides:
<
Type
,
Generator
>{
...
...
@@ -118,4 +122,4 @@ class MockFlutterWebFs extends Mock implements WebFs {}
class
MockDebugConnection
extends
Mock
implements
DebugConnection
{}
class
MockVmService
extends
Mock
implements
VmService
{}
class
MockStatus
extends
Mock
implements
Status
{}
class
MockFlutterDevice
extends
Mock
implements
FlutterDevice
{}
packages/flutter_tools/test/general.shard/resident_web_runner_test.dart
View file @
cc51ad5d
...
...
@@ -12,17 +12,22 @@ import 'package:flutter_tools/src/base/file_system.dart';
import
'package:flutter_tools/src/base/io.dart'
;
import
'package:flutter_tools/src/base/logger.dart'
;
import
'package:flutter_tools/src/build_info.dart'
;
import
'package:flutter_tools/src/compile.dart'
;
import
'package:flutter_tools/src/devfs.dart'
;
import
'package:flutter_tools/src/device.dart'
;
import
'package:flutter_tools/src/features.dart'
;
import
'package:flutter_tools/src/globals.dart'
;
import
'package:flutter_tools/src/project.dart'
;
import
'package:flutter_tools/src/reporting/reporting.dart'
;
import
'package:flutter_tools/src/resident_runner.dart'
;
import
'package:flutter_tools/src/build_runner/resident_web_runner.dart'
;
import
'package:flutter_tools/src/build_runner/web_fs.dart'
;
import
'package:flutter_tools/src/web/chrome.dart'
;
import
'package:flutter_tools/src/web/web_device.dart'
;
import
'package:meta/meta.dart'
;
import
'package:mockito/mockito.dart'
;
import
'package:vm_service/vm_service.dart'
;
import
'package:webkit_inspection_protocol/webkit_inspection_protocol.dart'
;
import
'../src/common.dart'
;
import
'../src/testbed.dart'
;
...
...
@@ -33,22 +38,41 @@ void main() {
ResidentWebRunner
residentWebRunner
;
MockDebugConnection
mockDebugConnection
;
MockVmService
mockVmService
;
Mock
WebDevice
mockWeb
Device
;
Mock
ChromeDevice
mockChrome
Device
;
MockAppConnection
mockAppConnection
;
MockFlutterDevice
mockFlutterDevice
;
MockWebDevFS
mockWebDevFS
;
MockResidentCompiler
mockResidentCompiler
;
MockChrome
mockChrome
;
MockChromeConnection
mockChromeConnection
;
MockChromeTab
mockChromeTab
;
MockWipConnection
mockWipConnection
;
MockWipDebugger
mockWipDebugger
;
setUp
(()
{
resetChromeForTesting
();
mockWebFs
=
MockFlutterWebFs
();
mockDebugConnection
=
MockDebugConnection
();
mockVmService
=
MockVmService
();
mock
WebDevice
=
MockWeb
Device
();
mock
ChromeDevice
=
MockChrome
Device
();
mockAppConnection
=
MockAppConnection
();
mockFlutterDevice
=
MockFlutterDevice
();
mockWebDevFS
=
MockWebDevFS
();
mockResidentCompiler
=
MockResidentCompiler
();
mockChrome
=
MockChrome
();
mockChromeConnection
=
MockChromeConnection
();
mockChromeTab
=
MockChromeTab
();
mockWipConnection
=
MockWipConnection
();
mockWipDebugger
=
MockWipDebugger
();
when
(
mockFlutterDevice
.
device
).
thenReturn
(
mockChromeDevice
);
testbed
=
Testbed
(
setup:
()
{
residentWebRunner
=
Resident
WebRunner
(
mock
Web
Device
,
residentWebRunner
=
DwdsWebRunnerFactory
().
create
WebRunner
(
mock
Flutter
Device
,
flutterProject:
FlutterProject
.
current
(),
debuggingOptions:
DebuggingOptions
.
enabled
(
BuildInfo
.
debug
),
ipv6:
true
,
stayResident:
true
,
);
},
overrides:
<
Type
,
Generator
>{
...
...
@@ -88,26 +112,44 @@ void main() {
return
const
Stream
<
Event
>.
empty
();
});
when
(
mockDebugConnection
.
uri
).
thenReturn
(
'ws://127.0.0.1/abcd/'
);
when
(
mockFlutterDevice
.
devFS
).
thenReturn
(
mockWebDevFS
);
when
(
mockWebDevFS
.
sources
).
thenReturn
(<
Uri
>[]);
when
(
mockFlutterDevice
.
generator
).
thenReturn
(
mockResidentCompiler
);
when
(
mockChrome
.
chromeConnection
).
thenReturn
(
mockChromeConnection
);
when
(
mockChromeConnection
.
getTab
(
any
)).
thenAnswer
((
Invocation
invocation
)
async
{
return
mockChromeTab
;
});
when
(
mockChromeTab
.
connect
()).
thenAnswer
((
Invocation
invocation
)
async
{
return
mockWipConnection
;
});
when
(
mockWipConnection
.
debugger
).
thenReturn
(
mockWipDebugger
);
}
test
(
'runner with web server device does not support debugging'
,
()
=>
testbed
.
run
(()
{
final
ResidentRunner
profileResidentWebRunner
=
ResidentWebRunner
(
WebServerDevice
(),
when
(
mockFlutterDevice
.
device
).
thenReturn
(
WebServerDevice
());
final
ResidentRunner
profileResidentWebRunner
=
residentWebRunner
=
DwdsWebRunnerFactory
().
createWebRunner
(
mockFlutterDevice
,
flutterProject:
FlutterProject
.
current
(),
debuggingOptions:
DebuggingOptions
.
enabled
(
BuildInfo
.
debug
),
ipv6:
true
,
stayResident:
true
,
);
expect
(
profileResidentWebRunner
.
debuggingEnabled
,
false
);
when
(
mockFlutterDevice
.
device
).
thenReturn
(
MockChromeDevice
());
expect
(
residentWebRunner
.
debuggingEnabled
,
true
);
}));
test
(
'profile does not supportsServiceProtocol'
,
()
=>
testbed
.
run
(()
{
final
ResidentRunner
profileResidentWebRunner
=
ResidentWebRunner
(
MockWebDevice
(),
when
(
mockFlutterDevice
.
device
).
thenReturn
(
mockChromeDevice
);
final
ResidentRunner
profileResidentWebRunner
=
DwdsWebRunnerFactory
().
createWebRunner
(
mockFlutterDevice
,
flutterProject:
FlutterProject
.
current
(),
debuggingOptions:
DebuggingOptions
.
enabled
(
BuildInfo
.
profile
),
ipv6:
true
,
stayResident:
true
,
);
expect
(
profileResidentWebRunner
.
supportsServiceProtocol
,
false
);
...
...
@@ -119,7 +161,7 @@ void main() {
final
BufferLogger
bufferLogger
=
logger
;
expect
(
await
residentWebRunner
.
run
(),
1
);
expect
(
bufferLogger
.
errorText
,
contains
(
'
No application found for TargetPlatform.web_javascript
'
));
expect
(
bufferLogger
.
errorText
,
contains
(
'
This application is not configured to build on the web
'
));
}));
test
(
'Exits on run if target file does not exist'
,
()
=>
testbed
.
run
(()
async
{
...
...
@@ -156,8 +198,8 @@ void main() {
test
(
'Can successfully run and disconnect with --no-resident'
,
()
=>
testbed
.
run
(()
async
{
_setupMocks
();
residentWebRunner
=
Resident
WebRunner
(
mock
Web
Device
,
residentWebRunner
=
DwdsWebRunnerFactory
().
create
WebRunner
(
mock
Flutter
Device
,
flutterProject:
FlutterProject
.
current
(),
debuggingOptions:
DebuggingOptions
.
enabled
(
BuildInfo
.
debug
),
ipv6:
true
,
...
...
@@ -192,11 +234,12 @@ void main() {
}));
test
(
'Does not run main with --start-paused'
,
()
=>
testbed
.
run
(()
async
{
residentWebRunner
=
Resident
WebRunner
(
mock
Web
Device
,
residentWebRunner
=
DwdsWebRunnerFactory
().
create
WebRunner
(
mock
Flutter
Device
,
flutterProject:
FlutterProject
.
current
(),
debuggingOptions:
DebuggingOptions
.
enabled
(
BuildInfo
.
debug
,
startPaused:
true
),
ipv6:
true
,
stayResident:
true
,
);
_setupMocks
();
final
Completer
<
DebugConnectionInfo
>
connectionInfoCompleter
=
Completer
<
DebugConnectionInfo
>();
...
...
@@ -244,6 +287,94 @@ void main() {
Usage:
()
=>
MockFlutterUsage
(),
}));
test
(
'Can hot reload after attaching - experimental'
,
()
=>
testbed
.
run
(()
async
{
_setupMocks
();
launchChromeInstance
(
mockChrome
);
when
(
mockWebDevFS
.
update
(
mainPath:
anyNamed
(
'mainPath'
),
target:
anyNamed
(
'target'
),
bundle:
anyNamed
(
'bundle'
),
firstBuildTime:
anyNamed
(
'firstBuildTime'
),
bundleFirstUpload:
anyNamed
(
'bundleFirstUpload'
),
generator:
anyNamed
(
'generator'
),
fullRestart:
anyNamed
(
'fullRestart'
),
dillOutputPath:
anyNamed
(
'dillOutputPath'
),
trackWidgetCreation:
anyNamed
(
'trackWidgetCreation'
),
projectRootPath:
anyNamed
(
'projectRootPath'
),
pathToReload:
anyNamed
(
'pathToReload'
),
invalidatedFiles:
anyNamed
(
'invalidatedFiles'
),
)).
thenAnswer
((
Invocation
invocation
)
async
{
return
UpdateFSReport
(
success:
true
)
..
invalidatedModules
=
<
String
>[
'example'
];
});
final
BufferLogger
bufferLogger
=
logger
;
final
Completer
<
DebugConnectionInfo
>
connectionInfoCompleter
=
Completer
<
DebugConnectionInfo
>();
unawaited
(
residentWebRunner
.
run
(
connectionInfoCompleter:
connectionInfoCompleter
,
));
await
connectionInfoCompleter
.
future
;
final
OperationResult
result
=
await
residentWebRunner
.
restart
(
fullRestart:
false
);
expect
(
bufferLogger
.
statusText
,
contains
(
'Reloaded application in'
));
expect
(
result
.
code
,
0
);
verify
(
mockResidentCompiler
.
accept
()).
called
(
2
);
// ensure that analytics are sent.
verify
(
Usage
.
instance
.
sendEvent
(
'hot'
,
'restart'
,
parameters:
<
String
,
String
>{
'cd27'
:
'web-javascript'
,
'cd28'
:
null
,
'cd29'
:
'false'
,
'cd30'
:
'true'
,
})).
called
(
1
);
verify
(
Usage
.
instance
.
sendTiming
(
'hot'
,
'web-incremental-restart'
,
any
)).
called
(
1
);
},
overrides:
<
Type
,
Generator
>{
Usage:
()
=>
MockFlutterUsage
(),
FeatureFlags:
()
=>
TestFeatureFlags
(
isWebIncrementalCompilerEnabled:
true
),
}));
test
(
'Can hot restart after attaching - experimental'
,
()
=>
testbed
.
run
(()
async
{
_setupMocks
();
launchChromeInstance
(
mockChrome
);
when
(
mockWebDevFS
.
update
(
mainPath:
anyNamed
(
'mainPath'
),
target:
anyNamed
(
'target'
),
bundle:
anyNamed
(
'bundle'
),
firstBuildTime:
anyNamed
(
'firstBuildTime'
),
bundleFirstUpload:
anyNamed
(
'bundleFirstUpload'
),
generator:
anyNamed
(
'generator'
),
fullRestart:
anyNamed
(
'fullRestart'
),
dillOutputPath:
anyNamed
(
'dillOutputPath'
),
trackWidgetCreation:
anyNamed
(
'trackWidgetCreation'
),
projectRootPath:
anyNamed
(
'projectRootPath'
),
pathToReload:
anyNamed
(
'pathToReload'
),
invalidatedFiles:
anyNamed
(
'invalidatedFiles'
),
)).
thenAnswer
((
Invocation
invocation
)
async
{
return
UpdateFSReport
(
success:
true
)
..
invalidatedModules
=
<
String
>[
'example'
];
});
final
BufferLogger
bufferLogger
=
logger
;
final
Completer
<
DebugConnectionInfo
>
connectionInfoCompleter
=
Completer
<
DebugConnectionInfo
>();
unawaited
(
residentWebRunner
.
run
(
connectionInfoCompleter:
connectionInfoCompleter
,
));
await
connectionInfoCompleter
.
future
;
final
OperationResult
result
=
await
residentWebRunner
.
restart
(
fullRestart:
true
);
expect
(
bufferLogger
.
statusText
,
contains
(
'Restarted application in'
));
expect
(
result
.
code
,
0
);
verify
(
mockResidentCompiler
.
accept
()).
called
(
2
);
// ensure that analytics are sent.
verify
(
Usage
.
instance
.
sendEvent
(
'hot'
,
'restart'
,
parameters:
<
String
,
String
>{
'cd27'
:
'web-javascript'
,
'cd28'
:
null
,
'cd29'
:
'false'
,
'cd30'
:
'true'
,
})).
called
(
1
);
verifyNever
(
Usage
.
instance
.
sendTiming
(
'hot'
,
'web-incremental-restart'
,
any
));
},
overrides:
<
Type
,
Generator
>{
Usage:
()
=>
MockFlutterUsage
(),
FeatureFlags:
()
=>
TestFeatureFlags
(
isWebIncrementalCompilerEnabled:
true
),
}));
test
(
'Can hot restart after attaching'
,
()
=>
testbed
.
run
(()
async
{
_setupMocks
();
final
BufferLogger
bufferLogger
=
logger
;
...
...
@@ -526,7 +657,7 @@ void main() {
test
(
'cleanup of resources is safe to call multiple times'
,
()
=>
testbed
.
run
(()
async
{
_setupMocks
();
bool
debugClosed
=
false
;
when
(
mock
Web
Device
.
stopApp
(
any
)).
thenAnswer
((
Invocation
invocation
)
async
{
when
(
mock
Chrome
Device
.
stopApp
(
any
)).
thenAnswer
((
Invocation
invocation
)
async
{
if
(
debugClosed
)
{
throw
StateError
(
'debug connection closed twice'
);
}
...
...
@@ -564,7 +695,7 @@ void main() {
test
(
'Prints target and device name on run'
,
()
=>
testbed
.
run
(()
async
{
_setupMocks
();
when
(
mock
Web
Device
.
name
).
thenReturn
(
'Chromez'
);
when
(
mock
Chrome
Device
.
name
).
thenReturn
(
'Chromez'
);
final
Completer
<
DebugConnectionInfo
>
connectionInfoCompleter
=
Completer
<
DebugConnectionInfo
>();
unawaited
(
residentWebRunner
.
run
(
connectionInfoCompleter:
connectionInfoCompleter
,
...
...
@@ -756,10 +887,18 @@ void main() {
}
class
MockFlutterUsage
extends
Mock
implements
Usage
{}
class
Mock
Web
Device
extends
Mock
implements
ChromeDevice
{}
class
Mock
Chrome
Device
extends
Mock
implements
ChromeDevice
{}
class
MockBuildDaemonCreator
extends
Mock
implements
BuildDaemonCreator
{}
class
MockFlutterWebFs
extends
Mock
implements
WebFs
{}
class
MockDebugConnection
extends
Mock
implements
DebugConnection
{}
class
MockAppConnection
extends
Mock
implements
AppConnection
{}
class
MockVmService
extends
Mock
implements
VmService
{}
class
MockStatus
extends
Mock
implements
Status
{}
class
MockFlutterDevice
extends
Mock
implements
FlutterDevice
{}
class
MockWebDevFS
extends
Mock
implements
DevFS
{}
class
MockResidentCompiler
extends
Mock
implements
ResidentCompiler
{}
class
MockChrome
extends
Mock
implements
Chrome
{}
class
MockChromeConnection
extends
Mock
implements
ChromeConnection
{}
class
MockChromeTab
extends
Mock
implements
ChromeTab
{}
class
MockWipConnection
extends
Mock
implements
WipConnection
{}
class
MockWipDebugger
extends
Mock
implements
WipDebugger
{}
packages/flutter_tools/test/general.shard/web/devfs_web_test.dart
View file @
cc51ad5d
...
...
@@ -89,28 +89,36 @@ void main() {
test
(
'Handles against malformed manifest'
,
()
=>
testbed
.
run
(()
async
{
final
File
source
=
fs
.
file
(
'source'
)
..
writeAsStringSync
(
'main() {}'
);
final
File
sourcemap
=
fs
.
file
(
'sourcemap'
)
..
writeAsStringSync
(
'{}'
);
// Missing ending offset.
final
File
manifestMissingOffset
=
fs
.
file
(
'manifestA'
)
..
writeAsStringSync
(
json
.
encode
(<
String
,
Object
>{
'/foo.js'
:
<
int
>[
0
]}));
// Non-file URI.
final
File
manifestNonFileScheme
=
fs
.
file
(
'manifestA'
)
..
writeAsStringSync
(
json
.
encode
(<
String
,
Object
>{
'/foo.js'
:
<
int
>[
0
,
10
]}));
..
writeAsStringSync
(
json
.
encode
(<
String
,
Object
>{
'/foo.js'
:
<
String
,
Object
>{
'code'
:
<
int
>[
0
],
'sourcemap'
:
<
int
>[
0
],
}}));
final
File
manifestOutOfBounds
=
fs
.
file
(
'manifest'
)
..
writeAsStringSync
(
json
.
encode
(<
String
,
Object
>{
'/foo.js'
:
<
int
>[
0
,
100
]}));
..
writeAsStringSync
(
json
.
encode
(<
String
,
Object
>{
'/foo.js'
:
<
String
,
Object
>{
'code'
:
<
int
>[
0
,
100
],
'sourcemap'
:
<
int
>[
0
],
}}));
expect
(
webAssetServer
.
write
(
source
,
manifestMissingOffset
),
isEmpty
);
expect
(
webAssetServer
.
write
(
source
,
manifestNonFileScheme
),
isEmpty
);
expect
(
webAssetServer
.
write
(
source
,
manifestOutOfBounds
),
isEmpty
);
expect
(
webAssetServer
.
write
(
source
,
manifestMissingOffset
,
sourcemap
),
isEmpty
);
expect
(
webAssetServer
.
write
(
source
,
manifestOutOfBounds
,
sourcemap
),
isEmpty
);
}));
test
(
'serves JavaScript files from in memory cache'
,
()
=>
testbed
.
run
(()
async
{
final
File
source
=
fs
.
file
(
'source'
)
..
writeAsStringSync
(
'main() {}'
);
final
File
sourcemap
=
fs
.
file
(
'sourcemap'
)
..
writeAsStringSync
(
'{}'
);
final
File
manifest
=
fs
.
file
(
'manifest'
)
..
writeAsStringSync
(
json
.
encode
(<
String
,
Object
>{
'/foo.js'
:
<
int
>[
0
,
source
.
lengthSync
()]}));
webAssetServer
.
write
(
source
,
manifest
);
..
writeAsStringSync
(
json
.
encode
(<
String
,
Object
>{
'/foo.js'
:
<
String
,
Object
>{
'code'
:
<
int
>[
0
,
source
.
lengthSync
()],
'sourcemap'
:
<
int
>[
0
,
2
],
}}));
webAssetServer
.
write
(
source
,
manifest
,
sourcemap
);
when
(
request
.
uri
).
thenReturn
(
Uri
.
parse
(
'http://foobar/foo.js'
));
requestController
.
add
(
request
);
...
...
@@ -136,9 +144,14 @@ void main() {
test
(
'handles missing JavaScript files from in memory cache'
,
()
=>
testbed
.
run
(()
async
{
final
File
source
=
fs
.
file
(
'source'
)
..
writeAsStringSync
(
'main() {}'
);
final
File
sourcemap
=
fs
.
file
(
'sourcemap'
)
..
writeAsStringSync
(
'{}'
);
final
File
manifest
=
fs
.
file
(
'manifest'
)
..
writeAsStringSync
(
json
.
encode
(<
String
,
Object
>{
'/foo.js'
:
<
int
>[
0
,
source
.
lengthSync
()]}));
webAssetServer
.
write
(
source
,
manifest
);
..
writeAsStringSync
(
json
.
encode
(<
String
,
Object
>{
'/foo.js'
:
<
String
,
Object
>{
'code'
:
<
int
>[
0
,
source
.
lengthSync
()],
'sourcemap'
:
<
int
>[
0
,
2
],
}}));
webAssetServer
.
write
(
source
,
manifest
,
sourcemap
);
when
(
request
.
uri
).
thenReturn
(
Uri
.
parse
(
'http://foobar/bar.js'
));
requestController
.
add
(
request
);
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment