mirror of
https://github.com/flutter/flutter
synced 2024-10-13 19:52:53 +00:00
Support flutter build web --wasm
(#117075)
* Work in progress. * Some fixes to the command line. * Bootstrapping works. * Change kickoff order to maximize concurrency. * Fix analyzer errors and formatting issues. * Fix doc comment. * Added unit tests for some of the web targets. * Format issue. * Add an integration test that builds an app to wasm. * Add a todo for depfiles. * Formatting. * Apparently the license header needs to say 2014. * `file://` URIs confuse dart2wasm on Windows. Just use absolute paths. * Update unit tests to match new path passing. * Have a distinct build directory for wasm, and fixes for some upstream changes.
This commit is contained in:
parent
70f391db77
commit
9f2c5d8e21
|
@ -34,10 +34,14 @@ enum Artifact {
|
|||
engineDartSdkPath,
|
||||
/// The dart binary used to execute any of the required snapshots.
|
||||
engineDartBinary,
|
||||
/// The dart binary for running aot snapshots
|
||||
engineDartAotRuntime,
|
||||
/// The snapshot of frontend_server compiler.
|
||||
frontendServerSnapshotForEngineDartSdk,
|
||||
/// The dart snapshot of the dart2js compiler.
|
||||
dart2jsSnapshot,
|
||||
/// The dart snapshot of the dart2wasm compiler.
|
||||
dart2wasmSnapshot,
|
||||
|
||||
/// The root of the Linux desktop sources.
|
||||
linuxDesktopPath,
|
||||
|
@ -168,8 +172,12 @@ String? _artifactToFileName(Artifact artifact, Platform hostPlatform, [ BuildMod
|
|||
return 'dart-sdk';
|
||||
case Artifact.engineDartBinary:
|
||||
return 'dart$exe';
|
||||
case Artifact.engineDartAotRuntime:
|
||||
return 'dartaotruntime$exe';
|
||||
case Artifact.dart2jsSnapshot:
|
||||
return 'dart2js.dart.snapshot';
|
||||
case Artifact.dart2wasmSnapshot:
|
||||
return 'dart2wasm_product.snapshot';
|
||||
case Artifact.frontendServerSnapshotForEngineDartSdk:
|
||||
return 'frontend_server.dart.snapshot';
|
||||
case Artifact.linuxDesktopPath:
|
||||
|
@ -488,7 +496,9 @@ class CachedArtifacts implements Artifacts {
|
|||
return _fileSystem.path.join(engineDir, hostPlatform, _artifactToFileName(artifact, _platform));
|
||||
case Artifact.engineDartSdkPath:
|
||||
case Artifact.engineDartBinary:
|
||||
case Artifact.engineDartAotRuntime:
|
||||
case Artifact.dart2jsSnapshot:
|
||||
case Artifact.dart2wasmSnapshot:
|
||||
case Artifact.frontendServerSnapshotForEngineDartSdk:
|
||||
case Artifact.constFinder:
|
||||
case Artifact.flutterFramework:
|
||||
|
@ -525,7 +535,9 @@ class CachedArtifacts implements Artifacts {
|
|||
return _getIosEngineArtifactPath(engineDir, environmentType, _fileSystem, _platform);
|
||||
case Artifact.engineDartSdkPath:
|
||||
case Artifact.engineDartBinary:
|
||||
case Artifact.engineDartAotRuntime:
|
||||
case Artifact.dart2jsSnapshot:
|
||||
case Artifact.dart2wasmSnapshot:
|
||||
case Artifact.frontendServerSnapshotForEngineDartSdk:
|
||||
case Artifact.constFinder:
|
||||
case Artifact.flutterMacOSFramework:
|
||||
|
@ -580,7 +592,9 @@ class CachedArtifacts implements Artifacts {
|
|||
case Artifact.fontSubset:
|
||||
case Artifact.engineDartSdkPath:
|
||||
case Artifact.engineDartBinary:
|
||||
case Artifact.engineDartAotRuntime:
|
||||
case Artifact.dart2jsSnapshot:
|
||||
case Artifact.dart2wasmSnapshot:
|
||||
case Artifact.frontendServerSnapshotForEngineDartSdk:
|
||||
case Artifact.icuData:
|
||||
case Artifact.isolateSnapshotData:
|
||||
|
@ -613,6 +627,7 @@ class CachedArtifacts implements Artifacts {
|
|||
// android_arm in profile mode because it is available on all supported host platforms.
|
||||
return _getAndroidArtifactPath(artifact, TargetPlatform.android_arm, BuildMode.profile);
|
||||
case Artifact.dart2jsSnapshot:
|
||||
case Artifact.dart2wasmSnapshot:
|
||||
case Artifact.frontendServerSnapshotForEngineDartSdk:
|
||||
return _fileSystem.path.join(
|
||||
_dartSdkPath(_cache), 'bin', 'snapshots',
|
||||
|
@ -634,6 +649,7 @@ class CachedArtifacts implements Artifacts {
|
|||
case Artifact.engineDartSdkPath:
|
||||
return _dartSdkPath(_cache);
|
||||
case Artifact.engineDartBinary:
|
||||
case Artifact.engineDartAotRuntime:
|
||||
return _fileSystem.path.join(_dartSdkPath(_cache), 'bin', _artifactToFileName(artifact, _platform));
|
||||
case Artifact.flutterMacOSFramework:
|
||||
case Artifact.linuxDesktopPath:
|
||||
|
@ -925,13 +941,12 @@ class CachedLocalEngineArtifacts implements Artifacts {
|
|||
case Artifact.engineDartSdkPath:
|
||||
return _getDartSdkPath();
|
||||
case Artifact.engineDartBinary:
|
||||
case Artifact.engineDartAotRuntime:
|
||||
return _fileSystem.path.join(_getDartSdkPath(), 'bin', artifactFileName);
|
||||
case Artifact.dart2jsSnapshot:
|
||||
return _fileSystem.path.join(_getDartSdkPath(), 'bin', 'snapshots', artifactFileName);
|
||||
case Artifact.dart2wasmSnapshot:
|
||||
case Artifact.frontendServerSnapshotForEngineDartSdk:
|
||||
return _fileSystem.path.join(
|
||||
_getDartSdkPath(), 'bin', 'snapshots', artifactFileName,
|
||||
);
|
||||
return _fileSystem.path.join(_getDartSdkPath(), 'bin', 'snapshots', artifactFileName);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1048,10 +1063,12 @@ class CachedLocalWebSdkArtifacts implements Artifacts {
|
|||
case Artifact.engineDartSdkPath:
|
||||
return _getDartSdkPath();
|
||||
case Artifact.engineDartBinary:
|
||||
case Artifact.engineDartAotRuntime:
|
||||
return _fileSystem.path.join(
|
||||
_getDartSdkPath(), 'bin',
|
||||
_artifactToFileName(artifact, _platform, mode));
|
||||
case Artifact.dart2jsSnapshot:
|
||||
case Artifact.dart2wasmSnapshot:
|
||||
case Artifact.frontendServerSnapshotForEngineDartSdk:
|
||||
return _fileSystem.path.join(
|
||||
_getDartSdkPath(), 'bin', 'snapshots',
|
||||
|
|
|
@ -914,8 +914,8 @@ String getMacOSBuildDirectory() {
|
|||
}
|
||||
|
||||
/// Returns the web build output directory.
|
||||
String getWebBuildDirectory() {
|
||||
return globals.fs.path.join(getBuildDirectory(), 'web');
|
||||
String getWebBuildDirectory([bool isWasm = false]) {
|
||||
return globals.fs.path.join(getBuildDirectory(), isWasm ? 'web_wasm' : 'web');
|
||||
}
|
||||
|
||||
/// Returns the Linux build output directory.
|
||||
|
|
|
@ -22,6 +22,7 @@ import '../../web/compile.dart';
|
|||
import '../../web/file_generators/flutter_js.dart' as flutter_js;
|
||||
import '../../web/file_generators/flutter_service_worker_js.dart';
|
||||
import '../../web/file_generators/main_dart.dart' as main_dart;
|
||||
import '../../web/file_generators/wasm_bootstrap.dart' as wasm_bootstrap;
|
||||
import '../build_system.dart';
|
||||
import '../depfile.dart';
|
||||
import '../exceptions.dart';
|
||||
|
@ -141,13 +142,11 @@ class WebEntrypointTarget extends Target {
|
|||
}
|
||||
|
||||
/// Compiles a web entry point with dart2js.
|
||||
class Dart2JSTarget extends Target {
|
||||
const Dart2JSTarget(this.webRenderer);
|
||||
abstract class Dart2WebTarget extends Target {
|
||||
const Dart2WebTarget(this.webRenderer);
|
||||
|
||||
final WebRendererMode webRenderer;
|
||||
|
||||
@override
|
||||
String get name => 'dart2js';
|
||||
Source get compilerSnapshot;
|
||||
|
||||
@override
|
||||
List<Target> get dependencies => const <Target>[
|
||||
|
@ -156,22 +155,17 @@ class Dart2JSTarget extends Target {
|
|||
];
|
||||
|
||||
@override
|
||||
List<Source> get inputs => const <Source>[
|
||||
Source.hostArtifact(HostArtifact.flutterWebSdk),
|
||||
Source.artifact(Artifact.dart2jsSnapshot),
|
||||
Source.artifact(Artifact.engineDartBinary),
|
||||
Source.pattern('{BUILD_DIR}/main.dart'),
|
||||
Source.pattern('{PROJECT_DIR}/.dart_tool/package_config_subset'),
|
||||
List<Source> get inputs => <Source>[
|
||||
const Source.hostArtifact(HostArtifact.flutterWebSdk),
|
||||
compilerSnapshot,
|
||||
const Source.artifact(Artifact.engineDartBinary),
|
||||
const Source.pattern('{BUILD_DIR}/main.dart'),
|
||||
const Source.pattern('{PROJECT_DIR}/.dart_tool/package_config_subset'),
|
||||
];
|
||||
|
||||
@override
|
||||
List<Source> get outputs => const <Source>[];
|
||||
|
||||
@override
|
||||
List<String> get depfiles => const <String>[
|
||||
'dart2js.d',
|
||||
];
|
||||
|
||||
String _collectOutput(ProcessResult result) {
|
||||
final String stdout = result.stdout is List<int>
|
||||
? utf8.decode(result.stdout as List<int>)
|
||||
|
@ -181,6 +175,21 @@ class Dart2JSTarget extends Target {
|
|||
: result.stderr as String;
|
||||
return stdout + stderr;
|
||||
}
|
||||
}
|
||||
|
||||
class Dart2JSTarget extends Dart2WebTarget {
|
||||
Dart2JSTarget(super.webRenderer);
|
||||
|
||||
@override
|
||||
String get name => 'dart2js';
|
||||
|
||||
@override
|
||||
Source get compilerSnapshot => const Source.artifact(Artifact.dart2jsSnapshot);
|
||||
|
||||
@override
|
||||
List<String> get depfiles => const <String>[
|
||||
'dart2js.d',
|
||||
];
|
||||
|
||||
@override
|
||||
Future<void> build(Environment environment) async {
|
||||
|
@ -270,29 +279,94 @@ class Dart2JSTarget extends Target {
|
|||
}
|
||||
}
|
||||
|
||||
/// Unpacks the dart2js compilation and resources to a given output directory.
|
||||
class Dart2WasmTarget extends Dart2WebTarget {
|
||||
Dart2WasmTarget(super.webRenderer);
|
||||
|
||||
@override
|
||||
Future<void> build(Environment environment) async {
|
||||
final String? buildModeEnvironment = environment.defines[kBuildMode];
|
||||
if (buildModeEnvironment == null) {
|
||||
throw MissingDefineException(kBuildMode, name);
|
||||
}
|
||||
final BuildMode buildMode = getBuildModeForName(buildModeEnvironment);
|
||||
final Artifacts artifacts = globals.artifacts!;
|
||||
final File outputWasmFile = environment.buildDir.childFile('main.dart.wasm');
|
||||
final String dartSdkPath = artifacts.getArtifactPath(Artifact.engineDartSdkPath, platform: TargetPlatform.web_javascript);
|
||||
final String dartSdkRoot = environment.fileSystem.directory(dartSdkPath).parent.path;
|
||||
|
||||
final List<String> compilationArgs = <String>[
|
||||
artifacts.getArtifactPath(Artifact.engineDartAotRuntime, platform: TargetPlatform.web_javascript),
|
||||
'--disable-dart-dev',
|
||||
artifacts.getArtifactPath(Artifact.dart2wasmSnapshot, platform: TargetPlatform.web_javascript),
|
||||
if (buildMode == BuildMode.profile)
|
||||
'-Ddart.vm.profile=true'
|
||||
else
|
||||
'-Ddart.vm.product=true',
|
||||
...decodeCommaSeparated(environment.defines, kExtraFrontEndOptions),
|
||||
for (final String dartDefine in decodeDartDefines(environment.defines, kDartDefines))
|
||||
'-D$dartDefine',
|
||||
'--packages=.dart_tool/package_config.json',
|
||||
'--dart-sdk=$dartSdkPath',
|
||||
'--multi-root-scheme',
|
||||
'org-dartlang-sdk',
|
||||
'--multi-root',
|
||||
artifacts.getHostArtifact(HostArtifact.flutterWebSdk).path,
|
||||
'--multi-root',
|
||||
dartSdkRoot,
|
||||
'--libraries-spec',
|
||||
artifacts.getHostArtifact(HostArtifact.flutterWebLibrariesJson).path,
|
||||
|
||||
environment.buildDir.childFile('main.dart').path, // dartfile
|
||||
outputWasmFile.path,
|
||||
];
|
||||
final ProcessResult compileResult = await globals.processManager.run(compilationArgs);
|
||||
if (compileResult.exitCode != 0) {
|
||||
throw Exception(_collectOutput(compileResult));
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Source get compilerSnapshot => const Source.artifact(Artifact.dart2wasmSnapshot);
|
||||
|
||||
@override
|
||||
String get name => 'dart2wasm';
|
||||
|
||||
@override
|
||||
List<Source> get outputs => const <Source>[
|
||||
Source.pattern('{OUTPUT_DIR}/main.dart.wasm'),
|
||||
];
|
||||
|
||||
// TODO(jacksongardner): override `depfiles` once dart2wasm begins producing
|
||||
// them: https://github.com/dart-lang/sdk/issues/50747
|
||||
}
|
||||
|
||||
/// Unpacks the dart2js or dart2wasm compilation and resources to a given
|
||||
/// output directory.
|
||||
class WebReleaseBundle extends Target {
|
||||
const WebReleaseBundle(this.webRenderer);
|
||||
const WebReleaseBundle(this.webRenderer, this.isWasm);
|
||||
|
||||
final WebRendererMode webRenderer;
|
||||
final bool isWasm;
|
||||
|
||||
String get outputFileName => isWasm ? 'main.dart.wasm' : 'main.dart.js';
|
||||
|
||||
@override
|
||||
String get name => 'web_release_bundle';
|
||||
|
||||
@override
|
||||
List<Target> get dependencies => <Target>[
|
||||
Dart2JSTarget(webRenderer),
|
||||
if (isWasm) Dart2WasmTarget(webRenderer) else Dart2JSTarget(webRenderer),
|
||||
];
|
||||
|
||||
@override
|
||||
List<Source> get inputs => const <Source>[
|
||||
Source.pattern('{BUILD_DIR}/main.dart.js'),
|
||||
Source.pattern('{PROJECT_DIR}/pubspec.yaml'),
|
||||
List<Source> get inputs => <Source>[
|
||||
Source.pattern('{BUILD_DIR}/$outputFileName'),
|
||||
const Source.pattern('{PROJECT_DIR}/pubspec.yaml'),
|
||||
];
|
||||
|
||||
@override
|
||||
List<Source> get outputs => const <Source>[
|
||||
Source.pattern('{OUTPUT_DIR}/main.dart.js'),
|
||||
List<Source> get outputs => <Source>[
|
||||
Source.pattern('{OUTPUT_DIR}/$outputFileName'),
|
||||
];
|
||||
|
||||
@override
|
||||
|
@ -306,7 +380,7 @@ class WebReleaseBundle extends Target {
|
|||
Future<void> build(Environment environment) async {
|
||||
for (final File outputFile in environment.buildDir.listSync(recursive: true).whereType<File>()) {
|
||||
final String basename = globals.fs.path.basename(outputFile.path);
|
||||
if (!basename.contains('main.dart.js')) {
|
||||
if (!basename.contains(outputFileName)) {
|
||||
continue;
|
||||
}
|
||||
// Do not copy the deps file.
|
||||
|
@ -318,6 +392,12 @@ class WebReleaseBundle extends Target {
|
|||
);
|
||||
}
|
||||
|
||||
if (isWasm) {
|
||||
// TODO(jacksongardner): Enable icon tree shaking once dart2wasm can do a two-phase compile.
|
||||
// https://github.com/flutter/flutter/issues/117248
|
||||
environment.defines[kIconTreeShakerFlag] = 'false';
|
||||
}
|
||||
|
||||
createVersionFile(environment, environment.defines);
|
||||
final Directory outputDirectory = environment.outputDir.childDirectory('assets');
|
||||
outputDirectory.createSync(recursive: true);
|
||||
|
@ -413,10 +493,11 @@ class WebReleaseBundle extends Target {
|
|||
/// These assets can be cached forever and are only invalidated when the
|
||||
/// Flutter SDK is upgraded to a new version.
|
||||
class WebBuiltInAssets extends Target {
|
||||
const WebBuiltInAssets(this.fileSystem, this.cache);
|
||||
const WebBuiltInAssets(this.fileSystem, this.cache, this.isWasm);
|
||||
|
||||
final FileSystem fileSystem;
|
||||
final Cache cache;
|
||||
final bool isWasm;
|
||||
|
||||
@override
|
||||
String get name => 'web_static_assets';
|
||||
|
@ -451,6 +532,21 @@ class WebBuiltInAssets extends Target {
|
|||
file.copySync(targetPath);
|
||||
}
|
||||
|
||||
if (isWasm) {
|
||||
final String dartSdkPath =
|
||||
globals.artifacts!.getArtifactPath(Artifact.engineDartSdkPath);
|
||||
final File dart2wasmRuntime = fileSystem.directory(dartSdkPath)
|
||||
.childDirectory('bin')
|
||||
.childFile('dart2wasm_runtime.mjs');
|
||||
final String targetPath = fileSystem.path.join(
|
||||
environment.outputDir.path,
|
||||
'dart2wasm_runtime.mjs');
|
||||
dart2wasmRuntime.copySync(targetPath);
|
||||
|
||||
final File bootstrapFile = environment.outputDir.childFile('main.dart.js');
|
||||
bootstrapFile.writeAsStringSync(wasm_bootstrap.generateWasmBootstrapFile());
|
||||
}
|
||||
|
||||
// Write the flutter.js file
|
||||
final File flutterJsFile = environment.outputDir.childFile('flutter.js');
|
||||
flutterJsFile.writeAsStringSync(flutter_js.generateFlutterJsFile());
|
||||
|
@ -459,20 +555,21 @@ class WebBuiltInAssets extends Target {
|
|||
|
||||
/// Generate a service worker for a web target.
|
||||
class WebServiceWorker extends Target {
|
||||
const WebServiceWorker(this.fileSystem, this.cache, this.webRenderer);
|
||||
const WebServiceWorker(this.fileSystem, this.cache, this.webRenderer, this.isWasm);
|
||||
|
||||
final FileSystem fileSystem;
|
||||
final Cache cache;
|
||||
final WebRendererMode webRenderer;
|
||||
final bool isWasm;
|
||||
|
||||
@override
|
||||
String get name => 'web_service_worker';
|
||||
|
||||
@override
|
||||
List<Target> get dependencies => <Target>[
|
||||
Dart2JSTarget(webRenderer),
|
||||
WebReleaseBundle(webRenderer),
|
||||
WebBuiltInAssets(fileSystem, cache),
|
||||
if (isWasm) Dart2WasmTarget(webRenderer) else Dart2JSTarget(webRenderer),
|
||||
WebReleaseBundle(webRenderer, isWasm),
|
||||
WebBuiltInAssets(fileSystem, cache, isWasm),
|
||||
];
|
||||
|
||||
@override
|
||||
|
|
|
@ -42,6 +42,10 @@ class BuildWebCommand extends BuildSubCommand {
|
|||
'to view and debug the original source code of a compiled and minified Dart '
|
||||
'application.'
|
||||
);
|
||||
argParser.addFlag(
|
||||
'wasm',
|
||||
help: 'Compile to WebAssembly rather than Javascript (experimental).'
|
||||
);
|
||||
|
||||
argParser.addOption('pwa-strategy',
|
||||
defaultsTo: kOfflineFirst,
|
||||
|
@ -140,6 +144,7 @@ class BuildWebCommand extends BuildSubCommand {
|
|||
stringArgDeprecated('pwa-strategy')!,
|
||||
boolArgDeprecated('source-maps'),
|
||||
boolArgDeprecated('native-null-assertions'),
|
||||
boolArgDeprecated('wasm'),
|
||||
baseHref: baseHref,
|
||||
dart2jsOptimization: stringArgDeprecated('dart2js-optimization'),
|
||||
outputDirectoryPath: outputDirectoryPath,
|
||||
|
|
|
@ -298,6 +298,7 @@ class ResidentWebRunner extends ResidentRunner {
|
|||
kNoneWorker,
|
||||
true,
|
||||
debuggingOptions.nativeNullAssertions,
|
||||
false,
|
||||
);
|
||||
}
|
||||
await device!.device!.startApp(
|
||||
|
@ -370,6 +371,7 @@ class ResidentWebRunner extends ResidentRunner {
|
|||
kNoneWorker,
|
||||
true,
|
||||
debuggingOptions.nativeNullAssertions,
|
||||
false,
|
||||
baseHref: kBaseHref,
|
||||
);
|
||||
} on ToolExit {
|
||||
|
|
|
@ -25,7 +25,8 @@ Future<void> buildWeb(
|
|||
bool csp,
|
||||
String serviceWorkerStrategy,
|
||||
bool sourceMaps,
|
||||
bool nativeNullAssertions, {
|
||||
bool nativeNullAssertions,
|
||||
bool isWasm, {
|
||||
String? dart2jsOptimization,
|
||||
String? baseHref,
|
||||
bool dumpInfo = false,
|
||||
|
@ -35,7 +36,7 @@ Future<void> buildWeb(
|
|||
final bool hasWebPlugins = (await findPlugins(flutterProject))
|
||||
.any((Plugin p) => p.platforms.containsKey(WebPlugin.kConfigKey));
|
||||
final Directory outputDirectory = outputDirectoryPath == null
|
||||
? globals.fs.directory(getWebBuildDirectory())
|
||||
? globals.fs.directory(getWebBuildDirectory(isWasm))
|
||||
: globals.fs.directory(outputDirectoryPath);
|
||||
outputDirectory.createSync(recursive: true);
|
||||
|
||||
|
@ -51,7 +52,7 @@ Future<void> buildWeb(
|
|||
final Stopwatch sw = Stopwatch()..start();
|
||||
try {
|
||||
final BuildResult result = await globals.buildSystem.build(
|
||||
WebServiceWorker(globals.fs, globals.cache, buildInfo.webRenderer),
|
||||
WebServiceWorker(globals.fs, globals.cache, buildInfo.webRenderer, isWasm),
|
||||
Environment(
|
||||
projectDir: globals.fs.currentDirectory,
|
||||
outputDir: outputDirectory,
|
||||
|
|
|
@ -0,0 +1,31 @@
|
|||
// 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.
|
||||
|
||||
String generateWasmBootstrapFile() {
|
||||
return r'''
|
||||
// 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.
|
||||
|
||||
(async function () {
|
||||
let dart2wasm_runtime;
|
||||
let moduleInstance;
|
||||
try {
|
||||
const dartModulePromise = WebAssembly.compileStreaming(fetch("main.dart.wasm"));
|
||||
dart2wasm_runtime = await import('./dart2wasm_runtime.mjs');
|
||||
moduleInstance = await dart2wasm_runtime.instantiate(dartModulePromise, {});
|
||||
} catch (exception) {
|
||||
console.error(`Failed to fetch and instantiate wasm module: ${exception}`);
|
||||
}
|
||||
|
||||
if (moduleInstance) {
|
||||
try {
|
||||
await dart2wasm_runtime.invoke(moduleInstance);
|
||||
} catch (exception) {
|
||||
console.error(`Exception while invoking test: ${exception}`);
|
||||
}
|
||||
}
|
||||
})();
|
||||
''';
|
||||
}
|
|
@ -100,7 +100,7 @@ void main() {
|
|||
webResources.childFile('index.html')
|
||||
.createSync(recursive: true);
|
||||
environment.buildDir.childFile('main.dart.js').createSync();
|
||||
await const WebReleaseBundle(WebRendererMode.autoDetect).build(environment);
|
||||
await const WebReleaseBundle(WebRendererMode.autoDetect, false).build(environment);
|
||||
|
||||
expect(environment.outputDir.childFile('version.json'), exists);
|
||||
}));
|
||||
|
@ -112,7 +112,7 @@ void main() {
|
|||
final Directory webResources = environment.projectDir.childDirectory('web');
|
||||
webResources.childFile('index.html').createSync(recursive: true);
|
||||
environment.buildDir.childFile('main.dart.js').createSync();
|
||||
await const WebReleaseBundle(WebRendererMode.autoDetect).build(environment);
|
||||
await const WebReleaseBundle(WebRendererMode.autoDetect, false).build(environment);
|
||||
|
||||
final String versionFile = environment.outputDir
|
||||
.childFile('version.json')
|
||||
|
@ -130,7 +130,7 @@ void main() {
|
|||
<!DOCTYPE html><html><base href="$kBaseHrefPlaceholder"><head></head></html>
|
||||
''');
|
||||
environment.buildDir.childFile('main.dart.js').createSync();
|
||||
await const WebReleaseBundle(WebRendererMode.autoDetect).build(environment);
|
||||
await const WebReleaseBundle(WebRendererMode.autoDetect, false).build(environment);
|
||||
|
||||
expect(environment.outputDir.childFile('index.html').readAsStringSync(), contains('/basehreftest/'));
|
||||
}));
|
||||
|
@ -143,7 +143,7 @@ void main() {
|
|||
<!DOCTYPE html><html><head><base href='/basehreftest/'></head></html>
|
||||
''');
|
||||
environment.buildDir.childFile('main.dart.js').createSync();
|
||||
await const WebReleaseBundle(WebRendererMode.autoDetect).build(environment);
|
||||
await const WebReleaseBundle(WebRendererMode.autoDetect, false).build(environment);
|
||||
|
||||
expect(environment.outputDir.childFile('index.html').readAsStringSync(), contains('/basehreftest/'));
|
||||
}));
|
||||
|
@ -165,7 +165,7 @@ void main() {
|
|||
.writeAsStringSync('A');
|
||||
environment.buildDir.childFile('main.dart.js').createSync();
|
||||
|
||||
await const WebReleaseBundle(WebRendererMode.autoDetect).build(environment);
|
||||
await const WebReleaseBundle(WebRendererMode.autoDetect, false).build(environment);
|
||||
|
||||
expect(environment.outputDir.childFile('foo.txt')
|
||||
.readAsStringSync(), 'A');
|
||||
|
@ -177,7 +177,7 @@ void main() {
|
|||
// Update to arbitrary resource file triggers rebuild.
|
||||
webResources.childFile('foo.txt').writeAsStringSync('B');
|
||||
|
||||
await const WebReleaseBundle(WebRendererMode.autoDetect).build(environment);
|
||||
await const WebReleaseBundle(WebRendererMode.autoDetect, false).build(environment);
|
||||
|
||||
expect(environment.outputDir.childFile('foo.txt')
|
||||
.readAsStringSync(), 'B');
|
||||
|
@ -358,7 +358,7 @@ void main() {
|
|||
]
|
||||
));
|
||||
|
||||
await const Dart2JSTarget(WebRendererMode.autoDetect).build(environment);
|
||||
await Dart2JSTarget(WebRendererMode.autoDetect).build(environment);
|
||||
}, overrides: <Type, Generator>{
|
||||
ProcessManager: () => processManager,
|
||||
}));
|
||||
|
@ -396,7 +396,7 @@ void main() {
|
|||
]
|
||||
));
|
||||
|
||||
await const Dart2JSTarget(WebRendererMode.autoDetect).build(environment);
|
||||
await Dart2JSTarget(WebRendererMode.autoDetect).build(environment);
|
||||
}, overrides: <Type, Generator>{
|
||||
ProcessManager: () => processManager,
|
||||
}));
|
||||
|
@ -430,7 +430,7 @@ void main() {
|
|||
]
|
||||
));
|
||||
|
||||
await const Dart2JSTarget(WebRendererMode.autoDetect).build(environment);
|
||||
await Dart2JSTarget(WebRendererMode.autoDetect).build(environment);
|
||||
}, overrides: <Type, Generator>{
|
||||
ProcessManager: () => processManager,
|
||||
}));
|
||||
|
@ -463,7 +463,7 @@ void main() {
|
|||
]
|
||||
));
|
||||
|
||||
await const Dart2JSTarget(WebRendererMode.autoDetect).build(environment);
|
||||
await Dart2JSTarget(WebRendererMode.autoDetect).build(environment);
|
||||
}, overrides: <Type, Generator>{
|
||||
ProcessManager: () => processManager,
|
||||
}));
|
||||
|
@ -499,7 +499,7 @@ void main() {
|
|||
]
|
||||
));
|
||||
|
||||
await const Dart2JSTarget(WebRendererMode.autoDetect).build(environment);
|
||||
await Dart2JSTarget(WebRendererMode.autoDetect).build(environment);
|
||||
}, overrides: <Type, Generator>{
|
||||
ProcessManager: () => processManager,
|
||||
}));
|
||||
|
@ -533,7 +533,7 @@ void main() {
|
|||
]
|
||||
));
|
||||
|
||||
await const Dart2JSTarget(WebRendererMode.autoDetect).build(environment);
|
||||
await Dart2JSTarget(WebRendererMode.autoDetect).build(environment);
|
||||
}, overrides: <Type, Generator>{
|
||||
ProcessManager: () => processManager,
|
||||
}));
|
||||
|
@ -556,7 +556,7 @@ void main() {
|
|||
.writeAsStringSync('file:///a.dart');
|
||||
},
|
||||
));
|
||||
await const Dart2JSTarget(WebRendererMode.autoDetect).build(environment);
|
||||
await Dart2JSTarget(WebRendererMode.autoDetect).build(environment);
|
||||
|
||||
expect(environment.buildDir.childFile('dart2js.d'), exists);
|
||||
final Depfile depfile = depfileService.parse(environment.buildDir.childFile('dart2js.d'));
|
||||
|
@ -601,7 +601,7 @@ void main() {
|
|||
]
|
||||
));
|
||||
|
||||
await const Dart2JSTarget(WebRendererMode.autoDetect).build(environment);
|
||||
await Dart2JSTarget(WebRendererMode.autoDetect).build(environment);
|
||||
}, overrides: <Type, Generator>{
|
||||
ProcessManager: () => processManager,
|
||||
}));
|
||||
|
@ -633,7 +633,7 @@ void main() {
|
|||
]
|
||||
));
|
||||
|
||||
await const Dart2JSTarget(WebRendererMode.autoDetect).build(environment);
|
||||
await Dart2JSTarget(WebRendererMode.autoDetect).build(environment);
|
||||
}, overrides: <Type, Generator>{
|
||||
ProcessManager: () => processManager,
|
||||
}));
|
||||
|
@ -673,7 +673,7 @@ void main() {
|
|||
]
|
||||
));
|
||||
|
||||
await const Dart2JSTarget(WebRendererMode.autoDetect).build(environment);
|
||||
await Dart2JSTarget(WebRendererMode.autoDetect).build(environment);
|
||||
}, overrides: <Type, Generator>{
|
||||
ProcessManager: () => processManager,
|
||||
}));
|
||||
|
@ -709,7 +709,7 @@ void main() {
|
|||
]
|
||||
));
|
||||
|
||||
await const Dart2JSTarget(WebRendererMode.canvaskit).build(environment);
|
||||
await Dart2JSTarget(WebRendererMode.canvaskit).build(environment);
|
||||
}, overrides: <Type, Generator>{
|
||||
ProcessManager: () => processManager,
|
||||
}));
|
||||
|
@ -745,7 +745,40 @@ void main() {
|
|||
]
|
||||
));
|
||||
|
||||
await const Dart2JSTarget(WebRendererMode.canvaskit).build(environment);
|
||||
await Dart2JSTarget(WebRendererMode.canvaskit).build(environment);
|
||||
}, overrides: <Type, Generator>{
|
||||
ProcessManager: () => processManager,
|
||||
}));
|
||||
|
||||
test('Dart2WasmTarget invokes dart2wasm with dart defines', () => testbed.run(() async {
|
||||
environment.defines[kBuildMode] = 'profile';
|
||||
environment.defines[kDartDefines] = encodeDartDefines(<String>['FOO=bar', 'BAZ=qux']);
|
||||
|
||||
processManager.addCommand(FakeCommand(
|
||||
command: <String>[
|
||||
'bin/cache/dart-sdk/bin/dartaotruntime',
|
||||
'--disable-dart-dev',
|
||||
'bin/cache/dart-sdk/bin/snapshots/dart2wasm_product.snapshot',
|
||||
'-Ddart.vm.profile=true',
|
||||
'-DFOO=bar',
|
||||
'-DBAZ=qux',
|
||||
'--packages=.dart_tool/package_config.json',
|
||||
'--dart-sdk=bin/cache/dart-sdk',
|
||||
'--multi-root-scheme',
|
||||
'org-dartlang-sdk',
|
||||
'--multi-root',
|
||||
'bin/cache/flutter_web_sdk',
|
||||
'--multi-root',
|
||||
'bin/cache',
|
||||
'--libraries-spec',
|
||||
'bin/cache/flutter_web_sdk/libraries.json',
|
||||
|
||||
environment.buildDir.childFile('main.dart').absolute.path,
|
||||
environment.buildDir.childFile('main.dart.wasm').absolute.path,
|
||||
])
|
||||
);
|
||||
|
||||
await Dart2WasmTarget(WebRendererMode.canvaskit).build(environment);
|
||||
}, overrides: <Type, Generator>{
|
||||
ProcessManager: () => processManager,
|
||||
}));
|
||||
|
@ -772,7 +805,7 @@ void main() {
|
|||
environment.outputDir.childDirectory('a').childFile('a.txt')
|
||||
..createSync(recursive: true)
|
||||
..writeAsStringSync('A');
|
||||
await WebServiceWorker(globals.fs, globals.cache, WebRendererMode.autoDetect).build(environment);
|
||||
await WebServiceWorker(globals.fs, globals.cache, WebRendererMode.autoDetect, false).build(environment);
|
||||
|
||||
expect(environment.outputDir.childFile('flutter_service_worker.js'), exists);
|
||||
// Contains file hash.
|
||||
|
@ -791,7 +824,7 @@ void main() {
|
|||
environment.outputDir
|
||||
.childFile('index.html')
|
||||
.createSync(recursive: true);
|
||||
await WebServiceWorker(globals.fs, globals.cache, WebRendererMode.autoDetect).build(environment);
|
||||
await WebServiceWorker(globals.fs, globals.cache, WebRendererMode.autoDetect, false).build(environment);
|
||||
|
||||
expect(environment.outputDir.childFile('flutter_service_worker.js'), exists);
|
||||
// Contains file hash for both `/` and index.html.
|
||||
|
@ -809,7 +842,7 @@ void main() {
|
|||
environment.outputDir
|
||||
.childFile('main.dart.js.map')
|
||||
.createSync(recursive: true);
|
||||
await WebServiceWorker(globals.fs, globals.cache, WebRendererMode.autoDetect).build(environment);
|
||||
await WebServiceWorker(globals.fs, globals.cache, WebRendererMode.autoDetect, false).build(environment);
|
||||
|
||||
// No caching of source maps.
|
||||
expect(environment.outputDir.childFile('flutter_service_worker.js').readAsStringSync(),
|
||||
|
@ -824,10 +857,25 @@ void main() {
|
|||
..createSync(recursive: true)
|
||||
..writeAsStringSync('OL');
|
||||
|
||||
await WebBuiltInAssets(globals.fs, globals.cache).build(environment);
|
||||
await WebBuiltInAssets(globals.fs, globals.cache, false).build(environment);
|
||||
|
||||
// No caching of source maps.
|
||||
expect(environment.outputDir.childFile('flutter.js').readAsStringSync(),
|
||||
equals(flutter_js.generateFlutterJsFile()));
|
||||
}));
|
||||
|
||||
test('wasm build copies and generates specific files', () => testbed.run(() async {
|
||||
globals.fs.file('bin/cache/dart-sdk/bin/dart2wasm_runtime.mjs')
|
||||
.createSync(recursive: true);
|
||||
globals.fs.file('bin/cache/flutter_web_sdk/canvaskit/canvaskit.wasm')
|
||||
.createSync(recursive: true);
|
||||
|
||||
await WebBuiltInAssets(globals.fs, globals.cache, true).build(environment);
|
||||
|
||||
expect(environment.outputDir.childFile('dart2wasm_runtime.mjs').existsSync(), true);
|
||||
expect(environment.outputDir.childFile('main.dart.js').existsSync(), true);
|
||||
expect(environment.outputDir.childDirectory('canvaskit')
|
||||
.childFile('canvaskit.wasm')
|
||||
.existsSync(), true);
|
||||
}));
|
||||
}
|
||||
|
|
|
@ -0,0 +1,60 @@
|
|||
// 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:io';
|
||||
|
||||
import 'package:file_testing/file_testing.dart';
|
||||
import 'package:flutter_tools/src/base/file_system.dart';
|
||||
|
||||
import '../src/common.dart';
|
||||
import 'test_utils.dart';
|
||||
|
||||
void main() {
|
||||
late Directory tempDir;
|
||||
late String flutterBin;
|
||||
late Directory exampleAppDir;
|
||||
|
||||
setUp(() async {
|
||||
tempDir = createResolvedTempDirectorySync('flutter_web_wasm_test.');
|
||||
flutterBin = fileSystem.path.join(
|
||||
getFlutterRoot(),
|
||||
'bin',
|
||||
'flutter',
|
||||
);
|
||||
exampleAppDir = tempDir.childDirectory('test_app');
|
||||
|
||||
processManager.runSync(<String>[
|
||||
flutterBin,
|
||||
'create',
|
||||
'--platforms=web',
|
||||
'test_app',
|
||||
], workingDirectory: tempDir.path);
|
||||
});
|
||||
|
||||
test('building web with --wasm produces expected files', () async {
|
||||
final ProcessResult result = processManager.runSync(<String>[
|
||||
flutterBin,
|
||||
'build',
|
||||
'web',
|
||||
'--wasm',
|
||||
], workingDirectory: exampleAppDir.path);
|
||||
expect(result.exitCode, 0);
|
||||
|
||||
final Directory appBuildDir = fileSystem.directory(fileSystem.path.join(
|
||||
exampleAppDir.path,
|
||||
'build',
|
||||
'web_wasm'
|
||||
));
|
||||
for (final String filename in const <String>[
|
||||
'dart2wasm_runtime.mjs',
|
||||
'flutter.js',
|
||||
'flutter_service_worker.js',
|
||||
'index.html',
|
||||
'main.dart.wasm',
|
||||
'main.dart.js',
|
||||
]) {
|
||||
expect(appBuildDir.childFile(filename), exists);
|
||||
}
|
||||
});
|
||||
}
|
Loading…
Reference in a new issue