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
3a0d8377
Unverified
Commit
3a0d8377
authored
Apr 02, 2020
by
Anna Gringauze
Committed by
GitHub
Apr 02, 2020
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Enable expression evaluation in debugger for web platform (#53595)
parent
191f86ea
Changes
11
Show whitespace changes
Inline
Side-by-side
Showing
11 changed files
with
350 additions
and
4 deletions
+350
-4
devfs_web.dart
packages/flutter_tools/lib/src/build_runner/devfs_web.dart
+39
-1
resident_web_runner.dart
...utter_tools/lib/src/build_runner/resident_web_runner.dart
+1
-0
codegen.dart
packages/flutter_tools/lib/src/codegen.dart
+9
-0
update_packages.dart
packages/flutter_tools/lib/src/commands/update_packages.dart
+2
-1
compile.dart
packages/flutter_tools/lib/src/compile.dart
+101
-0
pubspec.yaml
packages/flutter_tools/pubspec.yaml
+2
-2
devfs_web_test.dart
.../flutter_tools/test/general.shard/web/devfs_web_test.dart
+1
-0
expression_evaluation_web_test.dart
...est/integration.shard/expression_evaluation_web_test.dart
+178
-0
tests_project.dart
...tools/test/integration.shard/test_data/tests_project.dart
+1
-0
test_driver.dart
...ges/flutter_tools/test/integration.shard/test_driver.dart
+2
-0
mocks.dart
packages/flutter_tools/test/src/mocks.dart
+14
-0
No files found.
packages/flutter_tools/lib/src/build_runner/devfs_web.dart
View file @
3a0d8377
...
...
@@ -36,6 +36,39 @@ import '../globals.dart' as globals;
import
'../web/bootstrap.dart'
;
import
'../web/chrome.dart'
;
/// An expression compiler connecting to FrontendServer
///
/// This is only used in development mode
class
WebExpressionCompiler
implements
ExpressionCompiler
{
WebExpressionCompiler
(
this
.
_generator
);
final
ResidentCompiler
_generator
;
@override
Future
<
ExpressionCompilationResult
>
compileExpressionToJs
(
String
isolateId
,
String
libraryUri
,
int
line
,
int
column
,
Map
<
String
,
String
>
jsModules
,
Map
<
String
,
String
>
jsFrameValues
,
String
moduleName
,
String
expression
,
)
async
{
final
CompilerOutput
compilerOutput
=
await
_generator
.
compileExpressionToJs
(
libraryUri
,
line
,
column
,
jsModules
,
jsFrameValues
,
moduleName
,
expression
);
if
(
compilerOutput
!=
null
&&
compilerOutput
.
outputFilename
!=
null
)
{
final
String
content
=
utf8
.
decode
(
globals
.
fs
.
file
(
compilerOutput
.
outputFilename
).
readAsBytesSync
());
return
ExpressionCompilationResult
(
content
,
compilerOutput
.
errorCount
>
0
);
}
throw
Exception
(
'Failed to compile
$expression
'
);
}
}
/// A web server which handles serving JavaScript and assets.
///
/// This is only used in development mode.
...
...
@@ -85,7 +118,8 @@ class WebAssetServer implements AssetReader {
UrlTunneller
urlTunneller
,
BuildMode
buildMode
,
bool
enableDwds
,
Uri
entrypoint
,
{
Uri
entrypoint
,
ExpressionCompiler
expressionCompiler
,
{
bool
testMode
=
false
,
})
async
{
try
{
...
...
@@ -170,6 +204,7 @@ class WebAssetServer implements AssetReader {
serverPathForModule
,
serverPathForAppUri
,
),
expressionCompiler:
expressionCompiler
);
shelf
.
Pipeline
pipeline
=
const
shelf
.
Pipeline
();
if
(
enableDwds
)
{
...
...
@@ -501,6 +536,7 @@ class WebDevFS implements DevFS {
@required
this
.
buildMode
,
@required
this
.
enableDwds
,
@required
this
.
entrypoint
,
@required
this
.
expressionCompiler
,
this
.
testMode
=
false
,
});
...
...
@@ -512,6 +548,7 @@ class WebDevFS implements DevFS {
final
BuildMode
buildMode
;
final
bool
enableDwds
;
final
bool
testMode
;
final
ExpressionCompiler
expressionCompiler
;
WebAssetServer
webAssetServer
;
...
...
@@ -572,6 +609,7 @@ class WebDevFS implements DevFS {
buildMode
,
enableDwds
,
entrypoint
,
expressionCompiler
,
testMode:
testMode
,
);
_baseUri
=
Uri
.
parse
(
'http://
$hostname
:
$port
'
);
...
...
packages/flutter_tools/lib/src/build_runner/resident_web_runner.dart
View file @
3a0d8377
...
...
@@ -421,6 +421,7 @@ class _ResidentWebRunner extends ResidentWebRunner {
buildMode:
debuggingOptions
.
buildInfo
.
mode
,
enableDwds:
_enableDwds
,
entrypoint:
globals
.
fs
.
file
(
target
).
uri
,
expressionCompiler:
WebExpressionCompiler
(
device
.
generator
),
);
final
Uri
url
=
await
device
.
devFS
.
create
();
if
(
debuggingOptions
.
buildInfo
.
isDebug
)
{
...
...
packages/flutter_tools/lib/src/codegen.dart
View file @
3a0d8377
...
...
@@ -160,6 +160,15 @@ class CodeGeneratingResidentCompiler implements ResidentCompiler {
return
_residentCompiler
.
compileExpression
(
expression
,
definitions
,
typeDefinitions
,
libraryUri
,
klass
,
isStatic
);
}
@override
Future
<
CompilerOutput
>
compileExpressionToJs
(
String
libraryUri
,
int
line
,
int
column
,
Map
<
String
,
String
>
jsModules
,
Map
<
String
,
String
>
jsFrameValues
,
String
moduleName
,
String
expression
)
{
return
_residentCompiler
.
compileExpressionToJs
(
libraryUri
,
line
,
column
,
jsModules
,
jsFrameValues
,
moduleName
,
expression
);
}
@override
Future
<
CompilerOutput
>
recompile
(
String
mainPath
,
List
<
Uri
>
invalidatedFiles
,
{
String
outputPath
,
String
packagesFilePath
})
async
{
if
(
_codegenDaemon
.
lastStatus
!=
CodegenStatus
.
Succeeded
&&
_codegenDaemon
.
lastStatus
!=
CodegenStatus
.
Failed
)
{
...
...
packages/flutter_tools/lib/src/commands/update_packages.dart
View file @
3a0d8377
...
...
@@ -26,7 +26,8 @@ const Map<String, String> _kManuallyPinnedDependencies = <String, String>{
'mockito'
:
'^4.1.0'
,
// Prevent mockito from downgrading to 4.0.0
'vm_service_client'
:
'0.2.6+2'
,
// Final version before being marked deprecated.
'video_player'
:
'0.10.6'
,
// 0.10.7 fails a gallery smoke test for toString.
'package_config'
:
'1.9.1'
'package_config'
:
'1.9.1'
,
'flutter_template_images'
:
'1.0.0'
,
// 1.0.1 breaks windows tests
};
class
UpdatePackagesCommand
extends
FlutterCommand
{
...
...
packages/flutter_tools/lib/src/compile.dart
View file @
3a0d8377
...
...
@@ -431,6 +431,31 @@ class _CompileExpressionRequest extends _CompilationRequest {
compiler
.
_compileExpression
(
this
);
}
class
_CompileExpressionToJsRequest
extends
_CompilationRequest
{
_CompileExpressionToJsRequest
(
Completer
<
CompilerOutput
>
completer
,
this
.
libraryUri
,
this
.
line
,
this
.
column
,
this
.
jsModules
,
this
.
jsFrameValues
,
this
.
moduleName
,
this
.
expression
,
)
:
super
(
completer
);
final
String
libraryUri
;
final
int
line
;
final
int
column
;
final
Map
<
String
,
String
>
jsModules
;
final
Map
<
String
,
String
>
jsFrameValues
;
final
String
moduleName
;
final
String
expression
;
@override
Future
<
CompilerOutput
>
_run
(
DefaultResidentCompiler
compiler
)
async
=>
compiler
.
_compileExpressionToJs
(
this
);
}
class
_RejectRequest
extends
_CompilationRequest
{
_RejectRequest
(
Completer
<
CompilerOutput
>
completer
)
:
super
(
completer
);
...
...
@@ -489,6 +514,36 @@ abstract class ResidentCompiler {
bool
isStatic
,
);
/// Compiles [expression] in [libraryUri] at [line]:[column] to JavaScript
/// in [moduleName].
///
/// Values listed in [jsFrameValues] are substituted for their names in the
/// [expression].
///
/// Ensures that all [jsModules] are loaded and accessible inside the
/// expression.
///
/// Example values of parameters:
/// [moduleName] is of the form '/packages/hello_world_main.dart'
/// [jsFrameValues] is a map from js variable name to its primitive value
/// or another variable name, for example
/// { 'x': '1', 'y': 'y', 'o': 'null' }
/// [jsModules] is a map from variable name to the module name, where
/// variable name is the name originally used in JavaScript to contain the
/// module object, for example:
/// { 'dart':'dart_sdk', 'main': '/packages/hello_world_main.dart' }
/// Returns a [CompilerOutput] including the name of the file containing the
/// compilation result and a number of errors
Future
<
CompilerOutput
>
compileExpressionToJs
(
String
libraryUri
,
int
line
,
int
column
,
Map
<
String
,
String
>
jsModules
,
Map
<
String
,
String
>
jsFrameValues
,
String
moduleName
,
String
expression
,
);
/// Should be invoked when results of compilation are accepted by the client.
///
/// Either [accept] or [reject] should be called after every [recompile] call.
...
...
@@ -778,6 +833,52 @@ class DefaultResidentCompiler implements ResidentCompiler {
return
_stdoutHandler
.
compilerOutput
.
future
;
}
@override
Future
<
CompilerOutput
>
compileExpressionToJs
(
String
libraryUri
,
int
line
,
int
column
,
Map
<
String
,
String
>
jsModules
,
Map
<
String
,
String
>
jsFrameValues
,
String
moduleName
,
String
expression
,
)
{
if
(!
_controller
.
hasListener
)
{
_controller
.
stream
.
listen
(
_handleCompilationRequest
);
}
final
Completer
<
CompilerOutput
>
completer
=
Completer
<
CompilerOutput
>();
_controller
.
add
(
_CompileExpressionToJsRequest
(
completer
,
libraryUri
,
line
,
column
,
jsModules
,
jsFrameValues
,
moduleName
,
expression
)
);
return
completer
.
future
;
}
Future
<
CompilerOutput
>
_compileExpressionToJs
(
_CompileExpressionToJsRequest
request
)
async
{
_stdoutHandler
.
reset
(
suppressCompilerMessages:
true
,
expectSources:
false
);
// 'compile-expression-to-js' should be invoked after compiler has been started,
// program was compiled.
if
(
_server
==
null
)
{
return
null
;
}
final
String
inputKey
=
Uuid
().
generateV4
();
_server
.
stdin
.
writeln
(
'compile-expression-to-js
$inputKey
'
);
_server
.
stdin
.
writeln
(
request
.
libraryUri
??
''
);
_server
.
stdin
.
writeln
(
request
.
line
);
_server
.
stdin
.
writeln
(
request
.
column
);
request
.
jsModules
?.
forEach
((
String
k
,
String
v
)
{
_server
.
stdin
.
writeln
(
'
$k
:
$v
'
);
});
_server
.
stdin
.
writeln
(
inputKey
);
request
.
jsFrameValues
?.
forEach
((
String
k
,
String
v
)
{
_server
.
stdin
.
writeln
(
'
$k
:
$v
'
);
});
_server
.
stdin
.
writeln
(
inputKey
);
_server
.
stdin
.
writeln
(
request
.
moduleName
??
''
);
_server
.
stdin
.
writeln
(
request
.
expression
??
''
);
return
_stdoutHandler
.
compilerOutput
.
future
;
}
@override
void
accept
()
{
if
(
_compileRequestNeedsConfirmation
)
{
...
...
packages/flutter_tools/pubspec.yaml
View file @
3a0d8377
...
...
@@ -11,7 +11,7 @@ dependencies:
# To update these, use "flutter update-packages --force-upgrade".
archive
:
2.0.13
args
:
1.6.0
dwds
:
3.0.
1
dwds
:
3.0.
2
completion
:
0.2.2
coverage
:
0.13.9
crypto
:
2.1.4
...
...
@@ -112,4 +112,4 @@ dartdoc:
# Exclude this package from the hosted API docs.
nodoc
:
true
# PUBSPEC CHECKSUM:
65c1
# PUBSPEC CHECKSUM:
53c2
packages/flutter_tools/test/general.shard/web/devfs_web_test.dart
View file @
3a0d8377
...
...
@@ -373,6 +373,7 @@ void main() {
enableDwds:
false
,
entrypoint:
Uri
.
base
,
testMode:
true
,
expressionCompiler:
null
,
);
webDevFS
.
requireJS
.
createSync
(
recursive:
true
);
webDevFS
.
stackTraceMapper
.
createSync
(
recursive:
true
);
...
...
packages/flutter_tools/test/integration.shard/expression_evaluation_web_test.dart
0 → 100644
View file @
3a0d8377
// Copyright 2014 The Flutter 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
'dart:async'
;
import
'dart:io'
;
import
'package:file/file.dart'
;
import
'package:flutter_tools/src/base/file_system.dart'
;
import
'package:vm_service/vm_service.dart'
;
import
'../src/common.dart'
;
import
'test_data/basic_project.dart'
;
import
'test_data/tests_project.dart'
;
import
'test_driver.dart'
;
import
'test_utils.dart'
;
void
batch1
(
)
{
final
BasicProject
_project
=
BasicProject
();
Directory
tempDir
;
FlutterRunTestDriver
_flutter
;
Future
<
void
>
initProject
()
async
{
tempDir
=
createResolvedTempDirectorySync
(
'run_expression_eval_test.'
);
await
_project
.
setUpIn
(
tempDir
);
_flutter
=
FlutterRunTestDriver
(
tempDir
);
}
Future
<
void
>
cleanProject
()
async
{
await
_flutter
.
stop
();
tryToDelete
(
tempDir
);
}
Future
<
void
>
breakInBuildMethod
(
FlutterTestDriver
flutter
)
async
{
await
_flutter
.
breakAt
(
_project
.
buildMethodBreakpointUri
,
_project
.
buildMethodBreakpointLine
,
);
}
Future
<
void
>
breakInTopLevelFunction
(
FlutterTestDriver
flutter
)
async
{
await
_flutter
.
breakAt
(
_project
.
topLevelFunctionBreakpointUri
,
_project
.
topLevelFunctionBreakpointLine
,
);
}
test
(
'flutter run expression evaluation - can evaluate trivial expressions in top level function'
,
()
async
{
await
initProject
();
await
_flutter
.
run
(
withDebugger:
true
,
chrome:
true
);
await
breakInTopLevelFunction
(
_flutter
);
await
evaluateTrivialExpressions
(
_flutter
);
await
cleanProject
();
},
skip:
'CI not setup for web tests'
);
// https://github.com/flutter/flutter/issues/53779
test
(
'flutter run expression evaluation - can evaluate trivial expressions in build method'
,
()
async
{
await
initProject
();
await
_flutter
.
run
(
withDebugger:
true
,
chrome:
true
);
await
breakInBuildMethod
(
_flutter
);
await
evaluateTrivialExpressions
(
_flutter
);
await
cleanProject
();
},
skip:
'CI not setup for web tests'
);
// https://github.com/flutter/flutter/issues/53779
test
(
'flutter run expression evaluation - can evaluate complex expressions in top level function'
,
()
async
{
await
initProject
();
await
_flutter
.
run
(
withDebugger:
true
,
chrome:
true
);
await
breakInTopLevelFunction
(
_flutter
);
await
evaluateComplexExpressions
(
_flutter
);
await
cleanProject
();
},
skip:
'CI not setup for web tests'
);
// https://github.com/flutter/flutter/issues/53779
test
(
'flutter run expression evaluation - can evaluate complex expressions in build method'
,
()
async
{
await
initProject
();
await
_flutter
.
run
(
withDebugger:
true
,
chrome:
true
);
await
breakInBuildMethod
(
_flutter
);
await
evaluateComplexExpressions
(
_flutter
);
await
cleanProject
();
},
skip:
'CI not setup for web tests'
);
// https://github.com/flutter/flutter/issues/53779
test
(
'flutter run expression evaluation - can evaluate expressions returning complex objects in top level function'
,
()
async
{
await
initProject
();
await
_flutter
.
run
(
withDebugger:
true
,
chrome:
true
);
await
breakInTopLevelFunction
(
_flutter
);
await
evaluateComplexReturningExpressions
(
_flutter
);
await
cleanProject
();
},
skip:
'Evaluate on objects is not supported for web yet'
);
test
(
'flutter run expression evaluation - can evaluate expressions returning complex objects in build method'
,
()
async
{
await
initProject
();
await
_flutter
.
run
(
withDebugger:
true
,
chrome:
true
);
await
breakInBuildMethod
(
_flutter
);
await
evaluateComplexReturningExpressions
(
_flutter
);
await
cleanProject
();
},
skip:
'Evaluate on objects is not supported for web yet'
);
}
void
batch2
(
)
{
final
TestsProject
_project
=
TestsProject
();
Directory
tempDir
;
FlutterRunTestDriver
_flutter
;
Future
<
void
>
initProject
()
async
{
tempDir
=
createResolvedTempDirectorySync
(
'test_expression_eval_test.'
);
await
_project
.
setUpIn
(
tempDir
);
_flutter
=
FlutterRunTestDriver
(
tempDir
);
}
Future
<
void
>
cleanProject
()
async
{
await
_flutter
.
stop
();
tryToDelete
(
tempDir
);
}
Future
<
void
>
breakInMethod
(
FlutterTestDriver
flutter
)
async
{
await
_flutter
.
breakAt
(
_project
.
breakpointAppUri
,
_project
.
breakpointLine
,
);
}
test
(
'flutter test expression evaluation - can evaluate trivial expressions in a test'
,
()
async
{
await
initProject
();
await
_flutter
.
run
(
withDebugger:
true
,
chrome:
true
,
script:
_project
.
testFilePath
);
await
breakInMethod
(
_flutter
);
await
evaluateTrivialExpressions
(
_flutter
);
await
cleanProject
();
},
skip:
'CI not setup for web tests'
);
// https://github.com/flutter/flutter/issues/53779
test
(
'flutter test expression evaluation - can evaluate complex expressions in a test'
,
()
async
{
await
initProject
();
await
_flutter
.
run
(
withDebugger:
true
,
chrome:
true
,
script:
_project
.
testFilePath
);
await
breakInMethod
(
_flutter
);
await
evaluateComplexExpressions
(
_flutter
);
await
cleanProject
();
},
skip:
'CI not setup for web tests'
);
// https://github.com/flutter/flutter/issues/53779
test
(
'flutter test expression evaluation - can evaluate expressions returning complex objects in a test'
,
()
async
{
await
initProject
();
await
_flutter
.
run
(
withDebugger:
true
,
chrome:
true
,
script:
_project
.
testFilePath
);
await
breakInMethod
(
_flutter
);
await
evaluateComplexReturningExpressions
(
_flutter
);
await
cleanProject
();
},
skip:
'Evaluate on objects is not supported for web yet'
);
}
Future
<
void
>
evaluateTrivialExpressions
(
FlutterTestDriver
flutter
)
async
{
InstanceRef
res
;
res
=
await
flutter
.
evaluateInFrame
(
'"test"'
);
expect
(
res
.
kind
==
InstanceKind
.
kString
&&
res
.
valueAsString
==
'test'
,
isTrue
);
res
=
await
flutter
.
evaluateInFrame
(
'1'
);
expect
(
res
.
kind
==
InstanceKind
.
kDouble
&&
res
.
valueAsString
==
1
.
toString
(),
isTrue
);
res
=
await
flutter
.
evaluateInFrame
(
'true'
);
expect
(
res
.
kind
==
InstanceKind
.
kBool
&&
res
.
valueAsString
==
true
.
toString
(),
isTrue
);
}
Future
<
void
>
evaluateComplexExpressions
(
FlutterTestDriver
flutter
)
async
{
final
InstanceRef
res
=
await
flutter
.
evaluateInFrame
(
'new DateTime.now().year'
);
expect
(
res
.
kind
==
InstanceKind
.
kDouble
&&
res
.
valueAsString
==
DateTime
.
now
().
year
.
toString
(),
isTrue
);
}
Future
<
void
>
evaluateComplexReturningExpressions
(
FlutterTestDriver
flutter
)
async
{
final
DateTime
now
=
DateTime
.
now
();
final
InstanceRef
resp
=
await
flutter
.
evaluateInFrame
(
'new DateTime.now()'
);
expect
(
resp
.
classRef
.
name
,
equals
(
'DateTime'
));
// Ensure we got a reasonable approximation. The more accurate we try to
// make this, the more likely it'll fail due to differences in the time
// in the remote VM and the local VM at the time the code runs.
final
InstanceRef
res
=
await
flutter
.
evaluate
(
resp
.
id
,
r'"$year-$month-$day"'
);
expect
(
res
.
valueAsString
,
equals
(
'
${now.year}
-
${now.month}
-
${now.day}
'
));
}
void
main
(
)
{
batch1
();
batch2
();
}
packages/flutter_tools/test/integration.shard/test_data/tests_project.dart
View file @
3a0d8377
...
...
@@ -49,6 +49,7 @@ class TestsProject extends Project {
String
get
testFilePath
=>
globals
.
fs
.
path
.
join
(
dir
.
path
,
'test'
,
'test.dart'
);
Uri
get
breakpointUri
=>
Uri
.
file
(
testFilePath
);
Uri
get
breakpointAppUri
=>
Uri
.
parse
(
'org-dartlang-app:///test.dart'
);
int
get
breakpointLine
=>
lineContaining
(
testContent
,
'// BREAKPOINT'
);
}
packages/flutter_tools/test/integration.shard/test_driver.dart
View file @
3a0d8377
...
...
@@ -436,6 +436,7 @@ class FlutterRunTestDriver extends FlutterTestDriver {
bool
pauseOnExceptions
=
false
,
bool
chrome
=
false
,
File
pidFile
,
String
script
,
})
async
{
await
_setupProcess
(
<
String
>[
...
...
@@ -453,6 +454,7 @@ class FlutterRunTestDriver extends FlutterTestDriver {
startPaused:
startPaused
,
pauseOnExceptions:
pauseOnExceptions
,
pidFile:
pidFile
,
script:
script
,
);
}
...
...
packages/flutter_tools/test/src/mocks.dart
View file @
3a0d8377
...
...
@@ -646,6 +646,20 @@ class MockResidentCompiler extends BasicMock implements ResidentCompiler {
)
async
{
return
null
;
}
@override
Future
<
CompilerOutput
>
compileExpressionToJs
(
String
libraryUri
,
int
line
,
int
column
,
Map
<
String
,
String
>
jsModules
,
Map
<
String
,
String
>
jsFrameValues
,
String
moduleName
,
String
expression
,
)
async
{
return
null
;
}
@override
Future
<
CompilerOutput
>
recompile
(
String
mainPath
,
List
<
Uri
>
invalidatedFiles
,
{
String
outputPath
,
String
packagesFilePath
})
async
{
globals
.
fs
.
file
(
outputPath
).
createSync
(
recursive:
true
);
...
...
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