Have flutter.js load local canvaskit instead of the CDN when appropriate (#150806)

If the user specifies the `--no-web-resources-cdn` or `--local-web-sdk`, we should use the local version of CanvasKit. `flutter.js` now has a flag that can be specified in the build configuration that tells it to load locally instead.

Also, added a link to the relevant docs in the web template warnings.

This addresses https://github.com/flutter/flutter/issues/148713
Also fixes https://github.com/flutter/flutter/issues/145559
diff --git a/packages/flutter_tools/lib/src/build_info.dart b/packages/flutter_tools/lib/src/build_info.dart
index e3a9034..43f58bc 100644
--- a/packages/flutter_tools/lib/src/build_info.dart
+++ b/packages/flutter_tools/lib/src/build_info.dart
@@ -46,6 +46,7 @@
     this.initializeFromDill,
     this.assumeInitializeFromDillUpToDate = false,
     this.buildNativeAssets = true,
+    this.useLocalCanvasKit = false,
   }) : extraFrontEndOptions = extraFrontEndOptions ?? const <String>[],
        extraGenSnapshotOptions = extraGenSnapshotOptions ?? const <String>[],
        fileSystemRoots = fileSystemRoots ?? const <String>[],
@@ -180,6 +181,9 @@
   /// If set, builds native assets with `build.dart` from all packages.
   final bool buildNativeAssets;
 
+  /// If set, web builds will use the locally built CanvasKit instead of using the CDN
+  final bool useLocalCanvasKit;
+
   static const BuildInfo debug = BuildInfo(BuildMode.debug, null, trackWidgetCreation: true, treeShakeIcons: false);
   static const BuildInfo profile = BuildInfo(BuildMode.profile, null, treeShakeIcons: kIconTreeShakerEnabledDefault);
   static const BuildInfo jitRelease = BuildInfo(BuildMode.jitRelease, null, treeShakeIcons: kIconTreeShakerEnabledDefault);
@@ -260,6 +264,8 @@
         kBuildName: buildName!,
       if (buildNumber != null)
         kBuildNumber: buildNumber!,
+      if (useLocalCanvasKit)
+        kUseLocalCanvasKitFlag: useLocalCanvasKit.toString(),
     };
   }
 
@@ -941,6 +947,9 @@
 /// only the glyphs used by the application.
 const String kIconTreeShakerFlag = 'TreeShakeIcons';
 
+/// Controls whether a web build should use local canvaskit or the CDN
+const String kUseLocalCanvasKitFlag = 'UseLocalCanvasKit';
+
 /// The input key for an SkSL bundle path.
 const String kBundleSkSLPath = 'BundleSkSLPath';
 
diff --git a/packages/flutter_tools/lib/src/build_system/targets/web.dart b/packages/flutter_tools/lib/src/build_system/targets/web.dart
index 82e90bc..6d62b8e 100644
--- a/packages/flutter_tools/lib/src/build_system/targets/web.dart
+++ b/packages/flutter_tools/lib/src/build_system/targets/web.dart
@@ -104,6 +104,19 @@
   Iterable<File> buildFiles(Environment environment);
   Iterable<String> get buildPatternStems;
 
+  List<String> computeDartDefines(Environment environment) {
+    final List<String> dartDefines = compilerConfig.renderer.updateDartDefines(
+      decodeDartDefines(environment.defines, kDartDefines),
+    );
+    if (environment.defines[kUseLocalCanvasKitFlag] != 'true') {
+      final bool canvasKitUrlAlreadySet = dartDefines.any((String define) => define.startsWith('FLUTTER_WEB_CANVASKIT_URL='));
+      if (!canvasKitUrlAlreadySet) {
+        dartDefines.add('FLUTTER_WEB_CANVASKIT_URL=https://www.gstatic.com/flutter-canvaskit/${globals.flutterVersion.engineRevision}/');
+      }
+    }
+    return dartDefines;
+  }
+
   @override
   List<Target> get dependencies => const <Target>[
     WebEntrypointTarget(),
@@ -155,9 +168,6 @@
     final BuildMode buildMode = BuildMode.fromCliName(buildModeEnvironment);
     final Artifacts artifacts = environment.artifacts;
     final String platformBinariesPath = artifacts.getHostArtifact(HostArtifact.webPlatformKernelFolder).path;
-    final List<String> dartDefines = compilerConfig.renderer.updateDartDefines(
-      decodeDartDefines(environment.defines, kDartDefines),
-    );
     final List<String> sharedCommandOptions = <String>[
       artifacts.getArtifactPath(Artifact.engineDartBinary, platform: TargetPlatform.web_javascript),
       '--disable-dart-dev',
@@ -169,7 +179,7 @@
         '-Ddart.vm.profile=true'
       else
         '-Ddart.vm.product=true',
-      for (final String dartDefine in dartDefines)
+      for (final String dartDefine in computeDartDefines(environment))
         '-D$dartDefine',
     ];
 
@@ -287,9 +297,6 @@
     final File depFile = environment.buildDir.childFile('dart2wasm.d');
     final String platformBinariesPath = artifacts.getHostArtifact(HostArtifact.webPlatformKernelFolder).path;
     final String platformFilePath = environment.fileSystem.path.join(platformBinariesPath, 'dart2wasm_platform.dill');
-    final List<String> dartDefines = compilerConfig.renderer.updateDartDefines(
-      decodeDartDefines(environment.defines, kDartDefines),
-    );
 
     assert(buildMode == BuildMode.release || buildMode == BuildMode.profile);
     final List<String> compilationArgs = <String>[
@@ -309,7 +316,7 @@
       else
         '-Ddart.vm.product=true',
       ...decodeCommaSeparated(environment.defines, kExtraFrontEndOptions),
-      for (final String dartDefine in dartDefines)
+      for (final String dartDefine in computeDartDefines(environment))
         '-D$dartDefine',
       '--extra-compiler-option=--depfile=${depFile.path}',
 
@@ -380,23 +387,9 @@
 
   WebReleaseBundle._({
     required this.compileTargets,
-  }) : templatedFilesTarget = WebTemplatedFiles(generateBuildConfigString(compileTargets));
-
-  static String generateBuildConfigString(List<Dart2WebTarget> compileTargets) {
-    final List<Map<String, Object?>> buildDescriptions = compileTargets.map(
-      (Dart2WebTarget target) => target.buildConfig
-    ).toList();
-    final Map<String, Object?> buildConfig = <String, Object?>{
-      'engineRevision': globals.flutterVersion.engineRevision,
-      'builds': buildDescriptions,
-    };
-    return '''
-if (!window._flutter) {
-  window._flutter = {};
-}
-_flutter.buildConfig = ${jsonEncode(buildConfig)};
-''';
-  }
+  }) : templatedFilesTarget = WebTemplatedFiles(
+    compileTargets.map((Dart2WebTarget target) => target.buildConfig).toList()
+  );
 
   final List<Dart2WebTarget> compileTargets;
   final WebTemplatedFiles templatedFilesTarget;
@@ -516,12 +509,12 @@
 }
 
 class WebTemplatedFiles extends Target {
-  WebTemplatedFiles(this.buildConfigString);
+  WebTemplatedFiles(this.buildDescriptions);
 
-  final String buildConfigString;
+  final List<Map<String, Object?>> buildDescriptions;
 
   @override
-  String get buildKey => buildConfigString;
+  String get buildKey => jsonEncode(buildDescriptions);
 
   void _emitWebTemplateWarning(
     Environment environment,
@@ -533,6 +526,21 @@
     );
   }
 
+  String buildConfigString(Environment environment) {
+    final Map<String, Object> buildConfig = <String, Object>{
+      'engineRevision': globals.flutterVersion.engineRevision,
+      'builds': buildDescriptions,
+      if (environment.defines[kUseLocalCanvasKitFlag] == 'true')
+        'useLocalCanvasKit': true,
+    };
+    return '''
+if (!window._flutter) {
+  window._flutter = {};
+}
+_flutter.buildConfig = ${jsonEncode(buildConfig)};
+''';
+  }
+
   @override
   Future<void> build(Environment environment) async {
     final Directory webResources = environment.projectDir
@@ -555,6 +563,8 @@
       'flutter.js',
     ));
 
+    final String buildConfig = buildConfigString(environment);
+
     // Insert a random hash into the requests for service_worker.js. This is not a content hash,
     // because it would need to be the hash for the entire bundle and not just the resource
     // in question.
@@ -563,7 +573,7 @@
       baseHref: '',
       serviceWorkerVersion: serviceWorkerVersion,
       flutterJsFile: flutterJsFile,
-      buildConfig: buildConfigString,
+      buildConfig: buildConfig,
     );
 
     final File outputFlutterBootstrapJs = fileSystem.file(fileSystem.path.join(
@@ -585,7 +595,7 @@
           baseHref: environment.defines[kBaseHref] ?? '/',
           serviceWorkerVersion: serviceWorkerVersion,
           flutterJsFile: flutterJsFile,
-          buildConfig: buildConfigString,
+          buildConfig: buildConfig,
           flutterBootstrapJs: bootstrapTemplate.content,
         );
         final File outputIndexHtml = fileSystem.file(fileSystem.path.join(
diff --git a/packages/flutter_tools/lib/src/commands/run.dart b/packages/flutter_tools/lib/src/commands/run.dart
index 548b9fc..9d17bf5 100644
--- a/packages/flutter_tools/lib/src/commands/run.dart
+++ b/packages/flutter_tools/lib/src/commands/run.dart
@@ -235,6 +235,19 @@
 
   bool get useWasm => boolArg(FlutterOptions.kWebWasmFlag);
 
+  bool get useLocalCanvasKit {
+    // If we have specified not to use CDN, use local CanvasKit
+    if (!boolArg(FlutterOptions.kWebResourcesCdnFlag)) {
+      return true;
+    }
+
+    // If we are using a locally built web sdk, we should use local CanvasKit
+    if (stringArg(FlutterGlobalOptions.kLocalWebSDKOption, global: true) != null) {
+      return true;
+    }
+    return false;
+  }
+
   WebRendererMode get webRenderer => WebRendererMode.fromCliOption(
     stringArg(FlutterOptions.kWebRendererFlag),
     useWasm: useWasm
@@ -274,6 +287,7 @@
         webHeaders: webHeaders,
         webRenderer: webRenderer,
         webUseWasm: useWasm,
+        webUseLocalCanvaskit: useLocalCanvasKit,
         enableImpeller: enableImpeller,
         enableVulkanValidation: enableVulkanValidation,
         uninstallFirst: uninstallFirst,
@@ -325,6 +339,7 @@
         webHeaders: webHeaders,
         webRenderer: webRenderer,
         webUseWasm: useWasm,
+        webUseLocalCanvaskit: useLocalCanvasKit,
         vmserviceOutFile: stringArg('vmservice-out-file'),
         fastStart: argParser.options.containsKey('fast-start')
           && boolArg('fast-start')
diff --git a/packages/flutter_tools/lib/src/commands/test.dart b/packages/flutter_tools/lib/src/commands/test.dart
index bda8b30..493e2e2 100644
--- a/packages/flutter_tools/lib/src/commands/test.dart
+++ b/packages/flutter_tools/lib/src/commands/test.dart
@@ -412,6 +412,7 @@
       debugLogsDirectoryPath: debugLogsDirectoryPath,
       webRenderer: webRenderer,
       webUseWasm: useWasm,
+      webUseLocalCanvaskit: true,
     );
 
     String? testAssetDirectory;
diff --git a/packages/flutter_tools/lib/src/device.dart b/packages/flutter_tools/lib/src/device.dart
index 3bc4e30..35cc939 100644
--- a/packages/flutter_tools/lib/src/device.dart
+++ b/packages/flutter_tools/lib/src/device.dart
@@ -994,6 +994,7 @@
     this.webLaunchUrl,
     WebRendererMode? webRenderer,
     this.webUseWasm = false,
+    this.webUseLocalCanvaskit = false,
     this.vmserviceOutFile,
     this.fastStart = false,
     this.nullAssertions = false,
@@ -1026,6 +1027,7 @@
       this.webHeaders = const <String, String>{},
       WebRendererMode? webRenderer,
       this.webUseWasm = false,
+      this.webUseLocalCanvaskit = false,
       this.cacheSkSL = false,
       this.traceAllowlist,
       this.enableImpeller = ImpellerStatus.platformDefault,
@@ -1108,6 +1110,7 @@
     required this.webLaunchUrl,
     required this.webRenderer,
     required this.webUseWasm,
+    required this.webUseLocalCanvaskit,
     required this.vmserviceOutFile,
     required this.fastStart,
     required this.nullAssertions,
@@ -1198,6 +1201,9 @@
   /// Whether to compile to webassembly
   final bool webUseWasm;
 
+  /// If true, serve CanvasKit assets locally rather than using the CDN.
+  final bool webUseLocalCanvaskit;
+
   /// A file where the VM Service URL should be written after the application is started.
   final String? vmserviceOutFile;
   final bool fastStart;
@@ -1308,6 +1314,7 @@
     'webHeaders': webHeaders,
     'webRenderer': webRenderer.name,
     'webUseWasm': webUseWasm,
+    'webUseLocalCanvaskit': webUseLocalCanvaskit,
     'vmserviceOutFile': vmserviceOutFile,
     'fastStart': fastStart,
     'nullAssertions': nullAssertions,
@@ -1365,6 +1372,7 @@
       webLaunchUrl: json['webLaunchUrl'] as String?,
       webRenderer: WebRendererMode.values.byName(json['webRenderer']! as String),
       webUseWasm: json['webUseWasm']! as bool,
+      webUseLocalCanvaskit: json['webUseLocalCanvaskit']! as bool,
       vmserviceOutFile: json['vmserviceOutFile'] as String?,
       fastStart: json['fastStart']! as bool,
       nullAssertions: json['nullAssertions']! as bool,
diff --git a/packages/flutter_tools/lib/src/drive/web_driver_service.dart b/packages/flutter_tools/lib/src/drive/web_driver_service.dart
index b72a8d9..b7989cc 100644
--- a/packages/flutter_tools/lib/src/drive/web_driver_service.dart
+++ b/packages/flutter_tools/lib/src/drive/web_driver_service.dart
@@ -79,7 +79,8 @@
           port: debuggingOptions.port,
           hostname: debuggingOptions.hostname,
           webRenderer: debuggingOptions.webRenderer,
-          webUseWasm: debuggingOptions.webUseWasm
+          webUseWasm: debuggingOptions.webUseWasm,
+          webUseLocalCanvaskit: debuggingOptions.webUseLocalCanvaskit,
         )
         : DebuggingOptions.enabled(
           buildInfo,
@@ -88,6 +89,7 @@
           disablePortPublication: debuggingOptions.disablePortPublication,
           webRenderer: debuggingOptions.webRenderer,
           webUseWasm: debuggingOptions.webUseWasm,
+          webUseLocalCanvaskit: debuggingOptions.webUseLocalCanvaskit,
         ),
       stayResident: true,
       flutterProject: FlutterProject.current(),
diff --git a/packages/flutter_tools/lib/src/isolated/devfs_web.dart b/packages/flutter_tools/lib/src/isolated/devfs_web.dart
index a9cface..5faf5c5 100644
--- a/packages/flutter_tools/lib/src/isolated/devfs_web.dart
+++ b/packages/flutter_tools/lib/src/isolated/devfs_web.dart
@@ -120,6 +120,7 @@
     this._nullSafetyMode,
     this._ddcModuleSystem, {
     required this.webRenderer,
+    required this.useLocalCanvasKit,
   }) : basePath = _getWebTemplate('index.html', _kDefaultIndex).getBaseHref();
 
   // Fallback to "application/octet-stream" on null which
@@ -181,6 +182,7 @@
     NullSafetyMode nullSafetyMode, {
     required WebRendererMode webRenderer,
     required bool isWasm,
+    required bool useLocalCanvasKit,
     bool testMode = false,
     DwdsLauncher dwdsLauncher = Dwds.start,
     // TODO(markzipan): Make sure this default value aligns with that in the debugger options.
@@ -233,6 +235,7 @@
       nullSafetyMode,
       ddcModuleSystem,
       webRenderer: webRenderer,
+      useLocalCanvasKit: useLocalCanvasKit,
     );
     if (testMode) {
       return server;
@@ -530,6 +533,8 @@
   /// Determines what rendering backed to use.
   final WebRendererMode webRenderer;
 
+  final bool useLocalCanvasKit;
+
   String get _buildConfigString {
     final Map<String, dynamic> buildConfig = <String, dynamic>{
       'engineRevision': globals.flutterVersion.engineRevision,
@@ -540,6 +545,7 @@
           'mainJsPath': 'main.dart.js',
         },
       ],
+      if (useLocalCanvasKit) 'useLocalCanvasKit' : true,
     };
     return '''
 if (!window._flutter) {
@@ -740,6 +746,7 @@
     required this.ddcModuleSystem,
     required this.webRenderer,
     required this.isWasm,
+    required this.useLocalCanvasKit,
     required this.rootDirectory,
     this.testMode = false,
   }) : _port = port;
@@ -767,6 +774,7 @@
   final String? tlsCertKeyPath;
   final WebRendererMode webRenderer;
   final bool isWasm;
+  final bool useLocalCanvasKit;
 
   late WebAssetServer webAssetServer;
 
@@ -868,6 +876,7 @@
       nullSafetyMode,
       webRenderer: webRenderer,
       isWasm: isWasm,
+      useLocalCanvasKit: useLocalCanvasKit,
       testMode: testMode,
       ddcModuleSystem: ddcModuleSystem,
     );
diff --git a/packages/flutter_tools/lib/src/isolated/resident_web_runner.dart b/packages/flutter_tools/lib/src/isolated/resident_web_runner.dart
index 3df469e..5bed52b 100644
--- a/packages/flutter_tools/lib/src/isolated/resident_web_runner.dart
+++ b/packages/flutter_tools/lib/src/isolated/resident_web_runner.dart
@@ -318,6 +318,7 @@
           ddcModuleSystem: debuggingOptions.buildInfo.ddcModuleFormat == DdcModuleFormat.ddc,
           webRenderer: debuggingOptions.webRenderer,
           isWasm: debuggingOptions.webUseWasm,
+          useLocalCanvasKit: debuggingOptions.webUseLocalCanvaskit,
           rootDirectory: fileSystem.directory(projectRootPath),
         );
         Uri url = await device!.devFS!.create();
diff --git a/packages/flutter_tools/lib/src/runner/flutter_command.dart b/packages/flutter_tools/lib/src/runner/flutter_command.dart
index d85dbf9..ce96b55 100644
--- a/packages/flutter_tools/lib/src/runner/flutter_command.dart
+++ b/packages/flutter_tools/lib/src/runner/flutter_command.dart
@@ -1281,16 +1281,11 @@
 
     final Map<String, Object?> defineConfigJsonMap = extractDartDefineConfigJsonMap();
     final List<String> dartDefines = extractDartDefines(defineConfigJsonMap: defineConfigJsonMap);
-
-    if (argParser.options.containsKey(FlutterOptions.kWebResourcesCdnFlag)) {
-      final bool hasLocalWebSdk = argParser.options.containsKey('local-web-sdk') && stringArg('local-web-sdk') != null;
-      if (boolArg(FlutterOptions.kWebResourcesCdnFlag) && !hasLocalWebSdk) {
-        if (!dartDefines.any((String define) => define.startsWith('FLUTTER_WEB_CANVASKIT_URL='))) {
-          dartDefines.add('FLUTTER_WEB_CANVASKIT_URL=https://www.gstatic.com/flutter-canvaskit/${globals.flutterVersion.engineRevision}/');
-        }
-      }
-    }
-
+    final bool useCdn = !argParser.options.containsKey(FlutterOptions.kWebResourcesCdnFlag)
+      || boolArg(FlutterOptions.kWebResourcesCdnFlag);
+    final bool useLocalWebSdk = argParser.options.containsKey(FlutterGlobalOptions.kLocalWebSDKOption)
+      && stringArg(FlutterGlobalOptions.kLocalWebSDKOption, global: true) != null;
+    final bool useLocalCanvasKit = !useCdn || useLocalWebSdk;
     final String? defaultFlavor = FlutterProject.current().manifest.defaultFlavor;
     final String? cliFlavor = argParser.options.containsKey('flavor') ? stringArg('flavor') : null;
     final String? flavor = cliFlavor ?? defaultFlavor;
@@ -1343,6 +1338,7 @@
           : null,
       assumeInitializeFromDillUpToDate: argParser.options.containsKey(FlutterOptions.kAssumeInitializeFromDillUpToDate)
           && boolArg(FlutterOptions.kAssumeInitializeFromDillUpToDate),
+      useLocalCanvasKit: useLocalCanvasKit,
     );
   }
 
diff --git a/packages/flutter_tools/lib/src/web_template.dart b/packages/flutter_tools/lib/src/web_template.dart
index 802e60b..cfe8aa8 100644
--- a/packages/flutter_tools/lib/src/web_template.dart
+++ b/packages/flutter_tools/lib/src/web_template.dart
@@ -72,15 +72,15 @@
     return <WebTemplateWarning>[
       ..._getWarningsForPattern(
         RegExp('(const|var) serviceWorkerVersion = null'),
-        'Local variable for "serviceWorkerVersion" is deprecated. Use "{{flutter_service_worker_version}}" template token instead.',
+        'Local variable for "serviceWorkerVersion" is deprecated. Use "{{flutter_service_worker_version}}" template token instead. See https://docs.flutter.dev/platform-integration/web/initialization for more details.',
       ),
       ..._getWarningsForPattern(
         "navigator.serviceWorker.register('flutter_service_worker.js')",
-        'Manual service worker registration deprecated. Use flutter.js service worker bootstrapping instead.',
+        'Manual service worker registration deprecated. Use flutter.js service worker bootstrapping instead. See https://docs.flutter.dev/platform-integration/web/initialization for more details.',
       ),
       ..._getWarningsForPattern(
         '_flutter.loader.loadEntrypoint(',
-        '"FlutterLoader.loadEntrypoint" is deprecated. Use "FlutterLoader.load" instead.',
+        '"FlutterLoader.loadEntrypoint" is deprecated. Use "FlutterLoader.load" instead. See https://docs.flutter.dev/platform-integration/web/initialization for more details.',
       ),
     ];
   }
diff --git a/packages/flutter_tools/test/commands.shard/hermetic/build_web_test.dart b/packages/flutter_tools/test/commands.shard/hermetic/build_web_test.dart
index 3c0502b..0c2cb70 100644
--- a/packages/flutter_tools/test/commands.shard/hermetic/build_web_test.dart
+++ b/packages/flutter_tools/test/commands.shard/hermetic/build_web_test.dart
@@ -156,6 +156,7 @@
         'DartObfuscation': 'false',
         'TrackWidgetCreation': 'false',
         'TreeShakeIcons': 'true',
+        'UseLocalCanvasKit': 'true',
       });
     }),
   });
@@ -252,6 +253,7 @@
         'DartObfuscation': 'false',
         'TrackWidgetCreation': 'false',
         'TreeShakeIcons': 'true',
+        'UseLocalCanvasKit': 'true',
       });
     }),
   });
@@ -338,22 +340,6 @@
     BuildSystem: () => TestBuildSystem.all(BuildResult(success: true)),
   });
 
-  testUsingContext('Defaults to gstatic CanvasKit artifacts', () async {
-    final TestWebBuildCommand buildCommand = TestWebBuildCommand(fileSystem: fileSystem);
-    final CommandRunner<void> runner = createTestCommandRunner(buildCommand);
-    setupFileSystemForEndToEndTest(fileSystem);
-    await runner.run(<String>['build', 'web', '--no-pub', '--web-resources-cdn']);
-    final BuildInfo buildInfo =
-        await buildCommand.webCommand.getBuildInfo(forcedBuildMode: BuildMode.debug);
-    expect(buildInfo.dartDefines, contains(startsWith('FLUTTER_WEB_CANVASKIT_URL=https://www.gstatic.com/flutter-canvaskit/')));
-  }, overrides: <Type, Generator>{
-    Platform: () => fakePlatform,
-    FileSystem: () => fileSystem,
-    FeatureFlags: () => TestFeatureFlags(isWebEnabled: true),
-    ProcessManager: () => processManager,
-    BuildSystem: () => TestBuildSystem.all(BuildResult(success: true)),
-  });
-
   testUsingContext('Does not override custom CanvasKit URL', () async {
     final TestWebBuildCommand buildCommand = TestWebBuildCommand(fileSystem: fileSystem);
     final CommandRunner<void> runner = createTestCommandRunner(buildCommand);
diff --git a/packages/flutter_tools/test/general.shard/build_system/targets/web_test.dart b/packages/flutter_tools/test/general.shard/build_system/targets/web_test.dart
index 85f45ae..db004ad 100644
--- a/packages/flutter_tools/test/general.shard/build_system/targets/web_test.dart
+++ b/packages/flutter_tools/test/general.shard/build_system/targets/web_test.dart
@@ -144,11 +144,24 @@
 <!DOCTYPE html><html><base href="$kBaseHrefPlaceholder"><head></head></html>
     ''');
     environment.buildDir.childFile('main.dart.js').createSync();
-    await WebTemplatedFiles('buildConfig').build(environment);
+    await WebTemplatedFiles(<Map<String, Object?>>[]).build(environment);
 
     expect(environment.outputDir.childFile('index.html').readAsStringSync(), contains('/basehreftest/'));
   }));
 
+  test('WebTemplatedFiles emits useLocalCanvasKit in flutter_bootstrap.js when environment specifies', () => testbed.run(() async {
+    environment.defines[kUseLocalCanvasKitFlag] = 'true';
+    final Directory webResources = environment.projectDir.childDirectory('web');
+    webResources.childFile('index.html').createSync(recursive: true);
+    webResources.childFile('index.html').writeAsStringSync('''
+<!DOCTYPE html><html><base href="$kBaseHrefPlaceholder"><head></head></html>
+    ''');
+    environment.buildDir.childFile('main.dart.js').createSync();
+    await WebTemplatedFiles(<Map<String, Object?>>[]).build(environment);
+
+    expect(environment.outputDir.childFile('flutter_bootstrap.js').readAsStringSync(), contains('"useLocalCanvasKit":true'));
+  }));
+
   test('null base href does not override existing base href in index.html', () => testbed.run(() async {
     environment.defines[kBuildMode] = 'release';
     final Directory webResources = environment.projectDir.childDirectory('web');
@@ -157,7 +170,7 @@
 <!DOCTYPE html><html><head><base href='/basehreftest/'></head></html>
     ''');
     environment.buildDir.childFile('main.dart.js').createSync();
-    await WebTemplatedFiles('build config').build(environment);
+    await WebTemplatedFiles(<Map<String, Object?>>[]).build(environment);
 
     expect(environment.outputDir.childFile('index.html').readAsStringSync(), contains('/basehreftest/'));
   }));
@@ -378,6 +391,7 @@
         '-Ddart.vm.profile=true',
         '-DFLUTTER_WEB_AUTO_DETECT=false',
         '-DFLUTTER_WEB_USE_SKIA=true',
+        '-DFLUTTER_WEB_CANVASKIT_URL=https://www.gstatic.com/flutter-canvaskit/abcdefghijklmnopqrstuvwxyz/',
         '--no-source-maps',
         '-o',
         environment.buildDir.childFile('app.dill').absolute.path,
@@ -392,6 +406,7 @@
         '-Ddart.vm.profile=true',
         '-DFLUTTER_WEB_AUTO_DETECT=false',
         '-DFLUTTER_WEB_USE_SKIA=true',
+        '-DFLUTTER_WEB_CANVASKIT_URL=https://www.gstatic.com/flutter-canvaskit/abcdefghijklmnopqrstuvwxyz/',
         '--no-minify',
         '--no-source-maps',
         '-O4',
@@ -421,6 +436,7 @@
         '-Ddart.vm.profile=true',
         '-DFLUTTER_WEB_AUTO_DETECT=false',
         '-DFLUTTER_WEB_USE_SKIA=true',
+        '-DFLUTTER_WEB_CANVASKIT_URL=https://www.gstatic.com/flutter-canvaskit/abcdefghijklmnopqrstuvwxyz/',
         '--no-source-maps',
         '-o',
         environment.buildDir.childFile('app.dill').absolute.path,
@@ -435,6 +451,7 @@
         '-Ddart.vm.profile=true',
         '-DFLUTTER_WEB_AUTO_DETECT=false',
         '-DFLUTTER_WEB_USE_SKIA=true',
+        '-DFLUTTER_WEB_CANVASKIT_URL=https://www.gstatic.com/flutter-canvaskit/abcdefghijklmnopqrstuvwxyz/',
         '--no-minify',
         '--no-source-maps',
         '-O4',
@@ -463,6 +480,7 @@
         '-Ddart.vm.profile=true',
         '-DFLUTTER_WEB_AUTO_DETECT=false',
         '-DFLUTTER_WEB_USE_SKIA=true',
+        '-DFLUTTER_WEB_CANVASKIT_URL=https://www.gstatic.com/flutter-canvaskit/abcdefghijklmnopqrstuvwxyz/',
         '--no-source-maps',
         '-o',
         environment.buildDir.childFile('app.dill').absolute.path,
@@ -478,6 +496,7 @@
         '-Ddart.vm.profile=true',
         '-DFLUTTER_WEB_AUTO_DETECT=false',
         '-DFLUTTER_WEB_USE_SKIA=true',
+        '-DFLUTTER_WEB_CANVASKIT_URL=https://www.gstatic.com/flutter-canvaskit/abcdefghijklmnopqrstuvwxyz/',
         '--no-minify',
         '--no-source-maps',
         '-O4',
@@ -504,6 +523,7 @@
         '-Ddart.vm.profile=true',
         '-DFLUTTER_WEB_AUTO_DETECT=false',
         '-DFLUTTER_WEB_USE_SKIA=true',
+        '-DFLUTTER_WEB_CANVASKIT_URL=https://www.gstatic.com/flutter-canvaskit/abcdefghijklmnopqrstuvwxyz/',
         '--no-source-maps',
         '-o',
         environment.buildDir.childFile('app.dill').absolute.path,
@@ -518,6 +538,7 @@
         '-Ddart.vm.profile=true',
         '-DFLUTTER_WEB_AUTO_DETECT=false',
         '-DFLUTTER_WEB_USE_SKIA=true',
+        '-DFLUTTER_WEB_CANVASKIT_URL=https://www.gstatic.com/flutter-canvaskit/abcdefghijklmnopqrstuvwxyz/',
         '--no-minify',
         '--no-source-maps',
         '-O4',
@@ -544,6 +565,7 @@
         '-Ddart.vm.product=true',
         '-DFLUTTER_WEB_AUTO_DETECT=false',
         '-DFLUTTER_WEB_USE_SKIA=true',
+        '-DFLUTTER_WEB_CANVASKIT_URL=https://www.gstatic.com/flutter-canvaskit/abcdefghijklmnopqrstuvwxyz/',
         '--no-source-maps',
         '-o',
         environment.buildDir.childFile('app.dill').absolute.path,
@@ -558,6 +580,7 @@
         '-Ddart.vm.product=true',
         '-DFLUTTER_WEB_AUTO_DETECT=false',
         '-DFLUTTER_WEB_USE_SKIA=true',
+        '-DFLUTTER_WEB_CANVASKIT_URL=https://www.gstatic.com/flutter-canvaskit/abcdefghijklmnopqrstuvwxyz/',
         '--no-source-maps',
         '-O4',
         '-o',
@@ -584,6 +607,7 @@
         '-Ddart.vm.product=true',
         '-DFLUTTER_WEB_AUTO_DETECT=false',
         '-DFLUTTER_WEB_USE_SKIA=true',
+        '-DFLUTTER_WEB_CANVASKIT_URL=https://www.gstatic.com/flutter-canvaskit/abcdefghijklmnopqrstuvwxyz/',
         '--native-null-assertions',
         '--no-source-maps',
         '-o',
@@ -599,6 +623,7 @@
         '-Ddart.vm.product=true',
         '-DFLUTTER_WEB_AUTO_DETECT=false',
         '-DFLUTTER_WEB_USE_SKIA=true',
+        '-DFLUTTER_WEB_CANVASKIT_URL=https://www.gstatic.com/flutter-canvaskit/abcdefghijklmnopqrstuvwxyz/',
         '--native-null-assertions',
         '--no-source-maps',
         '-O4',
@@ -626,6 +651,7 @@
         '-Ddart.vm.product=true',
         '-DFLUTTER_WEB_AUTO_DETECT=false',
         '-DFLUTTER_WEB_USE_SKIA=true',
+        '-DFLUTTER_WEB_CANVASKIT_URL=https://www.gstatic.com/flutter-canvaskit/abcdefghijklmnopqrstuvwxyz/',
         '--no-source-maps',
         '-o',
         environment.buildDir.childFile('app.dill').absolute.path,
@@ -640,6 +666,7 @@
         '-Ddart.vm.product=true',
         '-DFLUTTER_WEB_AUTO_DETECT=false',
         '-DFLUTTER_WEB_USE_SKIA=true',
+        '-DFLUTTER_WEB_CANVASKIT_URL=https://www.gstatic.com/flutter-canvaskit/abcdefghijklmnopqrstuvwxyz/',
         '--no-source-maps',
         '-O3',
         '-o',
@@ -666,6 +693,7 @@
         '-Ddart.vm.product=true',
         '-DFLUTTER_WEB_AUTO_DETECT=false',
         '-DFLUTTER_WEB_USE_SKIA=true',
+        '-DFLUTTER_WEB_CANVASKIT_URL=https://www.gstatic.com/flutter-canvaskit/abcdefghijklmnopqrstuvwxyz/',
         '--no-source-maps',
         '-o',
         environment.buildDir.childFile('app.dill').absolute.path,
@@ -683,6 +711,7 @@
         '-Ddart.vm.product=true',
         '-DFLUTTER_WEB_AUTO_DETECT=false',
         '-DFLUTTER_WEB_USE_SKIA=true',
+        '-DFLUTTER_WEB_CANVASKIT_URL=https://www.gstatic.com/flutter-canvaskit/abcdefghijklmnopqrstuvwxyz/',
         '--no-source-maps',
         '-O4',
         '-o',
@@ -718,6 +747,7 @@
         '-DBAZ=qux',
         '-DFLUTTER_WEB_AUTO_DETECT=false',
         '-DFLUTTER_WEB_USE_SKIA=true',
+        '-DFLUTTER_WEB_CANVASKIT_URL=https://www.gstatic.com/flutter-canvaskit/abcdefghijklmnopqrstuvwxyz/',
         '--no-source-maps',
         '-o',
         environment.buildDir.childFile('app.dill').absolute.path,
@@ -734,6 +764,7 @@
         '-DBAZ=qux',
         '-DFLUTTER_WEB_AUTO_DETECT=false',
         '-DFLUTTER_WEB_USE_SKIA=true',
+        '-DFLUTTER_WEB_CANVASKIT_URL=https://www.gstatic.com/flutter-canvaskit/abcdefghijklmnopqrstuvwxyz/',
         '--no-source-maps',
         '-O4',
         '-o',
@@ -760,6 +791,7 @@
         '-Ddart.vm.product=true',
         '-DFLUTTER_WEB_AUTO_DETECT=false',
         '-DFLUTTER_WEB_USE_SKIA=true',
+        '-DFLUTTER_WEB_CANVASKIT_URL=https://www.gstatic.com/flutter-canvaskit/abcdefghijklmnopqrstuvwxyz/',
         '-o',
         environment.buildDir.childFile('app.dill').absolute.path,
         '--packages=.dart_tool/package_config.json',
@@ -773,6 +805,7 @@
         '-Ddart.vm.product=true',
         '-DFLUTTER_WEB_AUTO_DETECT=false',
         '-DFLUTTER_WEB_USE_SKIA=true',
+        '-DFLUTTER_WEB_CANVASKIT_URL=https://www.gstatic.com/flutter-canvaskit/abcdefghijklmnopqrstuvwxyz/',
         '-O4',
         '-o',
         environment.buildDir.childFile('main.dart.js').absolute.path,
@@ -799,6 +832,7 @@
         '-DBAZ=qux',
         '-DFLUTTER_WEB_AUTO_DETECT=false',
         '-DFLUTTER_WEB_USE_SKIA=true',
+        '-DFLUTTER_WEB_CANVASKIT_URL=https://www.gstatic.com/flutter-canvaskit/abcdefghijklmnopqrstuvwxyz/',
         '--no-source-maps',
         '-o',
         environment.buildDir.childFile('app.dill').absolute.path,
@@ -815,6 +849,7 @@
         '-DBAZ=qux',
         '-DFLUTTER_WEB_AUTO_DETECT=false',
         '-DFLUTTER_WEB_USE_SKIA=true',
+        '-DFLUTTER_WEB_CANVASKIT_URL=https://www.gstatic.com/flutter-canvaskit/abcdefghijklmnopqrstuvwxyz/',
         '--no-minify',
         '--no-source-maps',
         '-O4',
@@ -842,6 +877,7 @@
         '-Ddart.vm.profile=true',
         '-DFLUTTER_WEB_AUTO_DETECT=false',
         '-DFLUTTER_WEB_USE_SKIA=true',
+        '-DFLUTTER_WEB_CANVASKIT_URL=https://www.gstatic.com/flutter-canvaskit/abcdefghijklmnopqrstuvwxyz/',
         '--no-source-maps',
         '-o',
         environment.buildDir.childFile('app.dill').absolute.path,
@@ -856,6 +892,7 @@
         '-Ddart.vm.profile=true',
         '-DFLUTTER_WEB_AUTO_DETECT=false',
         '-DFLUTTER_WEB_USE_SKIA=true',
+        '-DFLUTTER_WEB_CANVASKIT_URL=https://www.gstatic.com/flutter-canvaskit/abcdefghijklmnopqrstuvwxyz/',
         '--no-minify',
         '--no-source-maps',
         '-O4',
@@ -885,6 +922,7 @@
         '-Ddart.vm.profile=true',
         '-DFLUTTER_WEB_AUTO_DETECT=false',
         '-DFLUTTER_WEB_USE_SKIA=true',
+        '-DFLUTTER_WEB_CANVASKIT_URL=https://www.gstatic.com/flutter-canvaskit/abcdefghijklmnopqrstuvwxyz/',
         '--no-source-maps',
         '-o',
         environment.buildDir.childFile('app.dill').absolute.path,
@@ -899,6 +937,7 @@
         '-Ddart.vm.profile=true',
         '-DFLUTTER_WEB_AUTO_DETECT=false',
         '-DFLUTTER_WEB_USE_SKIA=true',
+        '-DFLUTTER_WEB_CANVASKIT_URL=https://www.gstatic.com/flutter-canvaskit/abcdefghijklmnopqrstuvwxyz/',
         '--no-minify',
         '--no-source-maps',
         '-O4',
@@ -949,6 +988,7 @@
                     '-DFLUTTER_WEB_AUTO_DETECT=false',
                     '-DFLUTTER_WEB_USE_SKIA=true',
                   ],
+                  '-DFLUTTER_WEB_CANVASKIT_URL=https://www.gstatic.com/flutter-canvaskit/abcdefghijklmnopqrstuvwxyz/',
                   '--extra-compiler-option=--depfile=${depFile.absolute.path}',
                   '-O$level',
                   if (strip && buildMode == 'release') '--strip-wasm' else '--no-strip-wasm',
diff --git a/packages/flutter_tools/test/general.shard/web/devfs_web_ddc_modules_test.dart b/packages/flutter_tools/test/general.shard/web/devfs_web_ddc_modules_test.dart
index 2b18e13..c88c0d4 100644
--- a/packages/flutter_tools/test/general.shard/web/devfs_web_ddc_modules_test.dart
+++ b/packages/flutter_tools/test/general.shard/web/devfs_web_ddc_modules_test.dart
@@ -130,6 +130,7 @@
             NullSafetyMode.unsound,
             usesDdcModuleSystem,
             webRenderer: WebRendererMode.canvaskit,
+            useLocalCanvasKit: false,
           );
           releaseAssetServer = ReleaseAssetServer(
             globals.fs.file('main.dart').uri,
@@ -414,6 +415,7 @@
               NullSafetyMode.unsound,
               usesDdcModuleSystem,
               webRenderer: WebRendererMode.canvaskit,
+              useLocalCanvasKit: false,
             );
 
             expect(webAssetServer.basePath, 'foo/bar');
@@ -437,6 +439,7 @@
               NullSafetyMode.unsound,
               usesDdcModuleSystem,
               webRenderer: WebRendererMode.canvaskit,
+              useLocalCanvasKit: false,
             );
 
             // Defaults to "/" when there's no base element.
@@ -462,6 +465,7 @@
                 NullSafetyMode.unsound,
                 usesDdcModuleSystem,
                 webRenderer: WebRendererMode.canvaskit,
+                useLocalCanvasKit: false,
               ),
               throwsToolExit(),
             );
@@ -486,6 +490,7 @@
                 NullSafetyMode.unsound,
                 usesDdcModuleSystem,
                 webRenderer: WebRendererMode.canvaskit,
+                useLocalCanvasKit: false,
               ),
               throwsToolExit(),
             );
@@ -929,6 +934,7 @@
               ddcModuleSystem: usesDdcModuleSystem,
               webRenderer: WebRendererMode.html,
               isWasm: false,
+              useLocalCanvasKit: false,
               rootDirectory: globals.fs.currentDirectory,
             );
             webDevFS.ddcModuleLoaderJS.createSync(recursive: true);
@@ -1066,6 +1072,7 @@
               ddcModuleSystem: usesDdcModuleSystem,
               webRenderer: WebRendererMode.html,
               isWasm: false,
+              useLocalCanvasKit: false,
               rootDirectory: globals.fs.currentDirectory,
             );
             webDevFS.ddcModuleLoaderJS.createSync(recursive: true);
@@ -1203,6 +1210,7 @@
                 ddcModuleSystem: usesDdcModuleSystem,
                 webRenderer: WebRendererMode.canvaskit,
                 isWasm: false,
+                useLocalCanvasKit: false,
                 rootDirectory: globals.fs.currentDirectory,
               );
               webDevFS.ddcModuleLoaderJS.createSync(recursive: true);
@@ -1277,6 +1285,7 @@
               ddcModuleSystem: usesDdcModuleSystem,
               webRenderer: WebRendererMode.canvaskit,
               isWasm: false,
+              useLocalCanvasKit: false,
               rootDirectory: globals.fs.currentDirectory,
             );
             webDevFS.ddcModuleLoaderJS.createSync(recursive: true);
@@ -1327,6 +1336,7 @@
               ddcModuleSystem: usesDdcModuleSystem,
               webRenderer: WebRendererMode.canvaskit,
               isWasm: false,
+              useLocalCanvasKit: false,
               rootDirectory: globals.fs.currentDirectory,
             );
             webDevFS.ddcModuleLoaderJS.createSync(recursive: true);
@@ -1379,6 +1389,7 @@
               ddcModuleSystem: usesDdcModuleSystem,
               webRenderer: WebRendererMode.auto,
               isWasm: false,
+              useLocalCanvasKit: false,
               rootDirectory: globals.fs.currentDirectory,
             );
             webDevFS.ddcModuleLoaderJS.createSync(recursive: true);
@@ -1433,6 +1444,7 @@
               ddcModuleSystem: usesDdcModuleSystem,
               webRenderer: WebRendererMode.canvaskit,
               isWasm: false,
+              useLocalCanvasKit: false,
               rootDirectory: globals.fs.currentDirectory,
             );
             webDevFS.ddcModuleLoaderJS.createSync(recursive: true);
@@ -1472,6 +1484,7 @@
         NullSafetyMode.unsound,
         webRenderer: WebRendererMode.canvaskit,
         isWasm: false,
+        useLocalCanvasKit: false,
         testMode: true);
 
     expect(webAssetServer.defaultResponseHeaders['x-frame-options'], null);
@@ -1506,6 +1519,7 @@
         NullSafetyMode.unsound,
         webRenderer: WebRendererMode.canvaskit,
         isWasm: false,
+        useLocalCanvasKit: false,
         testMode: true);
 
     expect(webAssetServer.defaultResponseHeaders[extraHeaderKey],
@@ -1551,6 +1565,7 @@
               NullSafetyMode.sound,
               usesDdcModuleSystem,
               webRenderer: WebRendererMode.canvaskit,
+              useLocalCanvasKit: false,
             );
 
             expect(
@@ -1607,6 +1622,7 @@
               ddcModuleSystem: usesDdcModuleSystem,
               webRenderer: WebRendererMode.canvaskit,
               isWasm: false,
+              useLocalCanvasKit: false,
               rootDirectory: globals.fs.currentDirectory,
             );
             webDevFS.ddcModuleLoaderJS.createSync(recursive: true);
diff --git a/packages/flutter_tools/test/general.shard/web/devfs_web_test.dart b/packages/flutter_tools/test/general.shard/web/devfs_web_test.dart
index c4074f5..ea7a1f6 100644
--- a/packages/flutter_tools/test/general.shard/web/devfs_web_test.dart
+++ b/packages/flutter_tools/test/general.shard/web/devfs_web_test.dart
@@ -69,6 +69,7 @@
         NullSafetyMode.unsound,
         usesDdcModuleSystem,
         webRenderer: WebRendererMode.canvaskit,
+        useLocalCanvasKit: false,
       );
       releaseAssetServer = ReleaseAssetServer(
         globals.fs.file('main.dart').uri,
@@ -306,6 +307,7 @@
       NullSafetyMode.unsound,
       usesDdcModuleSystem,
       webRenderer: WebRendererMode.canvaskit,
+      useLocalCanvasKit: false,
     );
 
     expect(webAssetServer.basePath, 'foo/bar');
@@ -327,6 +329,7 @@
       NullSafetyMode.unsound,
       usesDdcModuleSystem,
       webRenderer: WebRendererMode.canvaskit,
+      useLocalCanvasKit: false,
     );
 
     // Defaults to "/" when there's no base element.
@@ -350,6 +353,7 @@
         NullSafetyMode.unsound,
         usesDdcModuleSystem,
         webRenderer: WebRendererMode.canvaskit,
+        useLocalCanvasKit: false,
       ),
       throwsToolExit(),
     );
@@ -372,6 +376,7 @@
         NullSafetyMode.unsound,
         usesDdcModuleSystem,
         webRenderer: WebRendererMode.canvaskit,
+        useLocalCanvasKit: false,
       ),
       throwsToolExit(),
     );
@@ -392,6 +397,48 @@
     expect((await response.read().toList()).first, utf8.encode('main() {}'));
   }));
 
+  test('serves flutter_bootstrap.js without useLocalCanvasKit', () => testbed.run(() async {
+    globals.fs.file(globals.fs.path.join(
+      globals.artifacts!.getHostArtifact(HostArtifact.flutterJsDirectory).path,
+      'flutter.js',
+    ))..createSync(recursive: true)..writeAsStringSync('flutter.js content');
+
+    final Response response = await webAssetServer.handleRequest(
+      Request('GET', Uri.parse('http://foobar/flutter_bootstrap.js'))
+    );
+
+    expect(response.statusCode, 200);
+    final String body = await response.readAsString();
+    expect(body, isNot(contains('useLocalCanvasKit')));
+  }));
+
+  test('serves flutter_bootstrap.js with useLocalCanvasKit', () => testbed.run(() async {
+    globals.fs.file(globals.fs.path.join(
+      globals.artifacts!.getHostArtifact(HostArtifact.flutterJsDirectory).path,
+      'flutter.js',
+    ))..createSync(recursive: true)..writeAsStringSync('flutter.js content');
+
+    webAssetServer = WebAssetServer(
+      httpServer,
+      packages,
+      InternetAddress.loopbackIPv4,
+      <String, String>{},
+      <String, String>{},
+      NullSafetyMode.unsound,
+      usesDdcModuleSystem,
+      webRenderer: WebRendererMode.canvaskit,
+      useLocalCanvasKit: true,
+    );
+
+    final Response response = await webAssetServer.handleRequest(
+      Request('GET', Uri.parse('http://foobar/flutter_bootstrap.js'))
+    );
+
+    expect(response.statusCode, 200);
+    final String body = await response.readAsString();
+    expect(body, contains('"useLocalCanvasKit":true'));
+  }));
+
   test('Returns notModified when the ifNoneMatch header matches the etag', () => testbed.run(() async {
     webAssetServer.writeFile('foo.js', 'main() {}');
 
@@ -717,6 +764,7 @@
       ddcModuleSystem: usesDdcModuleSystem,
       webRenderer: WebRendererMode.html,
       isWasm: false,
+      useLocalCanvasKit: false,
       rootDirectory: globals.fs.currentDirectory,
     );
     webDevFS.requireJS.createSync(recursive: true);
@@ -830,6 +878,7 @@
       ddcModuleSystem: usesDdcModuleSystem,
       webRenderer: WebRendererMode.html,
       isWasm: false,
+      useLocalCanvasKit: false,
       rootDirectory: globals.fs.currentDirectory,
     );
     webDevFS.requireJS.createSync(recursive: true);
@@ -949,6 +998,7 @@
         ddcModuleSystem: usesDdcModuleSystem,
         webRenderer: WebRendererMode.canvaskit,
         isWasm: false,
+        useLocalCanvasKit: false,
         rootDirectory: globals.fs.currentDirectory,
       );
       webDevFS.requireJS.createSync(recursive: true);
@@ -1014,6 +1064,7 @@
       ddcModuleSystem: usesDdcModuleSystem,
       webRenderer: WebRendererMode.canvaskit,
       isWasm: false,
+      useLocalCanvasKit: false,
       rootDirectory: globals.fs.currentDirectory,
     );
     webDevFS.requireJS.createSync(recursive: true);
@@ -1063,6 +1114,7 @@
       ddcModuleSystem: usesDdcModuleSystem,
       webRenderer: WebRendererMode.canvaskit,
       isWasm: false,
+      useLocalCanvasKit: false,
       rootDirectory: globals.fs.currentDirectory,
     );
     webDevFS.requireJS.createSync(recursive: true);
@@ -1113,6 +1165,7 @@
       ddcModuleSystem: usesDdcModuleSystem,
       webRenderer: WebRendererMode.auto,
       isWasm: false,
+      useLocalCanvasKit: false,
       rootDirectory: globals.fs.currentDirectory,
     );
     webDevFS.requireJS.createSync(recursive: true);
@@ -1164,6 +1217,7 @@
       ddcModuleSystem: usesDdcModuleSystem,
       webRenderer: WebRendererMode.canvaskit,
       isWasm: false,
+      useLocalCanvasKit: false,
       rootDirectory: globals.fs.currentDirectory,
     );
     webDevFS.requireJS.createSync(recursive: true);
@@ -1203,6 +1257,7 @@
       NullSafetyMode.unsound,
       webRenderer: WebRendererMode.canvaskit,
       isWasm: false,
+      useLocalCanvasKit: false,
       testMode: true
     );
 
@@ -1238,6 +1293,7 @@
       NullSafetyMode.unsound,
       webRenderer: WebRendererMode.canvaskit,
       isWasm: false,
+      useLocalCanvasKit: false,
       testMode: true
     );
 
@@ -1276,6 +1332,7 @@
       NullSafetyMode.sound,
       usesDdcModuleSystem,
       webRenderer: WebRendererMode.canvaskit,
+      useLocalCanvasKit: false,
     );
 
     expect(await webAssetServer.metadataContents('foo/main_module.ddc_merged_metadata'), null);
@@ -1321,6 +1378,7 @@
       ddcModuleSystem: usesDdcModuleSystem,
       webRenderer: WebRendererMode.canvaskit,
       isWasm: false,
+      useLocalCanvasKit: false,
       rootDirectory: globals.fs.currentDirectory,
     );
     webDevFS.requireJS.createSync(recursive: true);