@@ -22,6 +22,7 @@ import '../../web/compile.dart';
22
22
import '../../web/file_generators/flutter_js.dart' as flutter_js;
23
23
import '../../web/file_generators/flutter_service_worker_js.dart' ;
24
24
import '../../web/file_generators/main_dart.dart' as main_dart;
25
+ import '../../web/file_generators/wasm_bootstrap.dart' as wasm_bootstrap;
25
26
import '../build_system.dart' ;
26
27
import '../depfile.dart' ;
27
28
import '../exceptions.dart' ;
@@ -141,13 +142,11 @@ class WebEntrypointTarget extends Target {
141
142
}
142
143
143
144
/// Compiles a web entry point with dart2js.
144
- class Dart2JSTarget extends Target {
145
- const Dart2JSTarget (this .webRenderer);
145
+ abstract class Dart2WebTarget extends Target {
146
+ const Dart2WebTarget (this .webRenderer);
146
147
147
148
final WebRendererMode webRenderer;
148
-
149
- @override
150
- String get name => 'dart2js' ;
149
+ Source get compilerSnapshot;
151
150
152
151
@override
153
152
List <Target > get dependencies => const < Target > [
@@ -156,22 +155,17 @@ class Dart2JSTarget extends Target {
156
155
];
157
156
158
157
@override
159
- List <Source > get inputs => const < Source > [
160
- Source .hostArtifact (HostArtifact .flutterWebSdk),
161
- Source . artifact ( Artifact .dart2jsSnapshot) ,
162
- Source .artifact (Artifact .engineDartBinary),
163
- Source .pattern ('{BUILD_DIR}/main.dart' ),
164
- Source .pattern ('{PROJECT_DIR}/.dart_tool/package_config_subset' ),
158
+ List <Source > get inputs => < Source > [
159
+ const Source .hostArtifact (HostArtifact .flutterWebSdk),
160
+ compilerSnapshot ,
161
+ const Source .artifact (Artifact .engineDartBinary),
162
+ const Source .pattern ('{BUILD_DIR}/main.dart' ),
163
+ const Source .pattern ('{PROJECT_DIR}/.dart_tool/package_config_subset' ),
165
164
];
166
165
167
166
@override
168
167
List <Source > get outputs => const < Source > [];
169
168
170
- @override
171
- List <String > get depfiles => const < String > [
172
- 'dart2js.d' ,
173
- ];
174
-
175
169
String _collectOutput (ProcessResult result) {
176
170
final String stdout = result.stdout is List <int >
177
171
? utf8.decode (result.stdout as List <int >)
@@ -181,6 +175,21 @@ class Dart2JSTarget extends Target {
181
175
: result.stderr as String ;
182
176
return stdout + stderr;
183
177
}
178
+ }
179
+
180
+ class Dart2JSTarget extends Dart2WebTarget {
181
+ Dart2JSTarget (super .webRenderer);
182
+
183
+ @override
184
+ String get name => 'dart2js' ;
185
+
186
+ @override
187
+ Source get compilerSnapshot => const Source .artifact (Artifact .dart2jsSnapshot);
188
+
189
+ @override
190
+ List <String > get depfiles => const < String > [
191
+ 'dart2js.d' ,
192
+ ];
184
193
185
194
@override
186
195
Future <void > build (Environment environment) async {
@@ -270,29 +279,94 @@ class Dart2JSTarget extends Target {
270
279
}
271
280
}
272
281
273
- /// Unpacks the dart2js compilation and resources to a given output directory.
282
+ class Dart2WasmTarget extends Dart2WebTarget {
283
+ Dart2WasmTarget (super .webRenderer);
284
+
285
+ @override
286
+ Future <void > build (Environment environment) async {
287
+ final String ? buildModeEnvironment = environment.defines[kBuildMode];
288
+ if (buildModeEnvironment == null ) {
289
+ throw MissingDefineException (kBuildMode, name);
290
+ }
291
+ final BuildMode buildMode = getBuildModeForName (buildModeEnvironment);
292
+ final Artifacts artifacts = globals.artifacts! ;
293
+ final File outputWasmFile = environment.buildDir.childFile ('main.dart.wasm' );
294
+ final String dartSdkPath = artifacts.getArtifactPath (Artifact .engineDartSdkPath, platform: TargetPlatform .web_javascript);
295
+ final String dartSdkRoot = environment.fileSystem.directory (dartSdkPath).parent.path;
296
+
297
+ final List <String > compilationArgs = < String > [
298
+ artifacts.getArtifactPath (Artifact .engineDartAotRuntime, platform: TargetPlatform .web_javascript),
299
+ '--disable-dart-dev' ,
300
+ artifacts.getArtifactPath (Artifact .dart2wasmSnapshot, platform: TargetPlatform .web_javascript),
301
+ if (buildMode == BuildMode .profile)
302
+ '-Ddart.vm.profile=true'
303
+ else
304
+ '-Ddart.vm.product=true' ,
305
+ ...decodeCommaSeparated (environment.defines, kExtraFrontEndOptions),
306
+ for (final String dartDefine in decodeDartDefines (environment.defines, kDartDefines))
307
+ '-D$dartDefine ' ,
308
+ '--packages=.dart_tool/package_config.json' ,
309
+ '--dart-sdk=$dartSdkPath ' ,
310
+ '--multi-root-scheme' ,
311
+ 'org-dartlang-sdk' ,
312
+ '--multi-root' ,
313
+ artifacts.getHostArtifact (HostArtifact .flutterWebSdk).path,
314
+ '--multi-root' ,
315
+ dartSdkRoot,
316
+ '--libraries-spec' ,
317
+ artifacts.getHostArtifact (HostArtifact .flutterWebLibrariesJson).path,
318
+
319
+ environment.buildDir.childFile ('main.dart' ).path, // dartfile
320
+ outputWasmFile.path,
321
+ ];
322
+ final ProcessResult compileResult = await globals.processManager.run (compilationArgs);
323
+ if (compileResult.exitCode != 0 ) {
324
+ throw Exception (_collectOutput (compileResult));
325
+ }
326
+ }
327
+
328
+ @override
329
+ Source get compilerSnapshot => const Source .artifact (Artifact .dart2wasmSnapshot);
330
+
331
+ @override
332
+ String get name => 'dart2wasm' ;
333
+
334
+ @override
335
+ List <Source > get outputs => const < Source > [
336
+ Source .pattern ('{OUTPUT_DIR}/main.dart.wasm' ),
337
+ ];
338
+
339
+ // TODO(jacksongardner): override `depfiles` once dart2wasm begins producing
340
+ // them: https://github.com/dart-lang/sdk/issues/50747
341
+ }
342
+
343
+ /// Unpacks the dart2js or dart2wasm compilation and resources to a given
344
+ /// output directory.
274
345
class WebReleaseBundle extends Target {
275
- const WebReleaseBundle (this .webRenderer);
346
+ const WebReleaseBundle (this .webRenderer, this .isWasm );
276
347
277
348
final WebRendererMode webRenderer;
349
+ final bool isWasm;
350
+
351
+ String get outputFileName => isWasm ? 'main.dart.wasm' : 'main.dart.js' ;
278
352
279
353
@override
280
354
String get name => 'web_release_bundle' ;
281
355
282
356
@override
283
357
List <Target > get dependencies => < Target > [
284
- Dart2JSTarget (webRenderer),
358
+ if (isWasm) Dart2WasmTarget (webRenderer) else Dart2JSTarget (webRenderer),
285
359
];
286
360
287
361
@override
288
- List <Source > get inputs => const < Source > [
289
- Source .pattern ('{BUILD_DIR}/main.dart.js ' ),
290
- Source .pattern ('{PROJECT_DIR}/pubspec.yaml' ),
362
+ List <Source > get inputs => < Source > [
363
+ Source .pattern ('{BUILD_DIR}/$ outputFileName ' ),
364
+ const Source .pattern ('{PROJECT_DIR}/pubspec.yaml' ),
291
365
];
292
366
293
367
@override
294
- List <Source > get outputs => const < Source > [
295
- Source .pattern ('{OUTPUT_DIR}/main.dart.js ' ),
368
+ List <Source > get outputs => < Source > [
369
+ Source .pattern ('{OUTPUT_DIR}/$ outputFileName ' ),
296
370
];
297
371
298
372
@override
@@ -306,7 +380,7 @@ class WebReleaseBundle extends Target {
306
380
Future <void > build (Environment environment) async {
307
381
for (final File outputFile in environment.buildDir.listSync (recursive: true ).whereType <File >()) {
308
382
final String basename = globals.fs.path.basename (outputFile.path);
309
- if (! basename.contains ('main.dart.js' )) {
383
+ if (! basename.contains (outputFileName )) {
310
384
continue ;
311
385
}
312
386
// Do not copy the deps file.
@@ -318,6 +392,12 @@ class WebReleaseBundle extends Target {
318
392
);
319
393
}
320
394
395
+ if (isWasm) {
396
+ // TODO(jacksongardner): Enable icon tree shaking once dart2wasm can do a two-phase compile.
397
+ // https://github.com/flutter/flutter/issues/117248
398
+ environment.defines[kIconTreeShakerFlag] = 'false' ;
399
+ }
400
+
321
401
createVersionFile (environment, environment.defines);
322
402
final Directory outputDirectory = environment.outputDir.childDirectory ('assets' );
323
403
outputDirectory.createSync (recursive: true );
@@ -413,10 +493,11 @@ class WebReleaseBundle extends Target {
413
493
/// These assets can be cached forever and are only invalidated when the
414
494
/// Flutter SDK is upgraded to a new version.
415
495
class WebBuiltInAssets extends Target {
416
- const WebBuiltInAssets (this .fileSystem, this .cache);
496
+ const WebBuiltInAssets (this .fileSystem, this .cache, this .isWasm );
417
497
418
498
final FileSystem fileSystem;
419
499
final Cache cache;
500
+ final bool isWasm;
420
501
421
502
@override
422
503
String get name => 'web_static_assets' ;
@@ -451,6 +532,21 @@ class WebBuiltInAssets extends Target {
451
532
file.copySync (targetPath);
452
533
}
453
534
535
+ if (isWasm) {
536
+ final String dartSdkPath =
537
+ globals.artifacts! .getArtifactPath (Artifact .engineDartSdkPath);
538
+ final File dart2wasmRuntime = fileSystem.directory (dartSdkPath)
539
+ .childDirectory ('bin' )
540
+ .childFile ('dart2wasm_runtime.mjs' );
541
+ final String targetPath = fileSystem.path.join (
542
+ environment.outputDir.path,
543
+ 'dart2wasm_runtime.mjs' );
544
+ dart2wasmRuntime.copySync (targetPath);
545
+
546
+ final File bootstrapFile = environment.outputDir.childFile ('main.dart.js' );
547
+ bootstrapFile.writeAsStringSync (wasm_bootstrap.generateWasmBootstrapFile ());
548
+ }
549
+
454
550
// Write the flutter.js file
455
551
final File flutterJsFile = environment.outputDir.childFile ('flutter.js' );
456
552
flutterJsFile.writeAsStringSync (flutter_js.generateFlutterJsFile ());
@@ -459,20 +555,21 @@ class WebBuiltInAssets extends Target {
459
555
460
556
/// Generate a service worker for a web target.
461
557
class WebServiceWorker extends Target {
462
- const WebServiceWorker (this .fileSystem, this .cache, this .webRenderer);
558
+ const WebServiceWorker (this .fileSystem, this .cache, this .webRenderer, this .isWasm );
463
559
464
560
final FileSystem fileSystem;
465
561
final Cache cache;
466
562
final WebRendererMode webRenderer;
563
+ final bool isWasm;
467
564
468
565
@override
469
566
String get name => 'web_service_worker' ;
470
567
471
568
@override
472
569
List <Target > get dependencies => < Target > [
473
- Dart2JSTarget (webRenderer),
474
- WebReleaseBundle (webRenderer),
475
- WebBuiltInAssets (fileSystem, cache),
570
+ if (isWasm) Dart2WasmTarget (webRenderer) else Dart2JSTarget (webRenderer),
571
+ WebReleaseBundle (webRenderer, isWasm ),
572
+ WebBuiltInAssets (fileSystem, cache, isWasm ),
476
573
];
477
574
478
575
@override
0 commit comments