Skip to content

Commit 385728e

Browse files
authored
Add tools test for buildWeb compilation (#124179)
Add tools test for buildWeb compilation
1 parent 6058e95 commit 385728e

File tree

4 files changed

+249
-83
lines changed

4 files changed

+249
-83
lines changed

packages/flutter_tools/lib/src/commands/build_web.dart

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import '../base/file_system.dart';
77
import '../build_info.dart';
88
import '../build_system/targets/web.dart';
99
import '../features.dart';
10+
import '../globals.dart' as globals;
1011
import '../html_utils.dart';
1112
import '../project.dart';
1213
import '../runner/flutter_command.dart'
@@ -168,7 +169,14 @@ class BuildWebCommand extends BuildSubCommand {
168169
final String? outputDirectoryPath = stringArg('output');
169170

170171
displayNullSafetyMode(buildInfo);
171-
await buildWeb(
172+
final WebBuilder webBuilder = WebBuilder(
173+
logger: globals.logger,
174+
buildSystem: globals.buildSystem,
175+
fileSystem: globals.fs,
176+
flutterVersion: globals.flutterVersion,
177+
usage: globals.flutterUsage,
178+
);
179+
await webBuilder.buildWeb(
172180
flutterProject,
173181
target,
174182
buildInfo,

packages/flutter_tools/lib/src/isolated/resident_web_runner.dart

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -314,7 +314,14 @@ Please provide a valid TCP port (an integer between 0 and 65535, inclusive).
314314
device!.generator!.accept();
315315
cacheInitialDillCompilation();
316316
} else {
317-
await buildWeb(
317+
final WebBuilder webBuilder = WebBuilder(
318+
logger: _logger,
319+
buildSystem: globals.buildSystem,
320+
fileSystem: _fileSystem,
321+
flutterVersion: globals.flutterVersion,
322+
usage: globals.flutterUsage,
323+
);
324+
await webBuilder.buildWeb(
318325
flutterProject,
319326
target,
320327
debuggingOptions.buildInfo,
@@ -387,7 +394,14 @@ Please provide a valid TCP port (an integer between 0 and 65535, inclusive).
387394
}
388395
} else {
389396
try {
390-
await buildWeb(
397+
final WebBuilder webBuilder = WebBuilder(
398+
logger: _logger,
399+
buildSystem: globals.buildSystem,
400+
fileSystem: _fileSystem,
401+
flutterVersion: globals.flutterVersion,
402+
usage: globals.flutterUsage,
403+
);
404+
await webBuilder.buildWeb(
391405
flutterProject,
392406
target,
393407
debuggingOptions.buildInfo,

packages/flutter_tools/lib/src/web/compile.dart

Lines changed: 96 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -16,96 +16,112 @@ import '../globals.dart' as globals;
1616
import '../platform_plugins.dart';
1717
import '../plugins.dart';
1818
import '../project.dart';
19+
import '../reporting/reporting.dart';
20+
import '../version.dart';
1921
import 'migrations/scrub_generated_plugin_registrant.dart';
2022

2123
export '../build_system/targets/web.dart' show kDart2jsDefaultOptimizationLevel;
2224

23-
Future<void> buildWeb(
24-
FlutterProject flutterProject,
25-
String target,
26-
BuildInfo buildInfo,
27-
bool csp,
28-
String serviceWorkerStrategy,
29-
bool sourceMaps,
30-
bool nativeNullAssertions,
31-
bool isWasm, {
32-
String dart2jsOptimization = kDart2jsDefaultOptimizationLevel,
33-
String? baseHref,
34-
bool dumpInfo = false,
35-
bool noFrequencyBasedMinification = false,
36-
String? outputDirectoryPath,
37-
}) async {
38-
final bool hasWebPlugins = (await findPlugins(flutterProject))
39-
.any((Plugin p) => p.platforms.containsKey(WebPlugin.kConfigKey));
40-
final Directory outputDirectory = outputDirectoryPath == null
41-
? globals.fs.directory(getWebBuildDirectory(isWasm))
42-
: globals.fs.directory(outputDirectoryPath);
43-
outputDirectory.createSync(recursive: true);
25+
class WebBuilder {
26+
WebBuilder({
27+
required Logger logger,
28+
required BuildSystem buildSystem,
29+
required Usage usage,
30+
required FlutterVersion flutterVersion,
31+
required FileSystem fileSystem,
32+
}) : _logger = logger,
33+
_buildSystem = buildSystem,
34+
_flutterUsage = usage,
35+
_flutterVersion = flutterVersion,
36+
_fileSystem = fileSystem;
4437

45-
// The migrators to apply to a Web project.
46-
final List<ProjectMigrator> migrators = <ProjectMigrator>[
47-
ScrubGeneratedPluginRegistrant(flutterProject.web, globals.logger),
48-
];
38+
final Logger _logger;
39+
final BuildSystem _buildSystem;
40+
final Usage _flutterUsage;
41+
final FlutterVersion _flutterVersion;
42+
final FileSystem _fileSystem;
4943

50-
final ProjectMigration migration = ProjectMigration(migrators);
51-
migration.run();
44+
Future<void> buildWeb(
45+
FlutterProject flutterProject,
46+
String target,
47+
BuildInfo buildInfo,
48+
bool csp,
49+
String serviceWorkerStrategy,
50+
bool sourceMaps,
51+
bool nativeNullAssertions,
52+
bool isWasm, {
53+
String dart2jsOptimization = kDart2jsDefaultOptimizationLevel,
54+
String? baseHref,
55+
bool dumpInfo = false,
56+
bool noFrequencyBasedMinification = false,
57+
String? outputDirectoryPath,
58+
}) async {
59+
final bool hasWebPlugins =
60+
(await findPlugins(flutterProject)).any((Plugin p) => p.platforms.containsKey(WebPlugin.kConfigKey));
61+
final Directory outputDirectory = outputDirectoryPath == null
62+
? _fileSystem.directory(getWebBuildDirectory(isWasm))
63+
: _fileSystem.directory(outputDirectoryPath);
64+
outputDirectory.createSync(recursive: true);
5265

53-
final Status status = globals.logger.startProgress('Compiling $target for the Web...');
54-
final Stopwatch sw = Stopwatch()..start();
55-
try {
56-
final BuildResult result = await globals.buildSystem.build(
57-
WebServiceWorker(globals.fs, buildInfo.webRenderer, isWasm: isWasm),
58-
Environment(
59-
projectDir: globals.fs.currentDirectory,
60-
outputDir: outputDirectory,
61-
buildDir: flutterProject.directory
62-
.childDirectory('.dart_tool')
63-
.childDirectory('flutter_build'),
64-
defines: <String, String>{
65-
kTargetFile: target,
66-
kHasWebPlugins: hasWebPlugins.toString(),
67-
kCspMode: csp.toString(),
68-
if (baseHref != null)
69-
kBaseHref : baseHref,
70-
kSourceMapsEnabled: sourceMaps.toString(),
71-
kNativeNullAssertions: nativeNullAssertions.toString(),
72-
kServiceWorkerStrategy: serviceWorkerStrategy,
73-
kDart2jsOptimization: dart2jsOptimization,
74-
kDart2jsDumpInfo: dumpInfo.toString(),
75-
kDart2jsNoFrequencyBasedMinification: noFrequencyBasedMinification.toString(),
76-
...buildInfo.toBuildSystemEnvironment(),
77-
},
78-
artifacts: globals.artifacts!,
79-
fileSystem: globals.fs,
80-
logger: globals.logger,
81-
processManager: globals.processManager,
82-
platform: globals.platform,
83-
usage: globals.flutterUsage,
84-
cacheDir: globals.cache.getRoot(),
85-
engineVersion: globals.artifacts!.isLocalEngine
86-
? null
87-
: globals.flutterVersion.engineRevision,
88-
flutterRootDir: globals.fs.directory(Cache.flutterRoot),
89-
// Web uses a different Dart plugin registry.
90-
// https://github.com/flutter/flutter/issues/80406
91-
generateDartPluginRegistry: false,
92-
));
93-
if (!result.success) {
94-
for (final ExceptionMeasurement measurement in result.exceptions.values) {
95-
globals.printError('Target ${measurement.target} failed: ${measurement.exception}',
96-
stackTrace: measurement.fatal
97-
? measurement.stackTrace
98-
: null,
99-
);
66+
// The migrators to apply to a Web project.
67+
final List<ProjectMigrator> migrators = <ProjectMigrator>[
68+
ScrubGeneratedPluginRegistrant(flutterProject.web, _logger),
69+
];
70+
71+
final ProjectMigration migration = ProjectMigration(migrators);
72+
migration.run();
73+
74+
final Status status = _logger.startProgress('Compiling $target for the Web...');
75+
final Stopwatch sw = Stopwatch()..start();
76+
try {
77+
final BuildResult result = await _buildSystem.build(
78+
WebServiceWorker(_fileSystem, buildInfo.webRenderer, isWasm: isWasm),
79+
Environment(
80+
projectDir: _fileSystem.currentDirectory,
81+
outputDir: outputDirectory,
82+
buildDir: flutterProject.directory.childDirectory('.dart_tool').childDirectory('flutter_build'),
83+
defines: <String, String>{
84+
kTargetFile: target,
85+
kHasWebPlugins: hasWebPlugins.toString(),
86+
kCspMode: csp.toString(),
87+
if (baseHref != null) kBaseHref: baseHref,
88+
kSourceMapsEnabled: sourceMaps.toString(),
89+
kNativeNullAssertions: nativeNullAssertions.toString(),
90+
kServiceWorkerStrategy: serviceWorkerStrategy,
91+
kDart2jsOptimization: dart2jsOptimization,
92+
kDart2jsDumpInfo: dumpInfo.toString(),
93+
kDart2jsNoFrequencyBasedMinification: noFrequencyBasedMinification.toString(),
94+
...buildInfo.toBuildSystemEnvironment(),
95+
},
96+
artifacts: globals.artifacts!,
97+
fileSystem: _fileSystem,
98+
logger: _logger,
99+
processManager: globals.processManager,
100+
platform: globals.platform,
101+
usage: _flutterUsage,
102+
cacheDir: globals.cache.getRoot(),
103+
engineVersion: globals.artifacts!.isLocalEngine ? null : _flutterVersion.engineRevision,
104+
flutterRootDir: _fileSystem.directory(Cache.flutterRoot),
105+
// Web uses a different Dart plugin registry.
106+
// https://github.com/flutter/flutter/issues/80406
107+
generateDartPluginRegistry: false,
108+
));
109+
if (!result.success) {
110+
for (final ExceptionMeasurement measurement in result.exceptions.values) {
111+
_logger.printError(
112+
'Target ${measurement.target} failed: ${measurement.exception}',
113+
stackTrace: measurement.fatal ? measurement.stackTrace : null,
114+
);
115+
}
116+
throwToolExit('Failed to compile application for the Web.');
100117
}
101-
throwToolExit('Failed to compile application for the Web.');
118+
} on Exception catch (err) {
119+
throwToolExit(err.toString());
120+
} finally {
121+
status.stop();
102122
}
103-
} on Exception catch (err) {
104-
throwToolExit(err.toString());
105-
} finally {
106-
status.stop();
123+
_flutterUsage.sendTiming('build', 'dart2js', Duration(milliseconds: sw.elapsedMilliseconds));
107124
}
108-
globals.flutterUsage.sendTiming('build', 'dart2js', Duration(milliseconds: sw.elapsedMilliseconds));
109125
}
110126

111127
/// Web rendering backend mode.
Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
// Copyright 2014 The Flutter Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style license that can be
3+
// found in the LICENSE file.
4+
5+
import 'package:file/memory.dart';
6+
import 'package:flutter_tools/src/base/logger.dart';
7+
import 'package:flutter_tools/src/build_info.dart';
8+
import 'package:flutter_tools/src/build_system/build_system.dart';
9+
import 'package:flutter_tools/src/build_system/targets/web.dart';
10+
import 'package:flutter_tools/src/project.dart';
11+
import 'package:flutter_tools/src/reporting/reporting.dart';
12+
import 'package:flutter_tools/src/version.dart';
13+
import 'package:flutter_tools/src/web/compile.dart';
14+
15+
import '../../src/common.dart';
16+
import '../../src/context.dart';
17+
import '../../src/fakes.dart';
18+
import '../../src/test_build_system.dart';
19+
20+
void main() {
21+
late MemoryFileSystem fileSystem;
22+
late TestUsage testUsage;
23+
late BufferLogger logger;
24+
late FlutterVersion flutterVersion;
25+
late FlutterProject flutterProject;
26+
27+
setUp(() {
28+
fileSystem = MemoryFileSystem.test();
29+
testUsage = TestUsage();
30+
logger = BufferLogger.test();
31+
flutterVersion = FakeFlutterVersion(frameworkVersion: '1.0.0', engineRevision: '9.8.7');
32+
33+
flutterProject = FlutterProject.fromDirectoryTest(fileSystem.currentDirectory);
34+
fileSystem.file('.packages').createSync();
35+
});
36+
37+
testUsingContext('WebBuilder sets environment on success', () async {
38+
final TestBuildSystem buildSystem =
39+
TestBuildSystem.all(BuildResult(success: true), (Target target, Environment environment) {
40+
final WebServiceWorker webServiceWorker = target as WebServiceWorker;
41+
expect(webServiceWorker.isWasm, isTrue);
42+
expect(webServiceWorker.webRenderer, WebRendererMode.autoDetect);
43+
44+
expect(environment.defines, <String, String>{
45+
'TargetFile': 'target',
46+
'HasWebPlugins': 'false',
47+
'cspMode': 'true',
48+
'SourceMaps': 'true',
49+
'NativeNullAssertions': 'true',
50+
'ServiceWorkerStrategy': 'serviceWorkerStrategy',
51+
'Dart2jsOptimization': 'O4',
52+
'Dart2jsDumpInfo': 'false',
53+
'Dart2jsNoFrequencyBasedMinification': 'false',
54+
'BuildMode': 'debug',
55+
'DartObfuscation': 'false',
56+
'TrackWidgetCreation': 'true',
57+
'TreeShakeIcons': 'false',
58+
});
59+
60+
expect(environment.engineVersion, '9.8.7');
61+
expect(environment.generateDartPluginRegistry, isFalse);
62+
});
63+
64+
final WebBuilder webBuilder = WebBuilder(
65+
logger: logger,
66+
buildSystem: buildSystem,
67+
usage: testUsage,
68+
flutterVersion: flutterVersion,
69+
fileSystem: fileSystem,
70+
);
71+
await webBuilder.buildWeb(
72+
flutterProject,
73+
'target',
74+
BuildInfo.debug,
75+
true,
76+
'serviceWorkerStrategy',
77+
true,
78+
true,
79+
true,
80+
);
81+
82+
expect(logger.statusText, contains('Compiling target for the Web...'));
83+
expect(logger.errorText, isEmpty);
84+
// Runs ScrubGeneratedPluginRegistrant migrator.
85+
expect(logger.traceText, contains('generated_plugin_registrant.dart not found. Skipping.'));
86+
87+
// Sends timing event.
88+
final TestTimingEvent timingEvent = testUsage.timings.single;
89+
expect(timingEvent.category, 'build');
90+
expect(timingEvent.variableName, 'dart2js');
91+
});
92+
93+
testUsingContext('WebBuilder throws tool exit on failure', () async {
94+
final TestBuildSystem buildSystem = TestBuildSystem.all(BuildResult(
95+
success: false,
96+
exceptions: <String, ExceptionMeasurement>{
97+
'hello': ExceptionMeasurement(
98+
'hello',
99+
const FormatException('illegal character in input string'),
100+
StackTrace.current,
101+
),
102+
},
103+
));
104+
105+
final WebBuilder webBuilder = WebBuilder(
106+
logger: logger,
107+
buildSystem: buildSystem,
108+
usage: testUsage,
109+
flutterVersion: flutterVersion,
110+
fileSystem: fileSystem,
111+
);
112+
await expectLater(
113+
() async => webBuilder.buildWeb(
114+
flutterProject,
115+
'target',
116+
BuildInfo.debug,
117+
true,
118+
'serviceWorkerStrategy',
119+
true,
120+
true,
121+
true,
122+
),
123+
throwsToolExit(message: 'Failed to compile application for the Web.'));
124+
125+
expect(logger.errorText, contains('Target hello failed: FormatException: illegal character in input string'));
126+
expect(testUsage.timings, isEmpty);
127+
});
128+
}

0 commit comments

Comments
 (0)