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
ccc3dd96
Unverified
Commit
ccc3dd96
authored
Oct 01, 2019
by
Jonah Williams
Committed by
GitHub
Oct 01, 2019
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Switch to assemble API for dart2js (#41447)
parent
3df57a71
Changes
16
Hide whitespace changes
Inline
Side-by-side
Showing
16 changed files
with
667 additions
and
331 deletions
+667
-331
test.dart
dev/bots/test.dart
+1
-2
build_script.dart
...ages/flutter_tools/lib/src/build_runner/build_script.dart
+2
-123
resident_web_runner.dart
...utter_tools/lib/src/build_runner/resident_web_runner.dart
+18
-1
web_fs.dart
packages/flutter_tools/lib/src/build_runner/web_fs.dart
+133
-58
build_system.dart
...ages/flutter_tools/lib/src/build_system/build_system.dart
+7
-0
file_hash_store.dart
...s/flutter_tools/lib/src/build_system/file_hash_store.dart
+14
-17
assets.dart
...es/flutter_tools/lib/src/build_system/targets/assets.dart
+6
-4
dart.dart
...ages/flutter_tools/lib/src/build_system/targets/dart.dart
+23
-17
macos.dart
...ges/flutter_tools/lib/src/build_system/targets/macos.dart
+1
-1
web.dart
packages/flutter_tools/lib/src/build_system/targets/web.dart
+203
-0
assemble.dart
packages/flutter_tools/lib/src/commands/assemble.dart
+2
-0
compile.dart
packages/flutter_tools/lib/src/web/compile.dart
+27
-57
filecache_test.dart
...tools/test/general.shard/build_system/filecache_test.dart
+8
-8
web_test.dart
...ols/test/general.shard/build_system/targets/web_test.dart
+221
-0
build_web_test.dart
...ter_tools/test/general.shard/commands/build_web_test.dart
+0
-42
asset_server_test.dart
...utter_tools/test/general.shard/web/asset_server_test.dart
+1
-1
No files found.
dev/bots/test.dart
View file @
ccc3dd96
...
...
@@ -282,10 +282,9 @@ Future<void> _runBuildTests() async {
}
// Web compilation tests.
await
_flutterBuildDart2js
(
path
.
join
(
'dev'
,
'integration_tests'
,
'web'
),
path
.
join
(
'lib'
,
'main.dart'
));
// Should fail to compile with dart:io.
// Should
not
fail to compile with dart:io.
await
_flutterBuildDart2js
(
path
.
join
(
'dev'
,
'integration_tests'
,
'web_compile_tests'
),
path
.
join
(
'lib'
,
'dart_io_import.dart'
),
expectNonZeroExit:
true
,
);
print
(
'
${bold}
DONE: All build tests successful.
$reset
'
);
...
...
packages/flutter_tools/lib/src/build_runner/build_script.dart
View file @
ccc3dd96
...
...
@@ -4,21 +4,17 @@
// ignore_for_file: implementation_imports
import
'dart:async'
;
import
'dart:convert'
;
// ignore: dart_convert_import
import
'dart:io'
;
// ignore: dart_io_import
import
'dart:isolate'
;
import
'package:analyzer/dart/analysis/results.dart'
;
import
'package:analyzer/dart/analysis/utilities.dart'
;
import
'package:analyzer/dart/ast/ast.dart'
;
import
'package:archive/archive.dart'
;
import
'package:build/build.dart'
;
import
'package:build_config/build_config.dart'
;
import
'package:build_modules/build_modules.dart'
;
import
'package:build_modules/builders.dart'
;
import
'package:build_modules/src/module_builder.dart'
;
import
'package:build_modules/src/platform.dart'
;
import
'package:build_modules/src/workers.dart'
;
import
'package:build_runner/build_runner.dart'
as
build_runner
;
import
'package:build_runner_core/build_runner_core.dart'
as
core
;
import
'package:build_test/builder.dart'
;
...
...
@@ -26,10 +22,7 @@ import 'package:build_test/src/debug_test_builder.dart';
import
'package:build_web_compilers/build_web_compilers.dart'
;
import
'package:build_web_compilers/builders.dart'
;
import
'package:build_web_compilers/src/dev_compiler_bootstrap.dart'
;
import
'package:crypto/crypto.dart'
;
import
'package:glob/glob.dart'
;
import
'package:path/path.dart'
as
path
;
// ignore: package_path_import
import
'package:scratch_space/scratch_space.dart'
;
import
'package:test_core/backend.dart'
;
const
String
ddcBootstrapExtension
=
'.dart.bootstrap.js'
;
...
...
@@ -248,12 +241,8 @@ class FlutterWebEntrypointBuilder implements Builder {
@override
Future
<
void
>
build
(
BuildStep
buildStep
)
async
{
if
(
release
||
profile
)
{
await
bootstrapDart2Js
(
buildStep
,
flutterWebSdk
,
profile
);
}
else
{
await
bootstrapDdc
(
buildStep
,
platform:
flutterWebPlatform
,
skipPlatformCheckPackages:
skipPlatformCheckPackages
);
}
await
bootstrapDdc
(
buildStep
,
platform:
flutterWebPlatform
,
skipPlatformCheckPackages:
skipPlatformCheckPackages
);
}
}
...
...
@@ -422,116 +411,6 @@ Future<void> main() async {
};
}
Future<void> bootstrapDart2Js(BuildStep buildStep, String flutterWebSdk, bool profile) async {
final AssetId dartEntrypointId = buildStep.inputId;
final AssetId moduleId = dartEntrypointId.changeExtension(moduleExtension(flutterWebPlatform));
final Module module = Module.fromJson(json.decode(await buildStep.readAsString(moduleId)));
final List<Module> allDeps = await module.computeTransitiveDependencies(
buildStep,
throwIfUnsupported: true,
skipPlatformCheckPackages: skipPlatformCheckPackages,
)..add(module);
final ScratchSpace scratchSpace = await buildStep.fetchResource(scratchSpaceResource);
final Iterable<AssetId> allSrcs = allDeps.expand((Module module) => module.sources);
await scratchSpace.ensureAssets(allSrcs, buildStep);
final String packageFile = _createPackageFile(allSrcs, buildStep, scratchSpace);
final String dartPath = dartEntrypointId.path.startsWith('
lib
/
')
? '
package:
$
{
dartEntrypointId
.
package
}/
'
'
$
{
dartEntrypointId
.
path
.
substring
(
'lib/'
.
length
)}
'
: dartEntrypointId.path;
final String jsOutputPath =
'
$
{
path
.
withoutExtension
(
dartPath
.
replaceFirst
(
'package:'
,
'packages/'
))}
'
'
$jsEntrypointExtension
';
final String flutterWebSdkPath = flutterWebSdk;
final String librariesPath = path.join(flutterWebSdkPath, '
libraries
.
json
');
final List<String> args = <String>[
'
--
libraries
-
spec
=
"
$librariesPath
"',
if (profile)
'
-
O1
'
else
'
-
O4
',
'
-
o
',
'
$jsOutputPath
',
'
--
packages
=
"
$packageFile
"',
if (profile)
'
-
Ddart
.
vm
.
profile
=
true
'
else
'
-
Ddart
.
vm
.
product
=
true
',
dartPath,
];
final Dart2JsBatchWorkerPool dart2js = await buildStep.fetchResource(dart2JsWorkerResource);
final Dart2JsResult result = await dart2js.compile(args);
final AssetId jsOutputId = dartEntrypointId.changeExtension(jsEntrypointExtension);
final File jsOutputFile = scratchSpace.fileFor(jsOutputId);
if (result.succeeded && jsOutputFile.existsSync()) {
final String rootDir = path.dirname(jsOutputFile.path);
final String dartFile = path.basename(dartEntrypointId.path);
final Glob fileGlob = Glob('
$dartFile
.
js
*
');
final Archive archive = Archive();
await for (FileSystemEntity jsFile in fileGlob.list(root: rootDir)) {
if (jsFile.path.endsWith(jsEntrypointExtension) ||
jsFile.path.endsWith(jsEntrypointSourceMapExtension)) {
// These are explicitly output, and are not part of the archive.
continue;
}
if (jsFile is File) {
final String fileName = path.relative(jsFile.path, from: rootDir);
final FileStat fileStats = jsFile.statSync();
archive.addFile(
ArchiveFile(fileName, fileStats.size, await jsFile.readAsBytes())
..mode = fileStats.mode
..lastModTime = fileStats.modified.millisecondsSinceEpoch);
}
}
if (archive.isNotEmpty) {
final AssetId archiveId = dartEntrypointId.changeExtension(jsEntrypointArchiveExtension);
await buildStep.writeAsBytes(archiveId, TarEncoder().encode(archive));
}
// Explicitly write out the original js file and sourcemap - we can'
t
output
// these as part of the archive because they already have asset nodes.
await
scratchSpace
.
copyOutput
(
jsOutputId
,
buildStep
);
final
AssetId
jsSourceMapId
=
dartEntrypointId
.
changeExtension
(
jsEntrypointSourceMapExtension
);
await
_copyIfExists
(
jsSourceMapId
,
scratchSpace
,
buildStep
);
}
else
{
log
.
severe
(
result
.
output
);
}
}
Future
<
void
>
_copyIfExists
(
AssetId
id
,
ScratchSpace
scratchSpace
,
AssetWriter
writer
)
async
{
final
File
file
=
scratchSpace
.
fileFor
(
id
);
if
(
file
.
existsSync
())
{
await
scratchSpace
.
copyOutput
(
id
,
writer
);
}
}
/// Creates a `.packages` file unique to this entrypoint at the root of the
/// scratch space and returns it's filename.
///
/// Since mulitple invocations of Dart2Js will share a scratch space and we only
/// know the set of packages involved the current entrypoint we can't construct
/// a `.packages` file that will work for all invocations of Dart2Js so a unique
/// file is created for every entrypoint that is run.
///
/// The filename is based off the MD5 hash of the asset path so that files are
/// unique regarless of situations like `web/foo/bar.dart` vs
/// `web/foo-bar.dart`.
String
_createPackageFile
(
Iterable
<
AssetId
>
inputSources
,
BuildStep
buildStep
,
ScratchSpace
scratchSpace
)
{
final
Uri
inputUri
=
buildStep
.
inputId
.
uri
;
final
String
packageFileName
=
'.package-
${md5.convert(inputUri.toString().codeUnits)}
'
;
final
File
packagesFile
=
scratchSpace
.
fileFor
(
AssetId
(
buildStep
.
inputId
.
package
,
packageFileName
));
final
Set
<
String
>
packageNames
=
inputSources
.
map
((
AssetId
s
)
=>
s
.
package
).
toSet
();
final
String
packagesFileContent
=
packageNames
.
map
((
String
name
)
=>
'
$name
:packages/
$name
/'
).
join
(
'
\n
'
);
packagesFile
.
writeAsStringSync
(
'# Generated for
$inputUri
\n
$packagesFileContent
'
);
return
packageFileName
;
}
/// Returns whether or not [dartId] is an app entrypoint (basically, whether
/// or not it has a `main` function).
Future<bool> _isAppEntryPoint(AssetId dartId, AssetReader reader) async {
...
...
packages/flutter_tools/lib/src/build_runner/resident_web_runner.dart
View file @
ccc3dd96
...
...
@@ -6,6 +6,7 @@ import 'dart:async';
import
'package:meta/meta.dart'
;
import
'package:vm_service/vm_service.dart'
as
vmservice
;
import
'package:webkit_inspection_protocol/webkit_inspection_protocol.dart'
;
import
'../application_package.dart'
;
import
'../base/common.dart'
;
...
...
@@ -20,6 +21,7 @@ import '../globals.dart';
import
'../project.dart'
;
import
'../reporting/reporting.dart'
;
import
'../resident_runner.dart'
;
import
'../web/chrome.dart'
;
import
'../web/web_device.dart'
;
import
'../web/web_runner.dart'
;
import
'web_fs.dart'
;
...
...
@@ -170,7 +172,7 @@ class ResidentWebRunner extends ResidentRunner {
initializePlatform:
debuggingOptions
.
initializePlatform
,
hostname:
debuggingOptions
.
hostname
,
port:
debuggingOptions
.
port
,
skipDwds:
device
is
WebServerDevice
,
skipDwds:
device
is
WebServerDevice
||
!
debuggingOptions
.
buildInfo
.
isDebug
,
);
// When connecting to a browser, update the message with a seemsSlow notification
// to handle the case where we fail to connect.
...
...
@@ -291,6 +293,21 @@ class ResidentWebRunner extends ResidentRunner {
).
send
();
}
}
// Allows browser refresh hot restart on non-debug builds.
if
(
device
is
ChromeDevice
&&
debuggingOptions
.
browserLaunch
)
{
try
{
final
Chrome
chrome
=
await
ChromeLauncher
.
connectedInstance
;
final
ChromeTab
chromeTab
=
await
chrome
.
chromeConnection
.
getTab
((
ChromeTab
chromeTab
)
{
return
chromeTab
.
url
.
contains
(
debuggingOptions
.
hostname
);
});
final
WipConnection
wipConnection
=
await
chromeTab
.
connect
();
await
wipConnection
.
sendCommand
(
'Page.reload'
);
status
.
stop
();
return
OperationResult
.
ok
;
}
catch
(
err
)
{
// Ignore error and continue with posted message;
}
}
status
.
stop
();
printStatus
(
'Recompile complete. Page requires refresh.'
);
return
OperationResult
.
ok
;
...
...
packages/flutter_tools/lib/src/build_runner/web_fs.dart
View file @
ccc3dd96
...
...
@@ -35,6 +35,7 @@ import '../platform_plugins.dart';
import
'../plugins.dart'
;
import
'../project.dart'
;
import
'../web/chrome.dart'
;
import
'../web/compile.dart'
;
/// The name of the built web project.
const
String
kBuildTargetName
=
'web'
;
...
...
@@ -89,6 +90,11 @@ class WebFs {
this
.
_dwds
,
this
.
uri
,
this
.
_assetServer
,
this
.
_useBuildRunner
,
this
.
_flutterProject
,
this
.
_target
,
this
.
_buildInfo
,
this
.
_initializePlatform
,
);
/// The server uri.
...
...
@@ -98,12 +104,17 @@ class WebFs {
final
Dwds
_dwds
;
final
BuildDaemonClient
_client
;
final
AssetServer
_assetServer
;
final
bool
_useBuildRunner
;
final
FlutterProject
_flutterProject
;
final
String
_target
;
final
BuildInfo
_buildInfo
;
final
bool
_initializePlatform
;
StreamSubscription
<
void
>
_connectedApps
;
static
const
String
_kHostName
=
'localhost'
;
Future
<
void
>
stop
()
async
{
await
_client
.
close
();
await
_client
?
.
close
();
await
_dwds
?.
stop
();
await
_server
.
close
(
force:
true
);
await
_connectedApps
?.
cancel
();
...
...
@@ -132,6 +143,10 @@ class WebFs {
/// Recompile the web application and return whether this was successful.
Future
<
bool
>
recompile
()
async
{
if
(!
_useBuildRunner
)
{
await
buildWeb
(
_flutterProject
,
_target
,
_buildInfo
,
_initializePlatform
);
return
true
;
}
_client
.
startBuild
();
await
for
(
BuildResults
results
in
_client
.
buildResults
)
{
final
BuildResult
result
=
results
.
results
.
firstWhere
((
BuildResult
result
)
{
...
...
@@ -161,39 +176,7 @@ class WebFs {
if
(!
flutterProject
.
dartTool
.
existsSync
())
{
flutterProject
.
dartTool
.
createSync
(
recursive:
true
);
}
final
bool
hasWebPlugins
=
findPlugins
(
flutterProject
)
.
any
((
Plugin
p
)
=>
p
.
platforms
.
containsKey
(
WebPlugin
.
kConfigKey
));
// Start the build daemon and run an initial build.
final
Completer
<
bool
>
inititalBuild
=
Completer
<
bool
>();
final
BuildDaemonClient
client
=
await
buildDaemonCreator
.
startBuildDaemon
(
fs
.
currentDirectory
.
path
,
release:
buildInfo
.
isRelease
,
profile:
buildInfo
.
isProfile
,
hasPlugins:
hasWebPlugins
,
initializePlatform:
initializePlatform
,
);
client
.
startBuild
();
// Only provide relevant build results
final
Stream
<
BuildResult
>
filteredBuildResults
=
client
.
buildResults
.
asyncMap
<
BuildResult
>((
BuildResults
results
)
{
return
results
.
results
.
firstWhere
((
BuildResult
result
)
=>
result
.
target
==
kBuildTargetName
);
});
final
StreamSubscription
<
void
>
firstBuild
=
client
.
buildResults
.
listen
((
BuildResults
buildResults
)
{
if
(
inititalBuild
.
isCompleted
)
{
return
;
}
final
BuildResult
result
=
buildResults
.
results
.
firstWhere
((
BuildResult
result
)
{
return
result
.
target
==
kBuildTargetName
;
});
if
(
result
.
status
==
BuildStatus
.
failed
)
{
inititalBuild
.
complete
(
false
);
}
if
(
result
.
status
==
BuildStatus
.
succeeded
)
{
inititalBuild
.
complete
(
true
);
}
});
final
int
daemonAssetPort
=
buildDaemonCreator
.
assetServerPort
(
fs
.
currentDirectory
);
final
Completer
<
bool
>
firstBuildCompleter
=
Completer
<
bool
>();
// Initialize the asset bundle.
final
AssetBundle
assetBundle
=
AssetBundleFactory
.
instance
.
createBundle
();
...
...
@@ -201,7 +184,7 @@ class WebFs {
await
writeBundle
(
fs
.
directory
(
getAssetBuildDirectory
()),
assetBundle
.
entries
);
final
String
targetBaseName
=
fs
.
path
.
withoutExtension
(
target
).
replaceFirst
(
'lib
${fs.path.separator}
'
,
''
);
.
withoutExtension
(
target
).
replaceFirst
(
'lib
${fs.path.separator}
'
,
''
);
final
Map
<
String
,
String
>
mappedUrls
=
<
String
,
String
>{
'main.dart.js'
:
'packages/
${flutterProject.manifest.appName}
/'
'
${targetBaseName}
_web_entrypoint.dart.js'
,
...
...
@@ -236,29 +219,78 @@ class WebFs {
}
};
});
Handler
handler
;
Dwds
dwds
;
if
(!
skipDwds
)
{
dwds
=
await
dwdsFactory
(
hostname:
hostname
??
_kHostName
,
applicationPort:
hostPort
,
applicationTarget:
kBuildTargetName
,
assetServerPort:
daemonAssetPort
,
buildResults:
filteredBuildResults
,
chromeConnection:
()
async
{
return
(
await
ChromeLauncher
.
connectedInstance
).
chromeConnection
;
},
reloadConfiguration:
ReloadConfiguration
.
none
,
serveDevTools:
true
,
verbose:
false
,
enableDebugExtension:
true
,
logWriter:
(
dynamic
level
,
String
message
)
=>
printTrace
(
message
),
);
handler
=
pipeline
.
addHandler
(
dwds
.
handler
);
BuildDaemonClient
client
;
StreamSubscription
<
void
>
firstBuild
;
if
(
buildInfo
.
isDebug
)
{
final
bool
hasWebPlugins
=
findPlugins
(
flutterProject
)
.
any
((
Plugin
p
)
=>
p
.
platforms
.
containsKey
(
WebPlugin
.
kConfigKey
));
// Start the build daemon and run an initial build.
client
=
await
buildDaemonCreator
.
startBuildDaemon
(
fs
.
currentDirectory
.
path
,
release:
buildInfo
.
isRelease
,
profile:
buildInfo
.
isProfile
,
hasPlugins:
hasWebPlugins
,
initializePlatform:
initializePlatform
,
);
client
.
startBuild
();
// Only provide relevant build results
final
Stream
<
BuildResult
>
filteredBuildResults
=
client
.
buildResults
.
asyncMap
<
BuildResult
>((
BuildResults
results
)
{
return
results
.
results
.
firstWhere
((
BuildResult
result
)
=>
result
.
target
==
kBuildTargetName
);
});
// Start the build daemon and run an initial build.
firstBuild
=
client
.
buildResults
.
listen
((
BuildResults
buildResults
)
{
if
(
firstBuildCompleter
.
isCompleted
)
{
return
;
}
final
BuildResult
result
=
buildResults
.
results
.
firstWhere
((
BuildResult
result
)
{
return
result
.
target
==
kBuildTargetName
;
});
if
(
result
.
status
==
BuildStatus
.
failed
)
{
firstBuildCompleter
.
complete
(
false
);
}
if
(
result
.
status
==
BuildStatus
.
succeeded
)
{
firstBuildCompleter
.
complete
(
true
);
}
});
final
int
daemonAssetPort
=
buildDaemonCreator
.
assetServerPort
(
fs
.
currentDirectory
);
// Initialize the asset bundle.
final
AssetBundle
assetBundle
=
AssetBundleFactory
.
instance
.
createBundle
();
await
assetBundle
.
build
();
await
writeBundle
(
fs
.
directory
(
getAssetBuildDirectory
()),
assetBundle
.
entries
);
if
(!
skipDwds
)
{
dwds
=
await
dwdsFactory
(
hostname:
hostname
??
_kHostName
,
applicationPort:
hostPort
,
applicationTarget:
kBuildTargetName
,
assetServerPort:
daemonAssetPort
,
buildResults:
filteredBuildResults
,
chromeConnection:
()
async
{
return
(
await
ChromeLauncher
.
connectedInstance
).
chromeConnection
;
},
reloadConfiguration:
ReloadConfiguration
.
none
,
serveDevTools:
true
,
verbose:
false
,
enableDebugExtension:
true
,
logWriter:
(
dynamic
level
,
String
message
)
=>
printTrace
(
message
),
);
handler
=
pipeline
.
addHandler
(
dwds
.
handler
);
}
else
{
handler
=
pipeline
.
addHandler
(
proxyHandler
(
'http://localhost:
$daemonAssetPort
/web/'
));
}
}
else
{
handler
=
pipeline
.
addHandler
(
proxyHandler
(
'http://localhost:
$daemonAssetPort
/web/'
));
await
buildWeb
(
flutterProject
,
target
,
buildInfo
,
initializePlatform
);
firstBuildCompleter
.
complete
(
true
);
}
final
AssetServer
assetServer
=
AssetServer
(
flutterProject
,
targetBaseName
);
final
AssetServer
assetServer
=
buildInfo
.
isDebug
?
DebugAssetServer
(
flutterProject
,
targetBaseName
)
:
ReleaseAssetServer
();
Cascade
cascade
=
Cascade
();
cascade
=
cascade
.
add
(
handler
);
cascade
=
cascade
.
add
(
assetServer
.
handle
);
...
...
@@ -270,23 +302,65 @@ class WebFs {
dwds
,
'http://
$_kHostName
:
$hostPort
/'
,
assetServer
,
buildInfo
.
isDebug
,
flutterProject
,
target
,
buildInfo
,
initializePlatform
,
);
if
(!
await
inititalBuild
.
future
)
{
if
(!
await
firstBuildCompleter
.
future
)
{
throw
Exception
(
'Failed to compile for the web.'
);
}
await
firstBuild
.
cancel
();
await
firstBuild
?
.
cancel
();
return
webFS
;
}
}
class
AssetServer
{
AssetServer
(
this
.
flutterProject
,
this
.
targetBaseName
);
abstract
class
AssetServer
{
Future
<
Response
>
handle
(
Request
request
);
void
dispose
()
{}
}
class
ReleaseAssetServer
extends
AssetServer
{
@override
Future
<
Response
>
handle
(
Request
request
)
async
{
final
Uri
artifactUri
=
fs
.
directory
(
getWebBuildDirectory
()).
uri
.
resolveUri
(
request
.
url
);
final
File
file
=
fs
.
file
(
artifactUri
);
if
(
file
.
existsSync
())
{
return
Response
.
ok
(
file
.
readAsBytesSync
(),
headers:
<
String
,
String
>{
'Content-Type'
:
_guessExtension
(
file
),
});
}
if
(
request
.
url
.
path
==
''
)
{
final
File
file
=
fs
.
file
(
fs
.
path
.
join
(
getWebBuildDirectory
(),
'index.html'
));
return
Response
.
ok
(
file
.
readAsBytesSync
(),
headers:
<
String
,
String
>{
'Content-Type'
:
_guessExtension
(
file
),
});
}
return
Response
.
notFound
(
''
);
}
String
_guessExtension
(
File
file
)
{
switch
(
fs
.
path
.
extension
(
file
.
path
))
{
case
'.js'
:
return
'text/javascript'
;
case
'.html'
:
return
'text/html'
;
}
return
'text'
;
}
}
class
DebugAssetServer
extends
AssetServer
{
DebugAssetServer
(
this
.
flutterProject
,
this
.
targetBaseName
);
final
FlutterProject
flutterProject
;
final
String
targetBaseName
;
final
PackageMap
packageMap
=
PackageMap
(
PackageMap
.
globalPackagesPath
);
Directory
partFiles
;
@override
Future
<
Response
>
handle
(
Request
request
)
async
{
if
(
request
.
url
.
path
.
endsWith
(
'.html'
))
{
final
Uri
htmlUri
=
flutterProject
.
web
.
directory
.
uri
.
resolveUri
(
request
.
url
);
...
...
@@ -411,6 +485,7 @@ class AssetServer {
return
Response
.
notFound
(
''
);
}
@override
void
dispose
()
{
partFiles
?.
deleteSync
(
recursive:
true
);
}
...
...
packages/flutter_tools/lib/src/build_system/build_system.dart
View file @
ccc3dd96
...
...
@@ -25,6 +25,13 @@ export 'source.dart';
/// The [BuildSystem] instance.
BuildSystem
get
buildSystem
=>
context
.
get
<
BuildSystem
>();
/// A reasonable amount of files to open at the same time.
///
/// This number is somewhat arbitrary - it is difficult to detect whether
/// or not we'll run out of file descriptiors when using async dart:io
/// APIs.
const
int
kMaxOpenFiles
=
64
;
/// Configuration for the build system itself.
class
BuildSystemConfig
{
/// Create a new [BuildSystemConfig].
...
...
packages/flutter_tools/lib/src/build_system/file_hash_store.dart
View file @
ccc3dd96
...
...
@@ -7,6 +7,7 @@ import 'dart:collection';
import
'dart:typed_data'
;
import
'package:crypto/crypto.dart'
;
import
'package:pool/pool.dart'
;
import
'../base/file_system.dart'
;
import
'../convert.dart'
;
...
...
@@ -69,13 +70,6 @@ class FileHash {
///
/// The format of the file store is subject to change and not part of its API.
///
/// To regenerate the protobuf entries used to construct the cache:
/// 1. If not already installed, https://developers.google.com/protocol-buffers/docs/downloads
/// 2. pub global active `protoc-gen-dart`
/// 3. protoc -I=lib/src/build_system/ --dart_out=lib/src/build_system/ lib/src/build_system/filecache.proto
/// 4. Add licenses headers to the newly generated file and check-in.
///
/// See also: https://developers.google.com/protocol-buffers/docs/darttutorial
// TODO(jonahwilliams): find a better way to clear out old entries, perhaps
// track the last access or modification date?
class
FileHashStore
{
...
...
@@ -141,24 +135,27 @@ class FileHashStore {
/// Computes a hash of the provided files and returns a list of entities
/// that were dirty.
// TODO(jonahwilliams): compare hash performance with md5 tool on macOS and
// linux and certutil on Windows, as well as dividing up computation across
// isolates. This also related to the current performance issue with checking
// APKs before installing them on device.
Future
<
List
<
File
>>
hashFiles
(
List
<
File
>
files
)
async
{
final
List
<
File
>
dirty
=
<
File
>[];
for
(
File
file
in
files
)
{
final
String
absolutePath
=
file
.
resolveSymbolicLinksSync
();
final
String
previousHash
=
previousHashes
[
absolutePath
];
final
List
<
int
>
bytes
=
file
.
readAsBytesSync
();
final
String
currentHash
=
md5
.
convert
(
bytes
).
toString
();
await
Future
.
wait
(<
Future
<
void
>>[
for
(
File
file
in
files
)
_hashFile
(
file
,
dirty
,
Pool
(
kMaxOpenFiles
))]);
return
dirty
;
}
Future
<
void
>
_hashFile
(
File
file
,
List
<
File
>
dirty
,
Pool
pool
)
async
{
final
PoolResource
resource
=
await
pool
.
request
();
try
{
final
String
absolutePath
=
file
.
path
;
final
String
previousHash
=
previousHashes
[
absolutePath
];
final
Digest
digest
=
md5
.
convert
(
await
file
.
readAsBytes
());
final
String
currentHash
=
digest
.
toString
();
if
(
currentHash
!=
previousHash
)
{
dirty
.
add
(
file
);
}
currentHashes
[
absolutePath
]
=
currentHash
;
}
finally
{
resource
.
release
();
}
return
dirty
;
}
File
get
_cacheFile
=>
environment
.
buildDir
.
childFile
(
_kFileCache
);
...
...
packages/flutter_tools/lib/src/build_system/targets/assets.dart
View file @
ccc3dd96
...
...
@@ -50,7 +50,9 @@ class AssetBehavior extends SourceBehavior {
/// A specific asset behavior for building bundles.
class
AssetOutputBehavior
extends
SourceBehavior
{
const
AssetOutputBehavior
();
const
AssetOutputBehavior
([
this
.
_pathSuffix
=
''
]);
final
String
_pathSuffix
;
@override
List
<
File
>
inputs
(
Environment
environment
)
{
...
...
@@ -64,7 +66,7 @@ class AssetOutputBehavior extends SourceBehavior {
final
List
<
File
>
results
=
<
File
>[];
final
Iterable
<
DevFSFileContent
>
files
=
assetBundle
.
entries
.
values
.
whereType
<
DevFSFileContent
>();
for
(
DevFSFileContent
devFsContent
in
files
)
{
results
.
add
(
fs
.
file
(
devFsContent
.
file
.
path
));
results
.
add
(
fs
.
file
(
fs
.
path
.
join
(
_pathSuffix
,
devFsContent
.
file
.
path
)
));
}
return
results
;
}
...
...
@@ -78,7 +80,7 @@ class AssetOutputBehavior extends SourceBehavior {
);
final
List
<
File
>
results
=
<
File
>[];
for
(
String
key
in
assetBundle
.
entries
.
keys
)
{
final
File
file
=
fs
.
file
(
fs
.
path
.
join
(
environment
.
outputDir
.
path
,
key
));
final
File
file
=
fs
.
file
(
fs
.
path
.
join
(
environment
.
outputDir
.
path
,
_pathSuffix
,
key
));
results
.
add
(
file
);
}
return
results
;
...
...
@@ -125,7 +127,7 @@ class CopyAssets extends Target {
packagesPath:
environment
.
projectDir
.
childFile
(
'.packages'
).
path
,
);
// Limit number of open files to avoid running out of file descriptors.
final
Pool
pool
=
Pool
(
64
);
final
Pool
pool
=
Pool
(
kMaxOpenFiles
);
await
Future
.
wait
<
void
>(
assetBundle
.
entries
.
entries
.
map
<
Future
<
void
>>((
MapEntry
<
String
,
DevFSContent
>
entry
)
async
{
final
PoolResource
resource
=
await
pool
.
request
();
...
...
packages/flutter_tools/lib/src/build_system/targets/dart.dart
View file @
ccc3dd96
...
...
@@ -115,23 +115,7 @@ class CopyFlutterBundle extends Target {
final
AssetBundle
assetBundle
=
AssetBundleFactory
.
instance
.
createBundle
();
await
assetBundle
.
build
();
final
Pool
pool
=
Pool
(
64
);
await
Future
.
wait
<
void
>(
assetBundle
.
entries
.
entries
.
map
<
Future
<
void
>>((
MapEntry
<
String
,
DevFSContent
>
entry
)
async
{
final
PoolResource
resource
=
await
pool
.
request
();
try
{
final
File
file
=
fs
.
file
(
fs
.
path
.
join
(
environment
.
outputDir
.
path
,
entry
.
key
));
file
.
parent
.
createSync
(
recursive:
true
);
final
DevFSContent
content
=
entry
.
value
;
if
(
content
is
DevFSFileContent
&&
content
.
file
is
File
)
{
await
(
content
.
file
as
File
).
copy
(
file
.
path
);
}
else
{
await
file
.
writeAsBytes
(
await
entry
.
value
.
contentsAsBytes
());
}
}
finally
{
resource
.
release
();
}
}));
await
copyAssets
(
assetBundle
,
environment
);
}
@override
...
...
@@ -140,6 +124,28 @@ class CopyFlutterBundle extends Target {
];
}
/// A helper function to copy an [assetBundle] into an [environment]'s output directory,
/// plus an optional [pathSuffix]
Future
<
void
>
copyAssets
(
AssetBundle
assetBundle
,
Environment
environment
,
[
String
pathSuffix
=
''
])
async
{
final
Pool
pool
=
Pool
(
kMaxOpenFiles
);
await
Future
.
wait
<
void
>(
assetBundle
.
entries
.
entries
.
map
<
Future
<
void
>>((
MapEntry
<
String
,
DevFSContent
>
entry
)
async
{
final
PoolResource
resource
=
await
pool
.
request
();
try
{
final
File
file
=
fs
.
file
(
fs
.
path
.
join
(
environment
.
outputDir
.
path
,
pathSuffix
,
entry
.
key
));
file
.
parent
.
createSync
(
recursive:
true
);
final
DevFSContent
content
=
entry
.
value
;
if
(
content
is
DevFSFileContent
&&
content
.
file
is
File
)
{
await
(
content
.
file
as
File
).
copy
(
file
.
path
);
}
else
{
await
file
.
writeAsBytes
(
await
entry
.
value
.
contentsAsBytes
());
}
}
finally
{
resource
.
release
();
}
}));
}
/// Copies the prebuilt flutter bundle for release mode.
class
ReleaseCopyFlutterBundle
extends
CopyFlutterBundle
{
const
ReleaseCopyFlutterBundle
();
...
...
packages/flutter_tools/lib/src/build_system/targets/macos.dart
View file @
ccc3dd96
...
...
@@ -336,7 +336,7 @@ abstract class MacOSBundleFlutterAssets extends Target {
}
// Limit number of open files to avoid running out of file descriptors.
try
{
final
Pool
pool
=
Pool
(
64
);
final
Pool
pool
=
Pool
(
kMaxOpenFiles
);
await
Future
.
wait
<
void
>(
assetBundle
.
entries
.
entries
.
map
<
Future
<
void
>>((
MapEntry
<
String
,
DevFSContent
>
entry
)
async
{
final
PoolResource
resource
=
await
pool
.
request
();
...
...
packages/flutter_tools/lib/src/build_system/targets/web.dart
0 → 100644
View file @
ccc3dd96
// 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
'../../artifacts.dart'
;
import
'../../asset.dart'
;
import
'../../base/file_system.dart'
;
import
'../../base/io.dart'
;
import
'../../base/process_manager.dart'
;
import
'../../build_info.dart'
;
import
'../../dart/package_map.dart'
;
import
'../../globals.dart'
;
import
'../../project.dart'
;
import
'../build_system.dart'
;
import
'assets.dart'
;
import
'dart.dart'
;
/// Whether web builds should call the platform initialization logic.
const
String
kInitializePlatform
=
'InitializePlatform'
;
/// Whether the application has web plugins.
const
String
kHasWebPlugins
=
'HasWebPlugins'
;
/// An override for the dart2js build mode.
///
/// Valid values are O1 (lowest, profile default) to O4 (highest, release default).
const
String
kDart2jsOptimization
=
'Dart2jsOptimization'
;
/// Generates an entrypoint for a web target.
class
WebEntrypointTarget
extends
Target
{
const
WebEntrypointTarget
();
@override
String
get
name
=>
'web_entrypoint'
;
@override
List
<
Target
>
get
dependencies
=>
const
<
Target
>[];
@override
List
<
Source
>
get
inputs
=>
const
<
Source
>[
Source
.
pattern
(
'{FLUTTER_ROOT}/packages/flutter_tools/lib/src/build_system/targets/web.dart'
),
];
@override
List
<
Source
>
get
outputs
=>
const
<
Source
>[
Source
.
pattern
(
'{BUILD_DIR}/main.dart'
),
];
@override
Future
<
void
>
build
(
Environment
environment
)
async
{
final
String
targetFile
=
environment
.
defines
[
kTargetFile
];
final
bool
shouldInitializePlatform
=
environment
.
defines
[
kInitializePlatform
]
==
'true'
;
final
bool
hasPlugins
=
environment
.
defines
[
kHasWebPlugins
]
==
'true'
;
final
String
import
=
fs
.
file
(
fs
.
path
.
absolute
(
targetFile
)).
uri
.
toString
();
String
contents
;
if
(
hasPlugins
)
{
contents
=
'''
import '
dart:
ui
' as ui;
import '
package:
flutter_web_plugins
/
flutter_web_plugins
.
dart
';
import '
generated_plugin_registrant
.
dart
';
import "
$import
" as entrypoint;
Future<void> main() async {
registerPlugins(webPluginRegistry);
if (
$shouldInitializePlatform
) {
await ui.webOnlyInitializePlatform();
}
entrypoint.main();
}
'''
;
}
else
{
contents
=
'''
import '
dart:
ui
' as ui;
import "
$import
" as entrypoint;
Future<void> main() async {
if (
$shouldInitializePlatform
) {
await ui.webOnlyInitializePlatform();
}
entrypoint.main();
}
'''
;
}
environment
.
buildDir
.
childFile
(
'main.dart'
)
..
writeAsStringSync
(
contents
);
}
}
/// Compiles a web entrypoint with dart2js.
class
Dart2JSTarget
extends
Target
{
const
Dart2JSTarget
();
@override
String
get
name
=>
'dart2js'
;
@override
List
<
Target
>
get
dependencies
=>
const
<
Target
>[
WebEntrypointTarget
()
];
@override
List
<
Source
>
get
inputs
=>
const
<
Source
>[
Source
.
pattern
(
'{FLUTTER_ROOT}/packages/flutter_tools/lib/src/build_system/targets/web.dart'
),
Source
.
artifact
(
Artifact
.
flutterWebSdk
),
Source
.
artifact
(
Artifact
.
dart2jsSnapshot
),
Source
.
artifact
(
Artifact
.
engineDartBinary
),
Source
.
artifact
(
Artifact
.
engineDartSdkPath
),
Source
.
pattern
(
'{BUILD_DIR}/main.dart'
),
Source
.
pattern
(
'{PROJECT_DIR}/.packages'
),
Source
.
function
(
listDartSources
),
// <- every dart file under {PROJECT_DIR}/lib and in .packages
];
@override
List
<
Source
>
get
outputs
=>
const
<
Source
>[
Source
.
pattern
(
'{BUILD_DIR}/main.dart.js'
),
];
@override
Future
<
void
>
build
(
Environment
environment
)
async
{
final
String
dart2jsOptimization
=
environment
.
defines
[
kDart2jsOptimization
];
final
BuildMode
buildMode
=
getBuildModeForName
(
environment
.
defines
[
kBuildMode
]);
final
String
specPath
=
fs
.
path
.
join
(
artifacts
.
getArtifactPath
(
Artifact
.
flutterWebSdk
),
'libraries.json'
);
final
String
packageFile
=
FlutterProject
.
fromDirectory
(
environment
.
projectDir
).
hasBuilders
?
PackageMap
.
globalGeneratedPackagesPath
:
PackageMap
.
globalPackagesPath
;
final
ProcessResult
result
=
await
processManager
.
run
(<
String
>[
artifacts
.
getArtifactPath
(
Artifact
.
engineDartBinary
),
artifacts
.
getArtifactPath
(
Artifact
.
dart2jsSnapshot
),
'--libraries-spec=
$specPath
'
,
if
(
dart2jsOptimization
!=
null
)
'-
$dart2jsOptimization
'
else
if
(
buildMode
==
BuildMode
.
profile
)
'-O1'
else
'-O4'
,
'-o'
,
environment
.
buildDir
.
childFile
(
'main.dart.js'
).
path
,
'--packages=
$packageFile
'
,
if
(
buildMode
==
BuildMode
.
profile
)
'-Ddart.vm.profile=true'
else
'-Ddart.vm.product=true'
,
environment
.
buildDir
.
childFile
(
'main.dart'
).
path
,
]);
if
(
result
.
exitCode
!=
0
)
{
throw
Exception
(
result
.
stdout
+
result
.
stderr
);
}
}
}
/// Unpacks the dart2js compilation to a given output directory
class
WebReleaseBundle
extends
Target
{
const
WebReleaseBundle
();
@override
String
get
name
=>
'web_release_bundle'
;
@override
List
<
Target
>
get
dependencies
=>
const
<
Target
>[
Dart2JSTarget
(),
];
@override
List
<
Source
>
get
inputs
=>
const
<
Source
>[
Source
.
pattern
(
'{BUILD_DIR}/main.dart.js'
),
Source
.
pattern
(
'{FLUTTER_ROOT}/packages/flutter_tools/lib/src/build_system/targets/web.dart'
),
Source
.
behavior
(
AssetOutputBehavior
(
'assets'
)),
Source
.
pattern
(
'{PROJECT_DIR}/web/index.html'
),
];
@override
List
<
Source
>
get
outputs
=>
const
<
Source
>[
Source
.
pattern
(
'{OUTPUT_DIR}/main.dart.js'
),
Source
.
pattern
(
'{OUTPUT_DIR}/assets/AssetManifest.json'
),
Source
.
pattern
(
'{OUTPUT_DIR}/assets/FontManifest.json'
),
Source
.
pattern
(
'{OUTPUT_DIR}/assets/LICENSE'
),
Source
.
pattern
(
'{OUTPUT_DIR}/index.html'
),
Source
.
behavior
(
AssetOutputBehavior
(
'assets'
))
];
@override
Future
<
void
>
build
(
Environment
environment
)
async
{
for
(
File
outputFile
in
environment
.
buildDir
.
listSync
(
recursive:
true
).
whereType
<
File
>())
{
if
(!
fs
.
path
.
basename
(
outputFile
.
path
).
contains
(
'main.dart.js'
))
{
continue
;
}
outputFile
.
copySync
(
environment
.
outputDir
.
childFile
(
fs
.
path
.
basename
(
outputFile
.
path
)).
path
);
}
environment
.
projectDir
.
childDirectory
(
'web'
)
.
childFile
(
'index.html'
)
.
copySync
(
fs
.
path
.
join
(
environment
.
outputDir
.
path
,
'index.html'
));
final
AssetBundle
assetBundle
=
AssetBundleFactory
.
instance
.
createBundle
();
await
assetBundle
.
build
();
await
copyAssets
(
assetBundle
,
environment
,
'assets'
);
}
}
packages/flutter_tools/lib/src/commands/assemble.dart
View file @
ccc3dd96
...
...
@@ -12,6 +12,7 @@ import '../build_system/targets/dart.dart';
import
'../build_system/targets/ios.dart'
;
import
'../build_system/targets/linux.dart'
;
import
'../build_system/targets/macos.dart'
;
import
'../build_system/targets/web.dart'
;
import
'../build_system/targets/windows.dart'
;
import
'../globals.dart'
;
import
'../project.dart'
;
...
...
@@ -31,6 +32,7 @@ const List<Target> _kDefaultTargets = <Target>[
DebugMacOSBundleFlutterAssets
(),
ProfileMacOSBundleFlutterAssets
(),
ReleaseMacOSBundleFlutterAssets
(),
WebReleaseBundle
(),
];
/// Assemble provides a low level API to interact with the flutter tool build
...
...
packages/flutter_tools/lib/src/web/compile.dart
View file @
ccc3dd96
...
...
@@ -2,17 +2,19 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import
'package:archive/archive.dart'
;
import
'package:meta/meta.dart'
;
import
'../asset.dart'
;
import
'../base/common.dart'
;
import
'../base/context.dart'
;
import
'../base/file_system.dart'
;
import
'../base/logger.dart'
;
import
'../build_info.dart'
;
import
'../bundle.dart'
;
import
'../build_system/build_system.dart'
;
import
'../build_system/targets/dart.dart'
;
import
'../build_system/targets/web.dart'
;
import
'../globals.dart'
;
import
'../platform_plugins.dart'
;
import
'../plugins.dart'
;
import
'../project.dart'
;
import
'../reporting/reporting.dart'
;
...
...
@@ -23,64 +25,32 @@ Future<void> buildWeb(FlutterProject flutterProject, String target, BuildInfo bu
if
(!
flutterProject
.
web
.
existsSync
())
{
throwToolExit
(
'Missing index.html.'
);
}
final
bool
hasWebPlugins
=
findPlugins
(
flutterProject
)
.
any
((
Plugin
p
)
=>
p
.
platforms
.
containsKey
(
WebPlugin
.
kConfigKey
));
final
Status
status
=
logger
.
startProgress
(
'Compiling
$target
for the Web...'
,
timeout:
null
);
final
Stopwatch
sw
=
Stopwatch
()..
start
();
final
Directory
outputDir
=
fs
.
directory
(
getWebBuildDirectory
())
..
createSync
(
recursive:
true
);
bool
result
;
try
{
result
=
await
webCompilationProxy
.
initialize
(
projectDirectory:
FlutterProject
.
current
().
directory
,
mode:
buildInfo
.
mode
,
projectName:
flutterProject
.
manifest
.
appName
,
initializePlatform:
initializePlatform
,
);
if
(
result
)
{
// Places assets adjacent to the web stuff.
final
AssetBundle
assetBundle
=
AssetBundleFactory
.
instance
.
createBundle
();
await
assetBundle
.
build
();
await
writeBundle
(
fs
.
directory
(
fs
.
path
.
join
(
outputDir
.
path
,
'assets'
)),
assetBundle
.
entries
);
// Copy results to output directory.
final
String
outputPath
=
fs
.
path
.
join
(
flutterProject
.
dartTool
.
path
,
'build'
,
'flutter_web'
,
flutterProject
.
manifest
.
appName
,
'
${fs.path.withoutExtension(target)}
_web_entrypoint.dart.js'
,
);
// Check for deferred import outputs.
final
File
dart2jsArchive
=
fs
.
file
(
fs
.
path
.
join
(
flutterProject
.
dartTool
.
path
,
'build'
,
'flutter_web'
,
'
${flutterProject.manifest.appName}
'
,
'
${fs.path.withoutExtension(target)}
_web_entrypoint.dart.js.tar.gz'
),
);
fs
.
file
(
outputPath
).
copySync
(
fs
.
path
.
join
(
outputDir
.
path
,
'main.dart.js'
));
fs
.
file
(
'
$outputPath
.map'
).
copySync
(
fs
.
path
.
join
(
outputDir
.
path
,
'main.dart.js.map'
));
flutterProject
.
web
.
indexFile
.
copySync
(
fs
.
path
.
join
(
outputDir
.
path
,
'index.html'
));
if
(
dart2jsArchive
.
existsSync
())
{
final
Archive
archive
=
TarDecoder
().
decodeBytes
(
dart2jsArchive
.
readAsBytesSync
());
for
(
ArchiveFile
file
in
archive
.
files
)
{
outputDir
.
childFile
(
file
.
name
).
writeAsBytesSync
(
file
.
content
);
}
}
final
BuildResult
result
=
await
const
BuildSystem
().
build
(
const
WebReleaseBundle
(),
Environment
(
outputDir:
fs
.
directory
(
getWebBuildDirectory
()),
projectDir:
fs
.
currentDirectory
,
buildDir:
flutterProject
.
directory
.
childDirectory
(
'.dart_tool'
)
.
childDirectory
(
'flutter_build'
),
defines:
<
String
,
String
>{
kBuildMode:
getNameForBuildMode
(
buildInfo
.
mode
),
kTargetFile:
target
,
kInitializePlatform:
initializePlatform
.
toString
(),
kHasWebPlugins:
hasWebPlugins
.
toString
(),
},
));
if
(!
result
.
success
)
{
for
(
ExceptionMeasurement
measurement
in
result
.
exceptions
.
values
)
{
printError
(
measurement
.
stackTrace
.
toString
());
printError
(
measurement
.
exception
.
toString
());
}
}
catch
(
err
)
{
printError
(
err
.
toString
());
result
=
false
;
}
finally
{
status
.
stop
();
}
if
(
result
==
false
)
{
throwToolExit
(
'Failed to compile
$target
for the Web.'
);
}
String
buildName
=
'ddc'
;
if
(
buildInfo
.
isRelease
)
{
buildName
=
'dart2js'
;
throwToolExit
(
'Failed to compile application for the Web.'
);
}
flutterUsage
.
sendTiming
(
'build'
,
buildName
,
Duration
(
milliseconds:
sw
.
elapsedMilliseconds
));
status
.
stop
();
flutterUsage
.
sendTiming
(
'build'
,
'dart2js'
,
Duration
(
milliseconds:
sw
.
elapsedMilliseconds
));
}
/// An indirection on web compilation.
...
...
packages/flutter_tools/test/general.shard/build_system/filecache_test.dart
View file @
ccc3dd96
...
...
@@ -39,37 +39,37 @@ void main() {
expect
(
fileStorage
.
version
,
2
);
}));
test
(
'saves and restores to file cache'
,
()
=>
testbed
.
run
(()
{
test
(
'saves and restores to file cache'
,
()
=>
testbed
.
run
(()
async
{
final
File
file
=
fs
.
file
(
'foo.dart'
)
..
createSync
()
..
writeAsStringSync
(
'hello'
);
final
FileHashStore
fileCache
=
FileHashStore
(
environment
);
fileCache
.
initialize
();
fileCache
.
hashFiles
(<
File
>[
file
]);
await
fileCache
.
hashFiles
(<
File
>[
file
]);
fileCache
.
persist
();
final
String
currentHash
=
fileCache
.
currentHashes
[
file
.
resolveSymbolicLinksSync
()
];
final
String
currentHash
=
fileCache
.
currentHashes
[
file
.
path
];
final
List
<
int
>
buffer
=
fs
.
file
(
fs
.
path
.
join
(
environment
.
buildDir
.
path
,
'.filecache'
))
.
readAsBytesSync
();
FileStorage
fileStorage
=
FileStorage
.
fromBuffer
(
buffer
);
expect
(
fileStorage
.
files
.
single
.
hash
,
currentHash
);
expect
(
fileStorage
.
files
.
single
.
path
,
file
.
resolveSymbolicLinksSync
()
);
expect
(
fileStorage
.
files
.
single
.
path
,
file
.
path
);
final
FileHashStore
newFileCache
=
FileHashStore
(
environment
);
newFileCache
.
initialize
();
expect
(
newFileCache
.
currentHashes
,
isEmpty
);
expect
(
newFileCache
.
previousHashes
[
fs
.
path
.
absolute
(
'foo.dart'
)
],
currentHash
);
expect
(
newFileCache
.
previousHashes
[
'foo.dart'
],
currentHash
);
newFileCache
.
persist
();
// Still persisted correctly.
fileStorage
=
FileStorage
.
fromBuffer
(
buffer
);
expect
(
fileStorage
.
files
.
single
.
hash
,
currentHash
);
expect
(
fileStorage
.
files
.
single
.
path
,
file
.
resolveSymbolicLinksSync
()
);
expect
(
fileStorage
.
files
.
single
.
path
,
file
.
path
);
}));
test
(
'handles persisting with a missing build directory'
,
()
=>
testbed
.
run
(()
{
test
(
'handles persisting with a missing build directory'
,
()
=>
testbed
.
run
(()
async
{
final
File
file
=
fs
.
file
(
'foo.dart'
)
..
createSync
()
..
writeAsStringSync
(
'hello'
);
...
...
@@ -77,7 +77,7 @@ void main() {
fileCache
.
initialize
();
environment
.
buildDir
.
deleteSync
(
recursive:
true
);
fileCache
.
hashFiles
(<
File
>[
file
]);
await
fileCache
.
hashFiles
(<
File
>[
file
]);
// Does not throw.
fileCache
.
persist
();
}));
...
...
packages/flutter_tools/test/general.shard/build_system/targets/web_test.dart
0 → 100644
View file @
ccc3dd96
// 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_tools/src/base/file_system.dart'
;
import
'package:flutter_tools/src/base/platform.dart'
;
import
'package:flutter_tools/src/base/process_manager.dart'
;
import
'package:flutter_tools/src/build_system/build_system.dart'
;
import
'package:flutter_tools/src/build_system/targets/dart.dart'
;
import
'package:flutter_tools/src/build_system/targets/web.dart'
;
import
'package:mockito/mockito.dart'
;
import
'package:process/process.dart'
;
import
'../../../src/common.dart'
;
import
'../../../src/mocks.dart'
;
import
'../../../src/testbed.dart'
;
void
main
(
)
{
Testbed
testbed
;
Environment
environment
;
MockPlatform
mockPlatform
;
MockPlatform
mockWindowsPlatform
;
setUp
(()
{
mockPlatform
=
MockPlatform
();
mockWindowsPlatform
=
MockPlatform
();
when
(
mockPlatform
.
isWindows
).
thenReturn
(
false
);
when
(
mockPlatform
.
isMacOS
).
thenReturn
(
true
);
when
(
mockPlatform
.
isLinux
).
thenReturn
(
false
);
when
(
mockWindowsPlatform
.
isWindows
).
thenReturn
(
true
);
when
(
mockWindowsPlatform
.
isMacOS
).
thenReturn
(
false
);
when
(
mockWindowsPlatform
.
isLinux
).
thenReturn
(
false
);
testbed
=
Testbed
(
setup:
()
{
environment
=
Environment
(
projectDir:
fs
.
currentDirectory
,
outputDir:
fs
.
currentDirectory
,
buildDir:
fs
.
currentDirectory
,
defines:
<
String
,
String
>{
kTargetFile:
fs
.
path
.
join
(
'lib'
,
'main.dart'
),
}
);
environment
.
buildDir
.
createSync
(
recursive:
true
);
},
overrides:
<
Type
,
Generator
>{
Platform:
()
=>
mockPlatform
,
});
});
test
(
'WebEntrypointTarget generates an entrypoint with plugins and init platform'
,
()
=>
testbed
.
run
(()
async
{
environment
.
defines
[
kHasWebPlugins
]
=
'true'
;
environment
.
defines
[
kInitializePlatform
]
=
'true'
;
await
const
WebEntrypointTarget
().
build
(
environment
);
final
String
generated
=
environment
.
buildDir
.
childFile
(
'main.dart'
).
readAsStringSync
();
// Plugins
expect
(
generated
,
contains
(
"import 'generated_plugin_registrant.dart';"
));
expect
(
generated
,
contains
(
'registerPlugins(webPluginRegistry);'
));
// Platform
expect
(
generated
,
contains
(
'if (true) {'
));
// Main
expect
(
generated
,
contains
(
'entrypoint.main();'
));
// Import.
expect
(
generated
,
contains
(
'import "file:///lib/main.dart" as entrypoint;'
));
}));
test
(
'WebEntrypointTarget generates an entrypoint with plugins and init platform on windows'
,
()
=>
testbed
.
run
(()
async
{
environment
.
defines
[
kHasWebPlugins
]
=
'true'
;
environment
.
defines
[
kInitializePlatform
]
=
'true'
;
await
const
WebEntrypointTarget
().
build
(
environment
);
final
String
generated
=
environment
.
buildDir
.
childFile
(
'main.dart'
).
readAsStringSync
();
// Plugins
expect
(
generated
,
contains
(
"import 'generated_plugin_registrant.dart';"
));
expect
(
generated
,
contains
(
'registerPlugins(webPluginRegistry);'
));
// Platform
expect
(
generated
,
contains
(
'if (true) {'
));
// Main
expect
(
generated
,
contains
(
'entrypoint.main();'
));
// Import.
expect
(
generated
,
contains
(
'import "file:///C:/lib/main.dart" as entrypoint;'
));
},
overrides:
<
Type
,
Generator
>{
Platform:
()
=>
mockWindowsPlatform
,
}));
test
(
'WebEntrypointTarget generates an entrypoint without plugins and init platform'
,
()
=>
testbed
.
run
(()
async
{
environment
.
defines
[
kHasWebPlugins
]
=
'false'
;
environment
.
defines
[
kInitializePlatform
]
=
'true'
;
await
const
WebEntrypointTarget
().
build
(
environment
);
final
String
generated
=
environment
.
buildDir
.
childFile
(
'main.dart'
).
readAsStringSync
();
// Plugins
expect
(
generated
,
isNot
(
contains
(
"import 'generated_plugin_registrant.dart';"
)));
expect
(
generated
,
isNot
(
contains
(
'registerPlugins(webPluginRegistry);'
)));
// Platform
expect
(
generated
,
contains
(
'if (true) {'
));
// Main
expect
(
generated
,
contains
(
'entrypoint.main();'
));
}));
test
(
'WebEntrypointTarget generates an entrypoint with plugins and without init platform'
,
()
=>
testbed
.
run
(()
async
{
environment
.
defines
[
kHasWebPlugins
]
=
'true'
;
environment
.
defines
[
kInitializePlatform
]
=
'false'
;
await
const
WebEntrypointTarget
().
build
(
environment
);
final
String
generated
=
environment
.
buildDir
.
childFile
(
'main.dart'
).
readAsStringSync
();
// Plugins
expect
(
generated
,
contains
(
"import 'generated_plugin_registrant.dart';"
));
expect
(
generated
,
contains
(
'registerPlugins(webPluginRegistry);'
));
// Platform
expect
(
generated
,
contains
(
'if (false) {'
));
// Main
expect
(
generated
,
contains
(
'entrypoint.main();'
));
}));
test
(
'WebEntrypointTarget generates an entrypoint without plugins and without init platform'
,
()
=>
testbed
.
run
(()
async
{
environment
.
defines
[
kHasWebPlugins
]
=
'false'
;
environment
.
defines
[
kInitializePlatform
]
=
'false'
;
await
const
WebEntrypointTarget
().
build
(
environment
);
final
String
generated
=
environment
.
buildDir
.
childFile
(
'main.dart'
).
readAsStringSync
();
// Plugins
expect
(
generated
,
isNot
(
contains
(
"import 'generated_plugin_registrant.dart';"
)));
expect
(
generated
,
isNot
(
contains
(
'registerPlugins(webPluginRegistry);'
)));
// Platform
expect
(
generated
,
contains
(
'if (false) {'
));
// Main
expect
(
generated
,
contains
(
'entrypoint.main();'
));
}));
test
(
'Dart2JSTarget calls dart2js with expected args in profile mode'
,
()
=>
testbed
.
run
(()
async
{
environment
.
defines
[
kBuildMode
]
=
'profile'
;
when
(
processManager
.
run
(
any
)).
thenAnswer
((
Invocation
invocation
)
async
{
return
FakeProcessResult
(
exitCode:
0
);
});
await
const
Dart2JSTarget
().
build
(
environment
);
final
List
<
String
>
expected
=
<
String
>[
fs
.
path
.
join
(
'bin'
,
'cache'
,
'dart-sdk'
,
'bin'
,
'dart'
),
fs
.
path
.
join
(
'bin'
,
'cache'
,
'dart-sdk'
,
'bin'
,
'snapshots'
,
'dart2js.dart.snapshot'
),
'--libraries-spec='
+
fs
.
path
.
join
(
'bin'
,
'cache'
,
'flutter_web_sdk'
,
'libraries.json'
),
'-O1'
,
// lowest optimizations.
'-o'
,
environment
.
buildDir
.
childFile
(
'main.dart.js'
).
absolute
.
path
,
'--packages=.packages'
,
'-Ddart.vm.profile=true'
,
environment
.
buildDir
.
childFile
(
'main.dart'
).
absolute
.
path
,
];
verify
(
processManager
.
run
(
expected
)).
called
(
1
);
},
overrides:
<
Type
,
Generator
>{
ProcessManager:
()
=>
MockProcessManager
(),
}));
test
(
'Dart2JSTarget calls dart2js with expected args in release mode'
,
()
=>
testbed
.
run
(()
async
{
environment
.
defines
[
kBuildMode
]
=
'release'
;
when
(
processManager
.
run
(
any
)).
thenAnswer
((
Invocation
invocation
)
async
{
return
FakeProcessResult
(
exitCode:
0
);
});
await
const
Dart2JSTarget
().
build
(
environment
);
final
List
<
String
>
expected
=
<
String
>[
fs
.
path
.
join
(
'bin'
,
'cache'
,
'dart-sdk'
,
'bin'
,
'dart'
),
fs
.
path
.
join
(
'bin'
,
'cache'
,
'dart-sdk'
,
'bin'
,
'snapshots'
,
'dart2js.dart.snapshot'
),
'--libraries-spec='
+
fs
.
path
.
join
(
'bin'
,
'cache'
,
'flutter_web_sdk'
,
'libraries.json'
),
'-O4'
,
// highest optimizations.
'-o'
,
environment
.
buildDir
.
childFile
(
'main.dart.js'
).
absolute
.
path
,
'--packages=.packages'
,
'-Ddart.vm.product=true'
,
environment
.
buildDir
.
childFile
(
'main.dart'
).
absolute
.
path
,
];
verify
(
processManager
.
run
(
expected
)).
called
(
1
);
},
overrides:
<
Type
,
Generator
>{
ProcessManager:
()
=>
MockProcessManager
(),
}));
test
(
'Dart2JSTarget calls dart2js with expected args in release with dart2js optimization override'
,
()
=>
testbed
.
run
(()
async
{
environment
.
defines
[
kBuildMode
]
=
'release'
;
environment
.
defines
[
kDart2jsOptimization
]
=
'O3'
;
when
(
processManager
.
run
(
any
)).
thenAnswer
((
Invocation
invocation
)
async
{
return
FakeProcessResult
(
exitCode:
0
);
});
await
const
Dart2JSTarget
().
build
(
environment
);
final
List
<
String
>
expected
=
<
String
>[
fs
.
path
.
join
(
'bin'
,
'cache'
,
'dart-sdk'
,
'bin'
,
'dart'
),
fs
.
path
.
join
(
'bin'
,
'cache'
,
'dart-sdk'
,
'bin'
,
'snapshots'
,
'dart2js.dart.snapshot'
),
'--libraries-spec='
+
fs
.
path
.
join
(
'bin'
,
'cache'
,
'flutter_web_sdk'
,
'libraries.json'
),
'-O3'
,
// configured optimizations.
'-o'
,
environment
.
buildDir
.
childFile
(
'main.dart.js'
).
absolute
.
path
,
'--packages=.packages'
,
'-Ddart.vm.product=true'
,
environment
.
buildDir
.
childFile
(
'main.dart'
).
absolute
.
path
,
];
verify
(
processManager
.
run
(
expected
)).
called
(
1
);
},
overrides:
<
Type
,
Generator
>{
ProcessManager:
()
=>
MockProcessManager
(),
}));
}
class
MockProcessManager
extends
Mock
implements
ProcessManager
{}
class
MockPlatform
extends
Mock
implements
Platform
{}
packages/flutter_tools/test/general.shard/commands/build_web_test.dart
View file @
ccc3dd96
...
...
@@ -2,11 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import
'dart:convert'
;
import
'package:archive/archive.dart'
;
import
'package:args/command_runner.dart'
;
import
'package:file_testing/file_testing.dart'
;
import
'package:flutter_tools/src/base/common.dart'
;
import
'package:flutter_tools/src/base/file_system.dart'
;
import
'package:flutter_tools/src/base/platform.dart'
;
...
...
@@ -26,10 +22,8 @@ import '../../src/common.dart';
import
'../../src/testbed.dart'
;
void
main
(
)
{
MockWebCompilationProxy
mockWebCompilationProxy
;
Testbed
testbed
;
MockPlatform
mockPlatform
;
bool
addArchive
=
false
;
setUpAll
(()
{
Cache
.
flutterRoot
=
''
;
...
...
@@ -37,8 +31,6 @@ void main() {
});
setUp
(()
{
addArchive
=
false
;
mockWebCompilationProxy
=
MockWebCompilationProxy
();
testbed
=
Testbed
(
setup:
()
{
fs
.
file
(
'pubspec.yaml'
)
..
createSync
()
...
...
@@ -46,47 +38,13 @@ void main() {
fs
.
file
(
'.packages'
).
createSync
();
fs
.
file
(
fs
.
path
.
join
(
'web'
,
'index.html'
)).
createSync
(
recursive:
true
);
fs
.
file
(
fs
.
path
.
join
(
'lib'
,
'main.dart'
)).
createSync
(
recursive:
true
);
when
(
mockWebCompilationProxy
.
initialize
(
projectName:
anyNamed
(
'projectName'
),
projectDirectory:
anyNamed
(
'projectDirectory'
),
mode:
anyNamed
(
'mode'
),
initializePlatform:
anyNamed
(
'initializePlatform'
),
)).
thenAnswer
((
Invocation
invocation
)
{
final
String
prefix
=
fs
.
path
.
join
(
'.dart_tool'
,
'build'
,
'flutter_web'
,
'foo'
,
'lib'
);
final
String
path
=
fs
.
path
.
join
(
prefix
,
'main_web_entrypoint.dart.js'
);
fs
.
file
(
path
).
createSync
(
recursive:
true
);
fs
.
file
(
'
$path
.map'
).
createSync
();
if
(
addArchive
)
{
final
List
<
int
>
bytes
=
utf8
.
encode
(
'void main() {}'
);
final
TarEncoder
encoder
=
TarEncoder
();
final
Archive
archive
=
Archive
()
..
addFile
(
ArchiveFile
.
noCompress
(
'main_web_entrypoint.1.dart.js'
,
bytes
.
length
,
bytes
));
fs
.
file
(
fs
.
path
.
join
(
prefix
,
'main_web_entrypoint.dart.js.tar.gz'
))
..
writeAsBytes
(
encoder
.
encode
(
archive
));
}
return
Future
<
bool
>.
value
(
true
);
});
},
overrides:
<
Type
,
Generator
>{
WebCompilationProxy:
()
=>
mockWebCompilationProxy
,
Platform:
()
=>
mockPlatform
,
FlutterVersion:
()
=>
MockFlutterVersion
(),
FeatureFlags:
()
=>
TestFeatureFlags
(
isWebEnabled:
true
),
});
});
test
(
'Copies generated part files out of build directory'
,
()
=>
testbed
.
run
(()
async
{
addArchive
=
true
;
await
buildWeb
(
FlutterProject
.
current
(),
fs
.
path
.
join
(
'lib'
,
'main.dart'
),
BuildInfo
.
release
,
false
,
);
expect
(
fs
.
file
(
fs
.
path
.
join
(
'build'
,
'web'
,
'main_web_entrypoint.1.dart.js'
)),
exists
);
expect
(
fs
.
file
(
fs
.
path
.
join
(
'build'
,
'web'
,
'main.dart.js'
)),
exists
);
}));
test
(
'Refuses to build for web when missing index.html'
,
()
=>
testbed
.
run
(()
async
{
fs
.
file
(
fs
.
path
.
join
(
'web'
,
'index.html'
)).
deleteSync
();
...
...
packages/flutter_tools/test/general.shard/web/asset_server_test.dart
View file @
ccc3dd96
...
...
@@ -22,7 +22,7 @@ void main() {
fs
.
file
(
fs
.
path
.
join
(
'web'
,
'index.html'
))
..
createSync
(
recursive:
true
)
..
writeAsStringSync
(
'hello'
);
assetServer
=
AssetServer
(
FlutterProject
.
current
(),
fs
.
path
.
join
(
'main'
));
assetServer
=
Debug
AssetServer
(
FlutterProject
.
current
(),
fs
.
path
.
join
(
'main'
));
}
);
});
...
...
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