Unverified Commit 9bc56566 authored by Jonah Williams's avatar Jonah Williams Committed by GitHub

Wire dart2js through flutter tool, add compilation test (#27668)

parent 8661d8ae
......@@ -167,10 +167,22 @@ Future<void> _runBuildTests() async {
await _flutterBuildApk(path);
await _flutterBuildIpa(path);
}
await _flutterBuildDart2js(path.join('dev', 'integration_tests', 'web'));
print('${bold}DONE: All build tests successful.$reset');
}
Future<void> _flutterBuildDart2js(String relativePathToApplication) async {
print('Running Dart2JS build tests...');
await runCommand(flutter,
<String>['build', 'web', '-v'],
workingDirectory: path.join(flutterRoot, relativePathToApplication),
expectNonZeroExit: false,
timeout: _kShortTimeout,
);
print('Done.');
}
Future<void> _flutterBuildAot(String relativePathToApplication) async {
print('Running AOT build tests...');
await runCommand(flutter,
......
// 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/widgets.dart';
void main() {
runApp(Center(
// Can remove when https://github.com/dart-lang/sdk/issues/35801 is fixed.
// ignore: prefer_const_constructors
child: Text('Hello, World', textDirection: TextDirection.ltr),
));
}
name: web_integration
description: Integration test for web compilation.
environment:
# The pub client defaults to an <2.0.0 sdk constraint which we need to explicitly overwrite.
sdk: ">=2.0.0-dev.68.0 <3.0.0"
dependencies:
flutter:
sdk: flutter
collection: 1.14.11 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
meta: 1.1.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
typed_data: 1.1.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
vector_math: 2.0.8 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
# PUBSPEC CHECKSUM: d53c
......@@ -8,6 +8,7 @@ import 'dart:collection';
// COMMON SIGNATURES
export 'dart:ui' show VoidCallback;
export 'bitfield.dart' if (dart.library.html) 'bitfield_unsupported.dart';
/// Signature for callbacks that report that an underlying value has changed.
///
......@@ -66,69 +67,6 @@ typedef AsyncValueSetter<T> = Future<void> Function(T value);
/// * [AsyncValueSetter], the setter equivalent of this signature.
typedef AsyncValueGetter<T> = Future<T> Function();
// BITFIELD
/// The largest SMI value.
///
/// See <https://www.dartlang.org/articles/numeric-computation/#smis-and-mints>
const int kMaxUnsignedSMI = 0x3FFFFFFFFFFFFFFF;
/// A BitField over an enum (or other class whose values implement "index").
/// Only the first 62 values of the enum can be used as indices.
class BitField<T extends dynamic> {
/// Creates a bit field of all zeros.
///
/// The given length must be at most 62.
BitField(this._length)
: assert(_length <= _smiBits),
_bits = _allZeros;
/// Creates a bit field filled with a particular value.
///
/// If the value argument is true, the bits are filled with ones. Otherwise,
/// the bits are filled with zeros.
///
/// The given length must be at most 62.
BitField.filled(this._length, bool value)
: assert(_length <= _smiBits),
_bits = value ? _allOnes : _allZeros;
final int _length;
int _bits;
static const int _smiBits = 62; // see https://www.dartlang.org/articles/numeric-computation/#smis-and-mints
static const int _allZeros = 0;
static const int _allOnes = kMaxUnsignedSMI; // 2^(_kSMIBits+1)-1
/// Returns whether the bit with the given index is set to one.
bool operator [](T index) {
assert(index.index < _length);
return (_bits & 1 << index.index) > 0;
}
/// Sets the bit with the given index to the given value.
///
/// If value is true, the bit with the given index is set to one. Otherwise,
/// the bit is set to zero.
void operator []=(T index, bool value) {
assert(index.index < _length);
if (value)
_bits = _bits | (1 << index.index);
else
_bits = _bits & ~(1 << index.index);
}
/// Sets all the bits to the given value.
///
/// If the value is true, the bits are all set to one. Otherwise, the bits are
/// all set to zero. Defaults to setting all the bits to zero.
void reset([ bool value = false ]) {
_bits = value ? _allOnes : _allZeros;
}
}
// LAZY CACHING ITERATOR
/// A lazy caching version of [Iterable].
......
// Copyright 2015 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.
/// The largest SMI value.
///
/// See <https://www.dartlang.org/articles/numeric-computation/#smis-and-mints>
///
/// When compiling to JavaScript, this value is not supported since it is
/// larger than the maximum safe 32bit integer.
const int kMaxUnsignedSMI = 0x3FFFFFFFFFFFFFFF;
/// A BitField over an enum (or other class whose values implement "index").
/// Only the first 62 values of the enum can be used as indices.
///
/// When compiling to JavaScript, this class is not supported.
class BitField<T extends dynamic> {
/// Creates a bit field of all zeros.
///
/// The given length must be at most 62.
BitField(this._length)
: assert(_length <= _smiBits),
_bits = _allZeros;
/// Creates a bit field filled with a particular value.
///
/// If the value argument is true, the bits are filled with ones. Otherwise,
/// the bits are filled with zeros.
///
/// The given length must be at most 62.
BitField.filled(this._length, bool value)
: assert(_length <= _smiBits),
_bits = value ? _allOnes : _allZeros;
final int _length;
int _bits;
static const int _smiBits = 62; // see https://www.dartlang.org/articles/numeric-computation/#smis-and-mints
static const int _allZeros = 0;
static const int _allOnes = kMaxUnsignedSMI; // 2^(_kSMIBits+1)-1
/// Returns whether the bit with the given index is set to one.
bool operator [](T index) {
assert(index.index < _length);
return (_bits & 1 << index.index) > 0;
}
/// Sets the bit with the given index to the given value.
///
/// If value is true, the bit with the given index is set to one. Otherwise,
/// the bit is set to zero.
void operator []=(T index, bool value) {
assert(index.index < _length);
if (value)
_bits = _bits | (1 << index.index);
else
_bits = _bits & ~(1 << index.index);
}
/// Sets all the bits to the given value.
///
/// If the value is true, the bits are all set to one. Otherwise, the bits are
/// all set to zero. Defaults to setting all the bits to zero.
void reset([ bool value = false ]) {
_bits = value ? _allOnes : _allZeros;
}
}
\ No newline at end of file
// 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.
/// Unsupported.
const int kMaxUnsignedSMI = 0;
/// Unsupported.
class BitField<T extends dynamic> {
/// Unsupported.
// Ignored so that both bitfield implementations have the same API.
// ignore: avoid_unused_constructor_parameters
BitField(int length);
/// Unsupported.
// Ignored so that both bitfield implementations have the same API.
// ignore: avoid_unused_constructor_parameters
BitField.filled(int length, bool value);
/// Unsupported.
bool operator [](T index) {
throw UnsupportedError('Not supported when compiling to JavaScript');
}
/// Unsupported.
void operator []=(T index, bool value) {
throw UnsupportedError('Not supported when compiling to JavaScript');
}
/// Unsupported.
void reset([ bool value = false ]) {
throw UnsupportedError('Not supported when compiling to JavaScript');
}
}
/// The largest SMI value.
///
/// See <https://www.dartlang.org/articles/numeric-computation/#smis-and-mints>
///
/// When compiling to JavaScript, this value is not supported since it is
/// larger than the maximum safe 32bit integer.
const int kMaxUnsignedSMI = 0x3FFFFFFFFFFFFFFF;
\ No newline at end of file
/// The largest SMI value.
///
/// See <https://www.dartlang.org/articles/numeric-computation/#smis-and-mints>
///
/// When compiling to JavaScript, this value is not supported since it is
/// larger than the maximum safe 32bit integer.
const int kMaxUnsignedSMI = 0;
\ No newline at end of file
......@@ -49,6 +49,7 @@ class ApplicationPackageFactory {
case TargetPlatform.linux_x64:
case TargetPlatform.windows_x64:
case TargetPlatform.fuchsia:
case TargetPlatform.web:
return null;
}
assert(platform != null);
......@@ -352,6 +353,7 @@ class ApplicationPackageStore {
case TargetPlatform.windows_x64:
case TargetPlatform.fuchsia:
case TargetPlatform.tester:
case TargetPlatform.web:
return null;
}
return null;
......
......@@ -26,6 +26,8 @@ enum Artifact {
frontendServerSnapshotForEngineDartSdk,
engineDartSdkPath,
engineDartBinary,
dart2jsSnapshot,
kernelWorkerSnapshot,
}
String _artifactToFileName(Artifact artifact, [TargetPlatform platform, BuildMode mode]) {
......@@ -70,6 +72,10 @@ String _artifactToFileName(Artifact artifact, [TargetPlatform platform, BuildMod
return 'frontend_server.dart.snapshot';
case Artifact.engineDartBinary:
return 'dart';
case Artifact.dart2jsSnapshot:
return 'flutter_dart2js.dart.snapshot';
case Artifact.kernelWorkerSnapshot:
return 'flutter_kernel_worker.dart.snapshot';
}
assert(false, 'Invalid artifact $artifact.');
return null;
......@@ -121,6 +127,7 @@ class CachedArtifacts extends Artifacts {
case TargetPlatform.windows_x64:
case TargetPlatform.fuchsia:
case TargetPlatform.tester:
case TargetPlatform.web:
return _getHostArtifactPath(artifact, platform, mode);
}
assert(false, 'Invalid platform $platform.');
......@@ -183,13 +190,17 @@ class CachedArtifacts extends Artifacts {
case Artifact.engineDartSdkPath:
return dartSdkPath;
case Artifact.engineDartBinary:
return fs.path.join(dartSdkPath,'bin', _artifactToFileName(artifact));
return fs.path.join(dartSdkPath, 'bin', _artifactToFileName(artifact));
case Artifact.platformKernelDill:
return fs.path.join(_getFlutterPatchedSdkPath(), _artifactToFileName(artifact));
case Artifact.platformLibrariesJson:
return fs.path.join(_getFlutterPatchedSdkPath(), 'lib', _artifactToFileName(artifact));
case Artifact.flutterPatchedSdkPath:
return _getFlutterPatchedSdkPath();
case Artifact.dart2jsSnapshot:
return fs.path.join(dartSdkPath, 'bin', 'snapshots', _artifactToFileName(artifact));
case Artifact.kernelWorkerSnapshot:
return fs.path.join(dartSdkPath, 'bin', 'snapshots', _artifactToFileName(artifact));
default:
assert(false, 'Artifact $artifact not available for platform $platform.');
return null;
......@@ -205,6 +216,7 @@ class CachedArtifacts extends Artifacts {
case TargetPlatform.windows_x64:
case TargetPlatform.fuchsia:
case TargetPlatform.tester:
case TargetPlatform.web:
assert(mode == null, 'Platform $platform does not support different build modes.');
return fs.path.join(engineDir, platformName);
case TargetPlatform.ios:
......@@ -265,6 +277,10 @@ class LocalEngineArtifacts extends Artifacts {
return fs.path.join(_hostEngineOutPath, 'dart-sdk');
case Artifact.engineDartBinary:
return fs.path.join(_hostEngineOutPath, 'dart-sdk', 'bin', _artifactToFileName(artifact));
case Artifact.dart2jsSnapshot:
return fs.path.join(_hostEngineOutPath, 'dart-sdk', 'bin', 'snapshots', _artifactToFileName(artifact));
case Artifact.kernelWorkerSnapshot:
return fs.path.join(_hostEngineOutPath, 'dart-sdk', 'bin', 'snapshots', _artifactToFileName(artifact));
}
assert(false, 'Invalid artifact $artifact.');
return null;
......
......@@ -266,6 +266,7 @@ enum TargetPlatform {
windows_x64,
fuchsia,
tester,
web,
}
/// iOS target device architecture.
......@@ -325,6 +326,8 @@ String getNameForTargetPlatform(TargetPlatform platform) {
return 'fuchsia';
case TargetPlatform.tester:
return 'flutter-tester';
case TargetPlatform.web:
return 'web';
}
assert(false);
return null;
......@@ -346,6 +349,8 @@ TargetPlatform getTargetPlatformForName(String platform) {
return TargetPlatform.darwin_x64;
case 'linux-x64':
return TargetPlatform.linux_x64;
case 'web':
return TargetPlatform.web;
}
assert(platform != null);
return null;
......@@ -400,6 +405,11 @@ String getIosBuildDirectory() {
return fs.path.join(getBuildDirectory(), 'ios');
}
/// Returns the web build output directory.
String getWebBuildDirectory() {
return fs.path.join(getBuildDirectory(), 'web');
}
/// Returns directory used by incremental compiler (IKG - incremental kernel
/// generator) to store cached intermediate state.
String getIncrementalCompilerByteStoreDirectory() {
......
......@@ -11,6 +11,7 @@ import 'build_appbundle.dart';
import 'build_bundle.dart';
import 'build_flx.dart';
import 'build_ios.dart';
import 'build_web.dart';
class BuildCommand extends FlutterCommand {
BuildCommand({bool verboseHelp = false}) {
......@@ -20,6 +21,7 @@ class BuildCommand extends FlutterCommand {
addSubcommand(BuildIOSCommand());
addSubcommand(BuildFlxCommand());
addSubcommand(BuildBundleCommand(verboseHelp: verboseHelp));
addSubcommand(BuildWebCommand());
}
@override
......
// 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 'dart:async';
import '../base/logger.dart';
import '../build_info.dart';
import '../globals.dart';
import '../runner/flutter_command.dart' show ExitStatus, FlutterCommandResult;
import '../web/compile.dart';
import 'build.dart';
class BuildWebCommand extends BuildSubCommand {
BuildWebCommand() {
usesTargetOption();
usesPubOption();
defaultBuildMode = BuildMode.release;
}
@override
final String name = 'web';
@override
bool get hidden => true;
@override
final String description = '(EXPERIMENTAL) build a web application bundle.';
@override
Future<FlutterCommandResult> runCommand() async {
final String target = argResults['target'];
final Status status = logger.startProgress('Compiling $target to JavaScript...', timeout: null);
final int result = await webCompiler.compile(target: target);
status.stop();
return FlutterCommandResult(result == 0 ? ExitStatus.success : ExitStatus.fail);
}
}
......@@ -39,6 +39,7 @@ import 'macos/macos_workflow.dart';
import 'run_hot.dart';
import 'usage.dart';
import 'version.dart';
import 'web/compile.dart';
import 'windows/windows_workflow.dart';
Future<T> runInContext<T>(
......@@ -91,6 +92,7 @@ Future<T> runInContext<T>(
Usage: () => Usage(),
UserMessages: () => UserMessages(),
WindowsWorkflow: () => const WindowsWorkflow(),
WebCompiler: () => const WebCompiler(),
Xcode: () => Xcode(),
XcodeProjectInterpreter: () => XcodeProjectInterpreter(),
},
......
// 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:meta/meta.dart';
import '../artifacts.dart';
import '../base/common.dart';
import '../base/context.dart';
import '../base/file_system.dart';
import '../base/io.dart';
import '../base/process_manager.dart';
import '../build_info.dart';
import '../convert.dart';
import '../globals.dart';
/// The [WebCompiler] instance.
WebCompiler get webCompiler => context[WebCompiler];
/// A wrapper around dart2js for web compilation.
class WebCompiler {
const WebCompiler();
/// Compile `target` using dart2js.
///
/// `minify` controls whether minifaction of the source is enabled. Defaults to `true`.
/// `enabledAssertions` controls whether assertions are enabled. Defaults to `false`.
Future<int> compile({@required String target, bool minify = true, bool enabledAssertions = false}) async {
final String engineDartPath = artifacts.getArtifactPath(Artifact.engineDartBinary);
final String dart2jsPath = artifacts.getArtifactPath(Artifact.dart2jsSnapshot);
final String flutterPatchedSdkPath = artifacts.getArtifactPath(Artifact.flutterPatchedSdkPath);
final String librariesPath = fs.path.join(flutterPatchedSdkPath, 'libraries.json');
final Directory outputDir = fs.directory(getWebBuildDirectory());
if (!outputDir.existsSync()) {
outputDir.createSync(recursive: true);
}
final String outputPath = fs.path.join(outputDir.path, 'main.dart.js');
if (!processManager.canRun(engineDartPath)) {
throwToolExit('Unable to find Dart binary at $engineDartPath');
}
final List<String> command = <String>[
engineDartPath,
dart2jsPath,
target,
'-o',
'$outputPath',
'--libraries-spec=$librariesPath',
'--platform-binaries=$flutterPatchedSdkPath',
];
if (minify) {
command.add('-m');
}
if (enabledAssertions) {
command.add('--enable-asserts');
}
printTrace(command.join(' '));
final Process result = await processManager.start(command);
result
.stdout
.transform(utf8.decoder)
.transform(const LineSplitter())
.listen(printStatus);
result
.stderr
.transform(utf8.decoder)
.transform(const LineSplitter())
.listen(printError);
return result.exitCode;
}
}
// 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/artifacts.dart';
import 'package:flutter_tools/src/base/file_system.dart';
import 'package:flutter_tools/src/base/io.dart';
import 'package:flutter_tools/src/base/logger.dart';
import 'package:flutter_tools/src/globals.dart';
import 'package:flutter_tools/src/web/compile.dart';
import 'package:mockito/mockito.dart';
import 'package:process/process.dart';
import '../src/context.dart';
void main() {
final MockProcessManager mockProcessManager = MockProcessManager();
final MockProcess mockProcess = MockProcess();
final BufferLogger mockLogger = BufferLogger();
testUsingContext('invokes dart2js with correct arguments', () async {
const WebCompiler webCompiler = WebCompiler();
final String engineDartPath = artifacts.getArtifactPath(Artifact.engineDartBinary);
final String dart2jsPath = artifacts.getArtifactPath(Artifact.dart2jsSnapshot);
final String flutterPatchedSdkPath = artifacts.getArtifactPath(Artifact.flutterPatchedSdkPath);
final String librariesPath = fs.path.join(flutterPatchedSdkPath, 'libraries.json');
when(mockProcess.stdout).thenAnswer((Invocation invocation) => const Stream<List<int>>.empty());
when(mockProcess.stderr).thenAnswer((Invocation invocation) => const Stream<List<int>>.empty());
when(mockProcess.exitCode).thenAnswer((Invocation invocation) async => 0);
when(mockProcessManager.start(any)).thenAnswer((Invocation invocation) async => mockProcess);
when(mockProcessManager.canRun(engineDartPath)).thenReturn(true);
await webCompiler.compile(target: 'lib/main.dart');
final String outputPath = fs.path.join('build', 'web', 'main.dart.js');
verify(mockProcessManager.start(<String>[
engineDartPath,
dart2jsPath,
'lib/main.dart',
'-o',
outputPath,
'--libraries-spec=$librariesPath',
'--platform-binaries=$flutterPatchedSdkPath',
'-m',
])).called(1);
}, overrides: <Type, Generator>{
ProcessManager: () => mockProcessManager,
Logger: () => mockLogger,
});
}
class MockProcessManager extends Mock implements ProcessManager {}
class MockProcess extends Mock implements Process {}
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment