diff --git a/packages/flutter_tools/lib/src/build_runner/build_script.dart b/packages/flutter_tools/lib/src/build_runner/build_script.dart index 679cafa377..48bb8f293a 100644 --- a/packages/flutter_tools/lib/src/build_runner/build_script.dart +++ b/packages/flutter_tools/lib/src/build_runner/build_script.dart @@ -101,7 +101,11 @@ final List builders = [ [ (BuilderOptions options) { final bool hasPlugins = options.config['hasPlugins'] == true; - return FlutterWebShellBuilder(hasPlugins: hasPlugins); + final bool initializePlatform = options.config['initializePlatform'] == true; + return FlutterWebShellBuilder( + hasPlugins: hasPlugins, + initializePlatform: initializePlatform, + ); } ], core.toRoot(), @@ -360,10 +364,13 @@ void setStackTraceMapper(StackTraceMapper mapper) { /// A shell builder which generates the web specific entrypoint. class FlutterWebShellBuilder implements Builder { - const FlutterWebShellBuilder({this.hasPlugins = false}); + const FlutterWebShellBuilder({this.hasPlugins = false, this.initializePlatform = true}); final bool hasPlugins; + /// Whether to call webOnlyInitializePlatform. + final bool initializePlatform; + @override Future build(BuildStep buildStep) async { final AssetId dartEntrypointId = buildStep.inputId; @@ -383,7 +390,9 @@ import "${path.url.basename(buildStep.inputId.path)}" as entrypoint; Future main() async { registerPlugins(webPluginRegistry); - await ui.webOnlyInitializePlatform(); + if ($initializePlatform) { + await ui.webOnlyInitializePlatform(); + } entrypoint.main(); } '''); @@ -394,7 +403,9 @@ import 'dart:ui' as ui; import "${path.url.basename(buildStep.inputId.path)}" as entrypoint; Future main() async { - await ui.webOnlyInitializePlatform(); + if ($initializePlatform) { + await ui.webOnlyInitializePlatform(); + } entrypoint.main(); } '''); diff --git a/packages/flutter_tools/lib/src/build_runner/resident_web_runner.dart b/packages/flutter_tools/lib/src/build_runner/resident_web_runner.dart index 6943aeb429..a5d5ee89d3 100644 --- a/packages/flutter_tools/lib/src/build_runner/resident_web_runner.dart +++ b/packages/flutter_tools/lib/src/build_runner/resident_web_runner.dart @@ -168,6 +168,7 @@ class ResidentWebRunner extends ResidentRunner { target: target, flutterProject: flutterProject, buildInfo: debuggingOptions.buildInfo, + initializePlatform: debuggingOptions.initializePlatform, hostname: debuggingOptions.hostname, port: debuggingOptions.port, skipDwds: device is WebServerDevice, diff --git a/packages/flutter_tools/lib/src/build_runner/web_compilation_delegate.dart b/packages/flutter_tools/lib/src/build_runner/web_compilation_delegate.dart index 4425a726eb..4d428ca275 100644 --- a/packages/flutter_tools/lib/src/build_runner/web_compilation_delegate.dart +++ b/packages/flutter_tools/lib/src/build_runner/web_compilation_delegate.dart @@ -16,6 +16,9 @@ import 'package:path/path.dart' as path; import '../base/file_system.dart'; import '../build_info.dart'; import '../convert.dart'; +import '../platform_plugins.dart'; +import '../plugins.dart'; +import '../project.dart'; import '../web/compile.dart'; import 'web_fs.dart'; @@ -28,18 +31,23 @@ class BuildRunnerWebCompilationProxy extends WebCompilationProxy { Directory projectDirectory, String testOutputDir, BuildMode mode, - String projectName + String projectName, + bool initializePlatform, }) async { // Create the .dart_tool directory if it doesn't exist. projectDirectory .childDirectory('.dart_tool') .createSync(); + final FlutterProject flutterProject = FlutterProject.fromDirectory(projectDirectory); + final bool hasWebPlugins = findPlugins(flutterProject) + .any((Plugin p) => p.platforms.containsKey(WebPlugin.kConfigKey)); final BuildDaemonClient client = await buildDaemonCreator.startBuildDaemon( projectDirectory.path, release: mode == BuildMode.release, profile: mode == BuildMode.profile, - hasPlugins: false, + hasPlugins: hasWebPlugins, includeTests: true, + initializePlatform: initializePlatform, ); client.startBuild(); bool success = true; diff --git a/packages/flutter_tools/lib/src/build_runner/web_fs.dart b/packages/flutter_tools/lib/src/build_runner/web_fs.dart index 9e2dd700e8..e7ce54728c 100644 --- a/packages/flutter_tools/lib/src/build_runner/web_fs.dart +++ b/packages/flutter_tools/lib/src/build_runner/web_fs.dart @@ -75,6 +75,7 @@ typedef WebFsFactory = Future Function({ @required FlutterProject flutterProject, @required BuildInfo buildInfo, @required bool skipDwds, + @required bool initializePlatform, @required String hostname, @required String port, }); @@ -142,6 +143,7 @@ class WebFs { @required FlutterProject flutterProject, @required BuildInfo buildInfo, @required bool skipDwds, + @required bool initializePlatform, @required String hostname, @required String port, }) async { @@ -149,11 +151,16 @@ class WebFs { if (!flutterProject.dartTool.existsSync()) { flutterProject.dartTool.createSync(recursive: true); } - - final bool hasWebPlugins = findPlugins(flutterProject).any((Plugin p) => p.platforms.containsKey(WebPlugin.kConfigKey)); + final bool hasWebPlugins = findPlugins(flutterProject) + .any((Plugin p) => p.platforms.containsKey(WebPlugin.kConfigKey)); // Start the build daemon and run an initial build. final BuildDaemonClient client = await buildDaemonCreator - .startBuildDaemon(fs.currentDirectory.path, release: buildInfo.isRelease, profile: buildInfo.isProfile, hasPlugins: hasWebPlugins); + .startBuildDaemon(fs.currentDirectory.path, + release: buildInfo.isRelease, + profile: buildInfo.isProfile, + hasPlugins: hasWebPlugins, + initializePlatform: initializePlatform, + ); client.startBuild(); // Only provide relevant build results final Stream filteredBuildResults = client.buildResults @@ -340,11 +347,14 @@ class BuildDaemonCreator { static const String _ignoredLine3 = 'have your dependencies specified fully in your pubspec.yaml'; /// Start a build daemon and register the web targets. + /// + /// [initializePlatform] controls whether we should invoke [webOnlyInitializePlatform]. Future startBuildDaemon(String workingDirectory, { bool release = false, bool profile = false, bool hasPlugins = false, bool includeTests = false, + bool initializePlatform = true, }) async { try { final BuildDaemonClient client = await _connectClient( @@ -352,6 +362,7 @@ class BuildDaemonCreator { release: release, profile: profile, hasPlugins: hasPlugins, + initializePlatform: initializePlatform, ); _registerBuildTargets(client, includeTests); return client; @@ -384,7 +395,7 @@ class BuildDaemonCreator { Future _connectClient( String workingDirectory, - { bool release, bool profile, bool hasPlugins } + { bool release, bool profile, bool hasPlugins, bool initializePlatform } ) { final String flutterToolsPackages = fs.path.join(Cache.flutterRoot, 'packages', 'flutter_tools', '.packages'); final String buildScript = fs.path.join(Cache.flutterRoot, 'packages', 'flutter_tools', 'lib', 'src', 'build_runner', 'build_script.dart'); @@ -406,6 +417,7 @@ class BuildDaemonCreator { '--define', 'flutter_tools:entrypoint=profile=$profile', '--define', 'flutter_tools:shell=flutterWebSdk=$flutterWebSdk', '--define', 'flutter_tools:shell=hasPlugins=$hasPlugins', + '--define', 'flutter_tools:shell=initializePlatform=$initializePlatform' ], logHandler: (ServerLog serverLog) { switch (serverLog.level) { diff --git a/packages/flutter_tools/lib/src/commands/build_web.dart b/packages/flutter_tools/lib/src/commands/build_web.dart index 16ade17e2e..a443d318bf 100644 --- a/packages/flutter_tools/lib/src/commands/build_web.dart +++ b/packages/flutter_tools/lib/src/commands/build_web.dart @@ -18,6 +18,12 @@ class BuildWebCommand extends BuildSubCommand { usesTargetOption(); usesPubOption(); addBuildModeFlags(); + argParser.addFlag('web-initialize-platform', + defaultsTo: true, + negatable: true, + hide: true, + help: 'Whether to automatically invoke webOnlyInitializePlatform.', + ); } @override @@ -44,7 +50,7 @@ class BuildWebCommand extends BuildSubCommand { final FlutterProject flutterProject = FlutterProject.current(); final String target = argResults['target']; final BuildInfo buildInfo = getBuildInfo(); - await buildWeb(flutterProject, target, buildInfo); + await buildWeb(flutterProject, target, buildInfo, argResults['web-initialize-platform']); return null; } } diff --git a/packages/flutter_tools/lib/src/commands/run.dart b/packages/flutter_tools/lib/src/commands/run.dart index 74fce6a9da..4bcb839041 100644 --- a/packages/flutter_tools/lib/src/commands/run.dart +++ b/packages/flutter_tools/lib/src/commands/run.dart @@ -169,6 +169,12 @@ class RunCommand extends RunCommandBase { hide: !verboseHelp, help: 'No longer require an authentication code to connect to the VM ' 'service (not recommended).') + ..addFlag('web-initialize-platform', + negatable: true, + defaultsTo: true, + hide: true, + help: 'Whether to automatically invoke webOnlyInitializePlatform.' + ) ..addOption(FlutterOptions.kExtraFrontEndOptions, hide: true) ..addOption(FlutterOptions.kExtraGenSnapshotOptions, hide: true) ..addMultiOption(FlutterOptions.kEnableExperiment, @@ -274,7 +280,10 @@ class RunCommand extends RunCommandBase { DebuggingOptions _createDebuggingOptions() { final BuildInfo buildInfo = getBuildInfo(); if (buildInfo.isRelease) { - return DebuggingOptions.disabled(buildInfo); + return DebuggingOptions.disabled( + buildInfo, + initializePlatform: argResults['web-initialize-platform'], + ); } else { return DebuggingOptions.enabled( buildInfo, @@ -289,6 +298,7 @@ class RunCommand extends RunCommandBase { dumpSkpOnShaderCompilation: argResults['dump-skp-on-shader-compilation'], observatoryPort: observatoryPort, verboseSystemLogs: argResults['verbose-system-logs'], + initializePlatform: argResults['web-initialize-platform'], hostname: featureFlags.isWebEnabled ? argResults['web-hostname'] : '', port: featureFlags.isWebEnabled ? argResults['web-port'] : '', ); diff --git a/packages/flutter_tools/lib/src/device.dart b/packages/flutter_tools/lib/src/device.dart index bcd710e628..09f6cdba84 100644 --- a/packages/flutter_tools/lib/src/device.dart +++ b/packages/flutter_tools/lib/src/device.dart @@ -484,11 +484,12 @@ class DebuggingOptions { this.useTestFonts = false, this.verboseSystemLogs = false, this.observatoryPort, + this.initializePlatform = true, this.hostname, this.port, }) : debuggingEnabled = true; - DebuggingOptions.disabled(this.buildInfo) + DebuggingOptions.disabled(this.buildInfo, { this.initializePlatform = true }) : debuggingEnabled = false, useTestFonts = false, startPaused = false, @@ -517,6 +518,8 @@ class DebuggingOptions { final bool dumpSkpOnShaderCompilation; final bool useTestFonts; final bool verboseSystemLogs; + /// Whether to invoke webOnlyInitializePlatform in Flutter for web. + final bool initializePlatform; final int observatoryPort; final String port; final String hostname; diff --git a/packages/flutter_tools/lib/src/test/runner.dart b/packages/flutter_tools/lib/src/test/runner.dart index dc83d9bf77..67aed19b00 100644 --- a/packages/flutter_tools/lib/src/test/runner.dart +++ b/packages/flutter_tools/lib/src/test/runner.dart @@ -70,6 +70,7 @@ Future runTests( projectDirectory: flutterProject.directory, testOutputDir: tempBuildDir, projectName: flutterProject.manifest.appName, + initializePlatform: true, ); if (!result) { throwToolExit('Failed to compile tests'); diff --git a/packages/flutter_tools/lib/src/web/compile.dart b/packages/flutter_tools/lib/src/web/compile.dart index f74985147f..e40a37d123 100644 --- a/packages/flutter_tools/lib/src/web/compile.dart +++ b/packages/flutter_tools/lib/src/web/compile.dart @@ -18,7 +18,7 @@ import '../reporting/reporting.dart'; /// The [WebCompilationProxy] instance. WebCompilationProxy get webCompilationProxy => context.get(); -Future buildWeb(FlutterProject flutterProject, String target, BuildInfo buildInfo) async { +Future buildWeb(FlutterProject flutterProject, String target, BuildInfo buildInfo, bool initializePlatform) async { if (!flutterProject.web.existsSync()) { throwToolExit('Missing index.html.'); } @@ -32,6 +32,7 @@ Future buildWeb(FlutterProject flutterProject, String target, BuildInfo bu projectDirectory: FlutterProject.current().directory, mode: buildInfo.mode, projectName: flutterProject.manifest.appName, + initializePlatform: initializePlatform, ); if (result) { // Places assets adjacent to the web stuff. @@ -84,6 +85,7 @@ class WebCompilationProxy { @required String projectName, String testOutputDir, BuildMode mode, + bool initializePlatform, }) async { throw UnimplementedError(); } diff --git a/packages/flutter_tools/test/general.shard/build_runner/build_script_test.dart b/packages/flutter_tools/test/general.shard/build_runner/build_script_test.dart new file mode 100644 index 0000000000..6fc186f3b1 --- /dev/null +++ b/packages/flutter_tools/test/general.shard/build_runner/build_script_test.dart @@ -0,0 +1,74 @@ +// 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:build/build.dart'; +import 'package:flutter_tools/src/build_runner/build_script.dart'; +import 'package:mockito/mockito.dart'; + +import '../../src/common.dart'; + +void main() { + MockBuildStep mockBuildStep; + AssetId inputId; + + setUp(() { + mockBuildStep = MockBuildStep(); + inputId = AssetId('hello_world', 'lib/main.dart'); + when(mockBuildStep.inputId).thenReturn(inputId); + when(mockBuildStep.readAsString(any)).thenAnswer((Invocation invocation) async { + return 'void main() { }'; + }); + + }); + + test('FlutterWebShellBuilder correctly configures platform', () async { + const FlutterWebShellBuilder builder = FlutterWebShellBuilder( + hasPlugins: false, + initializePlatform: true, + ); + + await builder.build(mockBuildStep); + + verify(mockBuildStep.writeAsString(any, argThat(contains('if (true) ' + '{\n await ui.webOnlyInitializePlatform')))).called(1); + }); + + test('FlutterWebShellBuilder correctly configures does not platform', () async { + const FlutterWebShellBuilder builder = FlutterWebShellBuilder( + hasPlugins: false, + initializePlatform: false, + ); + + await builder.build(mockBuildStep); + + verify(mockBuildStep.writeAsString(any, argThat(contains('if (false) ' + '{\n await ui.webOnlyInitializePlatform')))).called(1); + }); + + test('FlutterWebShellBuilder correctly configures plugins', () async { + const FlutterWebShellBuilder builder = FlutterWebShellBuilder( + hasPlugins: true, + initializePlatform: true, + ); + + await builder.build(mockBuildStep); + + verify(mockBuildStep.writeAsString(any, + argThat(contains('registerPlugins(webPluginRegistry)')))).called(1); + }); + + test('FlutterWebShellBuilder correctly does not configure plugins', () async { + const FlutterWebShellBuilder builder = FlutterWebShellBuilder( + hasPlugins: false, + initializePlatform: true, + ); + + await builder.build(mockBuildStep); + + verify(mockBuildStep.writeAsString(any, + argThat(isNot(contains('registerPlugins(webPluginRegistry)'))))).called(1); + }); +} + +class MockBuildStep extends Mock implements BuildStep {} diff --git a/packages/flutter_tools/test/general.shard/commands/build_web_test.dart b/packages/flutter_tools/test/general.shard/commands/build_web_test.dart index dab520ef47..df62a962d4 100644 --- a/packages/flutter_tools/test/general.shard/commands/build_web_test.dart +++ b/packages/flutter_tools/test/general.shard/commands/build_web_test.dart @@ -43,7 +43,8 @@ void main() { when(mockWebCompilationProxy.initialize( projectName: anyNamed('projectName'), projectDirectory: anyNamed('projectDirectory'), - mode: anyNamed('mode') + mode: anyNamed('mode'), + initializePlatform: anyNamed('initializePlatform') )).thenAnswer((Invocation invocation) { final String path = fs.path.join('.dart_tool', 'build', 'flutter_web', 'foo', 'lib', 'main_web_entrypoint.dart.js'); fs.file(path).createSync(recursive: true); @@ -65,6 +66,7 @@ void main() { FlutterProject.current(), fs.path.join('lib', 'main.dart'), BuildInfo.debug, + false, ), throwsA(isInstanceOf())); })); @@ -86,6 +88,7 @@ void main() { FlutterProject.current(), fs.path.join('lib', 'main.dart'), BuildInfo.debug, + false, ); })); diff --git a/packages/flutter_tools/test/general.shard/resident_web_runner_cold_test.dart b/packages/flutter_tools/test/general.shard/resident_web_runner_cold_test.dart index e96f352060..561d7559b6 100644 --- a/packages/flutter_tools/test/general.shard/resident_web_runner_cold_test.dart +++ b/packages/flutter_tools/test/general.shard/resident_web_runner_cold_test.dart @@ -43,6 +43,7 @@ void main() { @required FlutterProject flutterProject, @required BuildInfo buildInfo, @required bool skipDwds, + @required bool initializePlatform, @required String hostname, @required String port, }) async { @@ -102,7 +103,6 @@ void main() { } - class MockWebDevice extends Mock implements Device {} class MockBuildDaemonCreator extends Mock implements BuildDaemonCreator {} class MockFlutterWebFs extends Mock implements WebFs {} diff --git a/packages/flutter_tools/test/general.shard/resident_web_runner_test.dart b/packages/flutter_tools/test/general.shard/resident_web_runner_test.dart index 057ed4fcc7..d7d8d91d90 100644 --- a/packages/flutter_tools/test/general.shard/resident_web_runner_test.dart +++ b/packages/flutter_tools/test/general.shard/resident_web_runner_test.dart @@ -52,6 +52,7 @@ void main() { @required FlutterProject flutterProject, @required BuildInfo buildInfo, @required bool skipDwds, + @required bool initializePlatform, @required String hostname, @required String port, }) async { diff --git a/packages/flutter_tools/test/general.shard/web/web_fs_test.dart b/packages/flutter_tools/test/general.shard/web/web_fs_test.dart index 572da10352..aa8de897f0 100644 --- a/packages/flutter_tools/test/general.shard/web/web_fs_test.dart +++ b/packages/flutter_tools/test/general.shard/web/web_fs_test.dart @@ -26,20 +26,23 @@ void main() { MockHttpMultiServer mockHttpMultiServer; MockBuildDaemonClient mockBuildDaemonClient; MockOperatingSystemUtils mockOperatingSystemUtils; + bool lastInitializePlatform; dynamic lastAddress; int lastPort; setUp(() { lastAddress = null; lastPort = null; + lastInitializePlatform = null; mockBuildDaemonCreator = MockBuildDaemonCreator(); mockChromeLauncher = MockChromeLauncher(); mockHttpMultiServer = MockHttpMultiServer(); mockBuildDaemonClient = MockBuildDaemonClient(); mockOperatingSystemUtils = MockOperatingSystemUtils(); mockDwds = MockDwds(); - when(mockBuildDaemonCreator.startBuildDaemon(any, release: anyNamed('release'))) - .thenAnswer((Invocation _) async { + when(mockBuildDaemonCreator.startBuildDaemon(any, release: anyNamed('release'), initializePlatform: anyNamed('initializePlatform'))) + .thenAnswer((Invocation invocation) async { + lastInitializePlatform = invocation.namedArguments[#initializePlatform]; return mockBuildDaemonClient; }); when(mockOperatingSystemUtils.findFreePort()).thenAnswer((Invocation _) async { @@ -89,6 +92,7 @@ void main() { target: fs.path.join('lib', 'main.dart'), buildInfo: BuildInfo.debug, flutterProject: flutterProject, + initializePlatform: true, hostname: null, port: null, ); @@ -98,6 +102,27 @@ void main() { // .dart_tool directory is created. expect(flutterProject.dartTool.existsSync(), true); + expect(lastInitializePlatform, true); + })); + + test('Can create webFs from mocked interfaces with initializePlatform', () => testbed.run(() async { + final FlutterProject flutterProject = FlutterProject.current(); + await WebFs.start( + skipDwds: false, + target: fs.path.join('lib', 'main.dart'), + buildInfo: BuildInfo.debug, + flutterProject: flutterProject, + initializePlatform: false, + hostname: null, + port: null, + ); + + // The build daemon is told to build once. + verify(mockBuildDaemonClient.startBuild()).called(1); + + // .dart_tool directory is created. + expect(flutterProject.dartTool.existsSync(), true); + expect(lastInitializePlatform, false); })); test('Uses provided port number and hostname.', () => testbed.run(() async { @@ -107,6 +132,7 @@ void main() { target: fs.path.join('lib', 'main.dart'), buildInfo: BuildInfo.debug, flutterProject: flutterProject, + initializePlatform: false, hostname: 'foo', port: '1234', );