Revert "[web] Move JS content to its own `.js` files (#117691)" (#120275)
This reverts commit e03029ef6a0c2040476bf6602da4e5d1271eb77d.
diff --git a/packages/flutter_tools/lib/src/artifacts.dart b/packages/flutter_tools/lib/src/artifacts.dart
index 4546a3d..fd56d3c 100644
--- a/packages/flutter_tools/lib/src/artifacts.dart
+++ b/packages/flutter_tools/lib/src/artifacts.dart
@@ -9,7 +9,6 @@
import 'base/file_system.dart';
import 'base/os.dart';
import 'base/platform.dart';
-import 'base/user_messages.dart';
import 'base/utils.dart';
import 'build_info.dart';
import 'cache.dart';
@@ -63,9 +62,6 @@
/// Tools related to subsetting or icon font files.
fontSubset,
constFinder,
-
- /// The location of file generators.
- flutterToolsFileGenerators,
}
/// A subset of [Artifact]s that are platform and build mode independent
@@ -206,8 +202,6 @@
return 'font-subset$exe';
case Artifact.constFinder:
return 'const_finder.dart.snapshot';
- case Artifact.flutterToolsFileGenerators:
- return '';
}
}
@@ -531,8 +525,6 @@
case Artifact.windowsCppClientWrapper:
case Artifact.windowsDesktopPath:
return _getHostArtifactPath(artifact, platform, mode);
- case Artifact.flutterToolsFileGenerators:
- return _getFileGeneratorsPath();
}
}
@@ -570,8 +562,6 @@
case Artifact.windowsCppClientWrapper:
case Artifact.windowsDesktopPath:
return _getHostArtifactPath(artifact, platform, mode);
- case Artifact.flutterToolsFileGenerators:
- return _getFileGeneratorsPath();
}
}
@@ -621,8 +611,6 @@
case Artifact.windowsCppClientWrapper:
case Artifact.windowsDesktopPath:
return _getHostArtifactPath(artifact, platform, mode);
- case Artifact.flutterToolsFileGenerators:
- return _getFileGeneratorsPath();
}
}
@@ -697,8 +685,6 @@
case Artifact.fuchsiaFlutterRunner:
case Artifact.fuchsiaKernelCompiler:
throw StateError('Artifact $artifact not available for platform $platform.');
- case Artifact.flutterToolsFileGenerators:
- return _getFileGeneratorsPath();
}
}
@@ -966,8 +952,6 @@
case Artifact.dart2wasmSnapshot:
case Artifact.frontendServerSnapshotForEngineDartSdk:
return _fileSystem.path.join(_getDartSdkPath(), 'bin', 'snapshots', artifactFileName);
- case Artifact.flutterToolsFileGenerators:
- return _getFileGeneratorsPath();
}
}
@@ -1115,7 +1099,6 @@
case Artifact.fuchsiaFlutterRunner:
case Artifact.fontSubset:
case Artifact.constFinder:
- case Artifact.flutterToolsFileGenerators:
break;
}
}
@@ -1315,11 +1298,6 @@
BuildMode? mode,
EnvironmentType? environmentType,
}) {
- // The path to file generators is the same even in the test environment.
- if (artifact == Artifact.flutterToolsFileGenerators) {
- return _getFileGeneratorsPath();
- }
-
final StringBuffer buffer = StringBuffer();
buffer.write(artifact);
if (platform != null) {
@@ -1362,20 +1340,3 @@
@override
final LocalEngineInfo localEngineInfo;
}
-
-String _getFileGeneratorsPath() {
- final String flutterRoot = Cache.defaultFlutterRoot(
- fileSystem: globals.localFileSystem,
- platform: const LocalPlatform(),
- userMessages: UserMessages(),
- );
- return globals.localFileSystem.path.join(
- flutterRoot,
- 'packages',
- 'flutter_tools',
- 'lib',
- 'src',
- 'web',
- 'file_generators',
- );
-}
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 fde180c..3812729 100644
--- a/packages/flutter_tools/lib/src/build_system/targets/web.dart
+++ b/packages/flutter_tools/lib/src/build_system/targets/web.dart
@@ -529,10 +529,7 @@
// Write the flutter.js file
final File flutterJsFile = environment.outputDir.childFile('flutter.js');
- final String fileGeneratorsPath =
- globals.artifacts!.getArtifactPath(Artifact.flutterToolsFileGenerators);
- flutterJsFile.writeAsStringSync(
- flutter_js.generateFlutterJsFile(fileGeneratorsPath));
+ flutterJsFile.writeAsStringSync(flutter_js.generateFlutterJsFile());
}
}
@@ -601,10 +598,7 @@
final ServiceWorkerStrategy serviceWorkerStrategy = _serviceWorkerStrategyFromString(
environment.defines[kServiceWorkerStrategy],
);
- final String fileGeneratorsPath =
- globals.artifacts!.getArtifactPath(Artifact.flutterToolsFileGenerators);
final String serviceWorker = generateServiceWorker(
- fileGeneratorsPath,
urlToHash,
<String>[
'main.dart.js',
diff --git a/packages/flutter_tools/lib/src/isolated/devfs_web.dart b/packages/flutter_tools/lib/src/isolated/devfs_web.dart
index cdd04e3..3c86d02 100644
--- a/packages/flutter_tools/lib/src/isolated/devfs_web.dart
+++ b/packages/flutter_tools/lib/src/isolated/devfs_web.dart
@@ -828,10 +828,7 @@
'stack_trace_mapper.js', stackTraceMapper.readAsBytesSync());
webAssetServer.writeFile(
'manifest.json', '{"info":"manifest not generated in run mode."}');
- final String fileGeneratorsPath = globals.artifacts!
- .getArtifactPath(Artifact.flutterToolsFileGenerators);
- webAssetServer.writeFile(
- 'flutter.js', flutter_js.generateFlutterJsFile(fileGeneratorsPath));
+ webAssetServer.writeFile('flutter.js', flutter_js.generateFlutterJsFile());
webAssetServer.writeFile('flutter_service_worker.js',
'// Service worker not loaded in run mode.');
webAssetServer.writeFile(
diff --git a/packages/flutter_tools/lib/src/web/file_generators/flutter_js.dart b/packages/flutter_tools/lib/src/web/file_generators/flutter_js.dart
index 991719d..81a611d 100644
--- a/packages/flutter_tools/lib/src/web/file_generators/flutter_js.dart
+++ b/packages/flutter_tools/lib/src/web/file_generators/flutter_js.dart
@@ -2,17 +2,388 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-import '../../globals.dart' as globals;
/// Generates the flutter.js file.
///
/// flutter.js should be completely static, so **do not use any parameter or
/// environment variable to generate this file**.
-String generateFlutterJsFile(String fileGeneratorsPath) {
- final String flutterJsPath = globals.localFileSystem.path.join(
- fileGeneratorsPath,
- 'js',
- 'flutter.js',
- );
- return globals.localFileSystem.file(flutterJsPath).readAsStringSync();
+String generateFlutterJsFile() {
+ return r'''
+// Copyright 2014 The Flutter Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+if (!_flutter) {
+ var _flutter = {};
+}
+_flutter.loader = null;
+
+(function () {
+ "use strict";
+
+ const baseUri = ensureTrailingSlash(getBaseURI());
+
+ function getBaseURI() {
+ const base = document.querySelector("base");
+ return (base && base.getAttribute("href")) || "";
+ }
+
+ function ensureTrailingSlash(uri) {
+ if (uri == "") {
+ return uri;
+ }
+ return uri.endsWith("/") ? uri : `${uri}/`;
+ }
+
+ /**
+ * Wraps `promise` in a timeout of the given `duration` in ms.
+ *
+ * Resolves/rejects with whatever the original `promises` does, or rejects
+ * if `promise` takes longer to complete than `duration`. In that case,
+ * `debugName` is used to compose a legible error message.
+ *
+ * If `duration` is < 0, the original `promise` is returned unchanged.
+ * @param {Promise} promise
+ * @param {number} duration
+ * @param {string} debugName
+ * @returns {Promise} a wrapped promise.
+ */
+ async function timeout(promise, duration, debugName) {
+ if (duration < 0) {
+ return promise;
+ }
+ let timeoutId;
+ const _clock = new Promise((_, reject) => {
+ timeoutId = setTimeout(() => {
+ reject(
+ new Error(
+ `${debugName} took more than ${duration}ms to resolve. Moving on.`,
+ {
+ cause: timeout,
+ }
+ )
+ );
+ }, duration);
+ });
+
+ return Promise.race([promise, _clock]).finally(() => {
+ clearTimeout(timeoutId);
+ });
+ }
+
+ /**
+ * Handles the creation of a TrustedTypes `policy` that validates URLs based
+ * on an (optional) incoming array of RegExes.
+ */
+ class FlutterTrustedTypesPolicy {
+ /**
+ * Constructs the policy.
+ * @param {[RegExp]} validPatterns the patterns to test URLs
+ * @param {String} policyName the policy name (optional)
+ */
+ constructor(validPatterns, policyName = "flutter-js") {
+ const patterns = validPatterns || [
+ /\.dart\.js$/,
+ /^flutter_service_worker.js$/
+ ];
+ if (window.trustedTypes) {
+ this.policy = trustedTypes.createPolicy(policyName, {
+ createScriptURL: function(url) {
+ const parsed = new URL(url, window.location);
+ const file = parsed.pathname.split("/").pop();
+ const matches = patterns.some((pattern) => pattern.test(file));
+ if (matches) {
+ return parsed.toString();
+ }
+ console.error(
+ "URL rejected by TrustedTypes policy",
+ policyName, ":", url, "(download prevented)");
+ }
+ });
+ }
+ }
+ }
+
+ /**
+ * Handles loading/reloading Flutter's service worker, if configured.
+ *
+ * @see: https://developers.google.com/web/fundamentals/primers/service-workers
+ */
+ class FlutterServiceWorkerLoader {
+ /**
+ * Injects a TrustedTypesPolicy (or undefined if the feature is not supported).
+ * @param {TrustedTypesPolicy | undefined} policy
+ */
+ setTrustedTypesPolicy(policy) {
+ this._ttPolicy = policy;
+ }
+
+ /**
+ * Returns a Promise that resolves when the latest Flutter service worker,
+ * configured by `settings` has been loaded and activated.
+ *
+ * Otherwise, the promise is rejected with an error message.
+ * @param {*} settings Service worker settings
+ * @returns {Promise} that resolves when the latest serviceWorker is ready.
+ */
+ loadServiceWorker(settings) {
+ if (!("serviceWorker" in navigator) || settings == null) {
+ // In the future, settings = null -> uninstall service worker?
+ return Promise.reject(
+ new Error("Service worker not supported (or configured).")
+ );
+ }
+ const {
+ serviceWorkerVersion,
+ serviceWorkerUrl = `${baseUri}flutter_service_worker.js?v=${serviceWorkerVersion}`,
+ timeoutMillis = 4000,
+ } = settings;
+
+ // Apply the TrustedTypes policy, if present.
+ let url = serviceWorkerUrl;
+ if (this._ttPolicy != null) {
+ url = this._ttPolicy.createScriptURL(url);
+ }
+
+ const serviceWorkerActivation = navigator.serviceWorker
+ .register(url)
+ .then(this._getNewServiceWorker)
+ .then(this._waitForServiceWorkerActivation);
+
+ // Timeout race promise
+ return timeout(
+ serviceWorkerActivation,
+ timeoutMillis,
+ "prepareServiceWorker"
+ );
+ }
+
+ /**
+ * Returns the latest service worker for the given `serviceWorkerRegistrationPromise`.
+ *
+ * This might return the current service worker, if there's no new service worker
+ * awaiting to be installed/updated.
+ *
+ * @param {Promise<ServiceWorkerRegistration>} serviceWorkerRegistrationPromise
+ * @returns {Promise<ServiceWorker>}
+ */
+ async _getNewServiceWorker(serviceWorkerRegistrationPromise) {
+ const reg = await serviceWorkerRegistrationPromise;
+
+ if (!reg.active && (reg.installing || reg.waiting)) {
+ // No active web worker and we have installed or are installing
+ // one for the first time. Simply wait for it to activate.
+ console.debug("Installing/Activating first service worker.");
+ return reg.installing || reg.waiting;
+ } else if (!reg.active.scriptURL.endsWith(serviceWorkerVersion)) {
+ // When the app updates the serviceWorkerVersion changes, so we
+ // need to ask the service worker to update.
+ return reg.update().then((newReg) => {
+ console.debug("Updating service worker.");
+ return newReg.installing || newReg.waiting || newReg.active;
+ });
+ } else {
+ console.debug("Loading from existing service worker.");
+ return reg.active;
+ }
+ }
+
+ /**
+ * Returns a Promise that resolves when the `latestServiceWorker` changes its
+ * state to "activated".
+ *
+ * @param {Promise<ServiceWorker>} latestServiceWorkerPromise
+ * @returns {Promise<void>}
+ */
+ async _waitForServiceWorkerActivation(latestServiceWorkerPromise) {
+ const serviceWorker = await latestServiceWorkerPromise;
+
+ if (!serviceWorker || serviceWorker.state == "activated") {
+ if (!serviceWorker) {
+ return Promise.reject(
+ new Error("Cannot activate a null service worker!")
+ );
+ } else {
+ console.debug("Service worker already active.");
+ return Promise.resolve();
+ }
+ }
+ return new Promise((resolve, _) => {
+ serviceWorker.addEventListener("statechange", () => {
+ if (serviceWorker.state == "activated") {
+ console.debug("Activated new service worker.");
+ resolve();
+ }
+ });
+ });
+ }
+ }
+
+ /**
+ * Handles injecting the main Flutter web entrypoint (main.dart.js), and notifying
+ * the user when Flutter is ready, through `didCreateEngineInitializer`.
+ *
+ * @see https://docs.flutter.dev/development/platform-integration/web/initialization
+ */
+ class FlutterEntrypointLoader {
+ /**
+ * Creates a FlutterEntrypointLoader.
+ */
+ constructor() {
+ // Watchdog to prevent injecting the main entrypoint multiple times.
+ this._scriptLoaded = false;
+ }
+
+ /**
+ * Injects a TrustedTypesPolicy (or undefined if the feature is not supported).
+ * @param {TrustedTypesPolicy | undefined} policy
+ */
+ setTrustedTypesPolicy(policy) {
+ this._ttPolicy = policy;
+ }
+
+ /**
+ * Loads flutter main entrypoint, specified by `entrypointUrl`, and calls a
+ * user-specified `onEntrypointLoaded` callback with an EngineInitializer
+ * object when it's done.
+ *
+ * @param {*} options
+ * @returns {Promise | undefined} that will eventually resolve with an
+ * EngineInitializer, or will be rejected with the error caused by the loader.
+ * Returns undefined when an `onEntrypointLoaded` callback is supplied in `options`.
+ */
+ async loadEntrypoint(options) {
+ const { entrypointUrl = `${baseUri}main.dart.js`, onEntrypointLoaded } =
+ options || {};
+
+ return this._loadEntrypoint(entrypointUrl, onEntrypointLoaded);
+ }
+
+ /**
+ * Resolves the promise created by loadEntrypoint, and calls the `onEntrypointLoaded`
+ * function supplied by the user (if needed).
+ *
+ * Called by Flutter through `_flutter.loader.didCreateEngineInitializer` method,
+ * which is bound to the correct instance of the FlutterEntrypointLoader by
+ * the FlutterLoader object.
+ *
+ * @param {Function} engineInitializer @see https://github.com/flutter/engine/blob/main/lib/web_ui/lib/src/engine/js_interop/js_loader.dart#L42
+ */
+ didCreateEngineInitializer(engineInitializer) {
+ if (typeof this._didCreateEngineInitializerResolve === "function") {
+ this._didCreateEngineInitializerResolve(engineInitializer);
+ // Remove the resolver after the first time, so Flutter Web can hot restart.
+ this._didCreateEngineInitializerResolve = null;
+ // Make the engine revert to "auto" initialization on hot restart.
+ delete _flutter.loader.didCreateEngineInitializer;
+ }
+ if (typeof this._onEntrypointLoaded === "function") {
+ this._onEntrypointLoaded(engineInitializer);
+ }
+ }
+
+ /**
+ * Injects a script tag into the DOM, and configures this loader to be able to
+ * handle the "entrypoint loaded" notifications received from Flutter web.
+ *
+ * @param {string} entrypointUrl the URL of the script that will initialize
+ * Flutter.
+ * @param {Function} onEntrypointLoaded a callback that will be called when
+ * Flutter web notifies this object that the entrypoint is
+ * loaded.
+ * @returns {Promise | undefined} a Promise that resolves when the entrypoint
+ * is loaded, or undefined if `onEntrypointLoaded`
+ * is a function.
+ */
+ _loadEntrypoint(entrypointUrl, onEntrypointLoaded) {
+ const useCallback = typeof onEntrypointLoaded === "function";
+
+ if (!this._scriptLoaded) {
+ this._scriptLoaded = true;
+ const scriptTag = this._createScriptTag(entrypointUrl);
+ if (useCallback) {
+ // Just inject the script tag, and return nothing; Flutter will call
+ // `didCreateEngineInitializer` when it's done.
+ console.debug("Injecting <script> tag. Using callback.");
+ this._onEntrypointLoaded = onEntrypointLoaded;
+ document.body.append(scriptTag);
+ } else {
+ // Inject the script tag and return a promise that will get resolved
+ // with the EngineInitializer object from Flutter when it calls
+ // `didCreateEngineInitializer` later.
+ return new Promise((resolve, reject) => {
+ console.debug(
+ "Injecting <script> tag. Using Promises. Use the callback approach instead!"
+ );
+ this._didCreateEngineInitializerResolve = resolve;
+ scriptTag.addEventListener("error", reject);
+ document.body.append(scriptTag);
+ });
+ }
+ }
+ }
+
+ /**
+ * Creates a script tag for the given URL.
+ * @param {string} url
+ * @returns {HTMLScriptElement}
+ */
+ _createScriptTag(url) {
+ const scriptTag = document.createElement("script");
+ scriptTag.type = "application/javascript";
+ // Apply TrustedTypes validation, if available.
+ let trustedUrl = url;
+ if (this._ttPolicy != null) {
+ trustedUrl = this._ttPolicy.createScriptURL(url);
+ }
+ scriptTag.src = trustedUrl;
+ return scriptTag;
+ }
+ }
+
+ /**
+ * The public interface of _flutter.loader. Exposes two methods:
+ * * loadEntrypoint (which coordinates the default Flutter web loading procedure)
+ * * didCreateEngineInitializer (which is called by Flutter to notify that its
+ * Engine is ready to be initialized)
+ */
+ class FlutterLoader {
+ /**
+ * Initializes the Flutter web app.
+ * @param {*} options
+ * @returns {Promise?} a (Deprecated) Promise that will eventually resolve
+ * with an EngineInitializer, or will be rejected with
+ * any error caused by the loader. Or Null, if the user
+ * supplies an `onEntrypointLoaded` Function as an option.
+ */
+ async loadEntrypoint(options) {
+ const { serviceWorker, ...entrypoint } = options || {};
+
+ // A Trusted Types policy that is going to be used by the loader.
+ const flutterTT = new FlutterTrustedTypesPolicy();
+
+ // The FlutterServiceWorkerLoader instance could be injected as a dependency
+ // (and dynamically imported from a module if not present).
+ const serviceWorkerLoader = new FlutterServiceWorkerLoader();
+ serviceWorkerLoader.setTrustedTypesPolicy(flutterTT.policy);
+ await serviceWorkerLoader.loadServiceWorker(serviceWorker).catch(e => {
+ // Regardless of what happens with the injection of the SW, the show must go on
+ console.warn("Exception while loading service worker:", e);
+ });
+
+ // The FlutterEntrypointLoader instance could be injected as a dependency
+ // (and dynamically imported from a module if not present).
+ const entrypointLoader = new FlutterEntrypointLoader();
+ entrypointLoader.setTrustedTypesPolicy(flutterTT.policy);
+ // Install the `didCreateEngineInitializer` listener where Flutter web expects it to be.
+ this.didCreateEngineInitializer =
+ entrypointLoader.didCreateEngineInitializer.bind(entrypointLoader);
+ return entrypointLoader.loadEntrypoint(entrypoint);
+ }
+ }
+
+ _flutter.loader = new FlutterLoader();
+})();
+
+''';
}
diff --git a/packages/flutter_tools/lib/src/web/file_generators/flutter_service_worker_js.dart b/packages/flutter_tools/lib/src/web/file_generators/flutter_service_worker_js.dart
index 24ce814..3a371f0 100644
--- a/packages/flutter_tools/lib/src/web/file_generators/flutter_service_worker_js.dart
+++ b/packages/flutter_tools/lib/src/web/file_generators/flutter_service_worker_js.dart
@@ -2,14 +2,11 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-import '../../globals.dart' as globals;
-
/// The caching strategy for the generated service worker.
enum ServiceWorkerStrategy {
/// Download the app shell eagerly and all other assets lazily.
/// Prefer the offline cached version.
offlineFirst,
-
/// Do not generate a service worker,
none,
}
@@ -21,7 +18,6 @@
/// invalidation will automatically reactivate workers whenever a new
/// version is deployed.
String generateServiceWorker(
- String fileGeneratorsPath,
Map<String, String> resources,
List<String> coreBundle, {
required ServiceWorkerStrategy serviceWorkerStrategy,
@@ -29,21 +25,185 @@
if (serviceWorkerStrategy == ServiceWorkerStrategy.none) {
return '';
}
+ return '''
+'use strict';
+const MANIFEST = 'flutter-app-manifest';
+const TEMP = 'flutter-temp-cache';
+const CACHE_NAME = 'flutter-app-cache';
+const RESOURCES = {
+ ${resources.entries.map((MapEntry<String, String> entry) => '"${entry.key}": "${entry.value}"').join(",\n")}
+};
- final String flutterServiceWorkerJsPath = globals.localFileSystem.path.join(
- fileGeneratorsPath,
- 'js',
- 'flutter_service_worker.js',
+// The application shell files that are downloaded before a service worker can
+// start.
+const CORE = [
+ ${coreBundle.map((String file) => '"$file"').join(',\n')}];
+// During install, the TEMP cache is populated with the application shell files.
+self.addEventListener("install", (event) => {
+ self.skipWaiting();
+ return event.waitUntil(
+ caches.open(TEMP).then((cache) => {
+ return cache.addAll(
+ CORE.map((value) => new Request(value, {'cache': 'reload'})));
+ })
);
- return globals.localFileSystem
- .file(flutterServiceWorkerJsPath)
- .readAsStringSync()
- .replaceAll(
- r'$$RESOURCES_MAP',
- '{${resources.entries.map((MapEntry<String, String> entry) => '"${entry.key}": "${entry.value}"').join(",\n")}}',
- )
- .replaceAll(
- r'$$CORE_LIST',
- '[${coreBundle.map((String file) => '"$file"').join(',\n')}]',
- );
+});
+
+// During activate, the cache is populated with the temp files downloaded in
+// install. If this service worker is upgrading from one with a saved
+// MANIFEST, then use this to retain unchanged resource files.
+self.addEventListener("activate", function(event) {
+ return event.waitUntil(async function() {
+ try {
+ var contentCache = await caches.open(CACHE_NAME);
+ var tempCache = await caches.open(TEMP);
+ var manifestCache = await caches.open(MANIFEST);
+ var manifest = await manifestCache.match('manifest');
+ // When there is no prior manifest, clear the entire cache.
+ if (!manifest) {
+ await caches.delete(CACHE_NAME);
+ contentCache = await caches.open(CACHE_NAME);
+ for (var request of await tempCache.keys()) {
+ var response = await tempCache.match(request);
+ await contentCache.put(request, response);
+ }
+ await caches.delete(TEMP);
+ // Save the manifest to make future upgrades efficient.
+ await manifestCache.put('manifest', new Response(JSON.stringify(RESOURCES)));
+ // Claim client to enable caching on first launch
+ self.clients.claim();
+ return;
+ }
+ var oldManifest = await manifest.json();
+ var origin = self.location.origin;
+ for (var request of await contentCache.keys()) {
+ var key = request.url.substring(origin.length + 1);
+ if (key == "") {
+ key = "/";
+ }
+ // If a resource from the old manifest is not in the new cache, or if
+ // the MD5 sum has changed, delete it. Otherwise the resource is left
+ // in the cache and can be reused by the new service worker.
+ if (!RESOURCES[key] || RESOURCES[key] != oldManifest[key]) {
+ await contentCache.delete(request);
+ }
+ }
+ // Populate the cache with the app shell TEMP files, potentially overwriting
+ // cache files preserved above.
+ for (var request of await tempCache.keys()) {
+ var response = await tempCache.match(request);
+ await contentCache.put(request, response);
+ }
+ await caches.delete(TEMP);
+ // Save the manifest to make future upgrades efficient.
+ await manifestCache.put('manifest', new Response(JSON.stringify(RESOURCES)));
+ // Claim client to enable caching on first launch
+ self.clients.claim();
+ return;
+ } catch (err) {
+ // On an unhandled exception the state of the cache cannot be guaranteed.
+ console.error('Failed to upgrade service worker: ' + err);
+ await caches.delete(CACHE_NAME);
+ await caches.delete(TEMP);
+ await caches.delete(MANIFEST);
+ }
+ }());
+});
+
+// The fetch handler redirects requests for RESOURCE files to the service
+// worker cache.
+self.addEventListener("fetch", (event) => {
+ if (event.request.method !== 'GET') {
+ return;
+ }
+ var origin = self.location.origin;
+ var key = event.request.url.substring(origin.length + 1);
+ // Redirect URLs to the index.html
+ if (key.indexOf('?v=') != -1) {
+ key = key.split('?v=')[0];
+ }
+ if (event.request.url == origin || event.request.url.startsWith(origin + '/#') || key == '') {
+ key = '/';
+ }
+ // If the URL is not the RESOURCE list then return to signal that the
+ // browser should take over.
+ if (!RESOURCES[key]) {
+ return;
+ }
+ // If the URL is the index.html, perform an online-first request.
+ if (key == '/') {
+ return onlineFirst(event);
+ }
+ event.respondWith(caches.open(CACHE_NAME)
+ .then((cache) => {
+ return cache.match(event.request).then((response) => {
+ // Either respond with the cached resource, or perform a fetch and
+ // lazily populate the cache only if the resource was successfully fetched.
+ return response || fetch(event.request).then((response) => {
+ if (response && Boolean(response.ok)) {
+ cache.put(event.request, response.clone());
+ }
+ return response;
+ });
+ })
+ })
+ );
+});
+
+self.addEventListener('message', (event) => {
+ // SkipWaiting can be used to immediately activate a waiting service worker.
+ // This will also require a page refresh triggered by the main worker.
+ if (event.data === 'skipWaiting') {
+ self.skipWaiting();
+ return;
+ }
+ if (event.data === 'downloadOffline') {
+ downloadOffline();
+ return;
+ }
+});
+
+// Download offline will check the RESOURCES for all files not in the cache
+// and populate them.
+async function downloadOffline() {
+ var resources = [];
+ var contentCache = await caches.open(CACHE_NAME);
+ var currentContent = {};
+ for (var request of await contentCache.keys()) {
+ var key = request.url.substring(origin.length + 1);
+ if (key == "") {
+ key = "/";
+ }
+ currentContent[key] = true;
+ }
+ for (var resourceKey of Object.keys(RESOURCES)) {
+ if (!currentContent[resourceKey]) {
+ resources.push(resourceKey);
+ }
+ }
+ return contentCache.addAll(resources);
+}
+
+// Attempt to download the resource online before falling back to
+// the offline cache.
+function onlineFirst(event) {
+ return event.respondWith(
+ fetch(event.request).then((response) => {
+ return caches.open(CACHE_NAME).then((cache) => {
+ cache.put(event.request, response.clone());
+ return response;
+ });
+ }).catch((error) => {
+ return caches.open(CACHE_NAME).then((cache) => {
+ return cache.match(event.request).then((response) => {
+ if (response != null) {
+ return response;
+ }
+ throw error;
+ });
+ });
+ })
+ );
+}
+''';
}
diff --git a/packages/flutter_tools/lib/src/web/file_generators/js/flutter.js b/packages/flutter_tools/lib/src/web/file_generators/js/flutter.js
deleted file mode 100644
index bdf438b..0000000
--- a/packages/flutter_tools/lib/src/web/file_generators/js/flutter.js
+++ /dev/null
@@ -1,375 +0,0 @@
-// Copyright 2014 The Flutter Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-if (!_flutter) {
- var _flutter = {};
-}
-_flutter.loader = null;
-
-(function () {
- "use strict";
-
- const baseUri = ensureTrailingSlash(getBaseURI());
-
- function getBaseURI() {
- const base = document.querySelector("base");
- return (base && base.getAttribute("href")) || "";
- }
-
- function ensureTrailingSlash(uri) {
- if (uri == "") {
- return uri;
- }
- return uri.endsWith("/") ? uri : `${uri}/`;
- }
-
- /**
- * Wraps `promise` in a timeout of the given `duration` in ms.
- *
- * Resolves/rejects with whatever the original `promises` does, or rejects
- * if `promise` takes longer to complete than `duration`. In that case,
- * `debugName` is used to compose a legible error message.
- *
- * If `duration` is < 0, the original `promise` is returned unchanged.
- * @param {Promise} promise
- * @param {number} duration
- * @param {string} debugName
- * @returns {Promise} a wrapped promise.
- */
- async function timeout(promise, duration, debugName) {
- if (duration < 0) {
- return promise;
- }
- let timeoutId;
- const _clock = new Promise((_, reject) => {
- timeoutId = setTimeout(() => {
- reject(
- new Error(
- `${debugName} took more than ${duration}ms to resolve. Moving on.`,
- {
- cause: timeout,
- }
- )
- );
- }, duration);
- });
-
- return Promise.race([promise, _clock]).finally(() => {
- clearTimeout(timeoutId);
- });
- }
-
- /**
- * Handles the creation of a TrustedTypes `policy` that validates URLs based
- * on an (optional) incoming array of RegExes.
- */
- class FlutterTrustedTypesPolicy {
- /**
- * Constructs the policy.
- * @param {[RegExp]} validPatterns the patterns to test URLs
- * @param {String} policyName the policy name (optional)
- */
- constructor(validPatterns, policyName = "flutter-js") {
- const patterns = validPatterns || [
- /\.dart\.js$/,
- /^flutter_service_worker.js$/
- ];
- if (window.trustedTypes) {
- this.policy = trustedTypes.createPolicy(policyName, {
- createScriptURL: function(url) {
- const parsed = new URL(url, window.location);
- const file = parsed.pathname.split("/").pop();
- const matches = patterns.some((pattern) => pattern.test(file));
- if (matches) {
- return parsed.toString();
- }
- console.error(
- "URL rejected by TrustedTypes policy",
- policyName, ":", url, "(download prevented)");
- }
- });
- }
- }
- }
-
- /**
- * Handles loading/reloading Flutter's service worker, if configured.
- *
- * @see: https://developers.google.com/web/fundamentals/primers/service-workers
- */
- class FlutterServiceWorkerLoader {
- /**
- * Injects a TrustedTypesPolicy (or undefined if the feature is not supported).
- * @param {TrustedTypesPolicy | undefined} policy
- */
- setTrustedTypesPolicy(policy) {
- this._ttPolicy = policy;
- }
-
- /**
- * Returns a Promise that resolves when the latest Flutter service worker,
- * configured by `settings` has been loaded and activated.
- *
- * Otherwise, the promise is rejected with an error message.
- * @param {*} settings Service worker settings
- * @returns {Promise} that resolves when the latest serviceWorker is ready.
- */
- loadServiceWorker(settings) {
- if (!("serviceWorker" in navigator) || settings == null) {
- // In the future, settings = null -> uninstall service worker?
- return Promise.reject(
- new Error("Service worker not supported (or configured).")
- );
- }
- const {
- serviceWorkerVersion,
- serviceWorkerUrl = `${baseUri}flutter_service_worker.js?v=${serviceWorkerVersion}`,
- timeoutMillis = 4000,
- } = settings;
-
- // Apply the TrustedTypes policy, if present.
- let url = serviceWorkerUrl;
- if (this._ttPolicy != null) {
- url = this._ttPolicy.createScriptURL(url);
- }
-
- const serviceWorkerActivation = navigator.serviceWorker
- .register(url)
- .then(this._getNewServiceWorker)
- .then(this._waitForServiceWorkerActivation);
-
- // Timeout race promise
- return timeout(
- serviceWorkerActivation,
- timeoutMillis,
- "prepareServiceWorker"
- );
- }
-
- /**
- * Returns the latest service worker for the given `serviceWorkerRegistrationPromise`.
- *
- * This might return the current service worker, if there's no new service worker
- * awaiting to be installed/updated.
- *
- * @param {Promise<ServiceWorkerRegistration>} serviceWorkerRegistrationPromise
- * @returns {Promise<ServiceWorker>}
- */
- async _getNewServiceWorker(serviceWorkerRegistrationPromise) {
- const reg = await serviceWorkerRegistrationPromise;
-
- if (!reg.active && (reg.installing || reg.waiting)) {
- // No active web worker and we have installed or are installing
- // one for the first time. Simply wait for it to activate.
- console.debug("Installing/Activating first service worker.");
- return reg.installing || reg.waiting;
- } else if (!reg.active.scriptURL.endsWith(serviceWorkerVersion)) {
- // When the app updates the serviceWorkerVersion changes, so we
- // need to ask the service worker to update.
- return reg.update().then((newReg) => {
- console.debug("Updating service worker.");
- return newReg.installing || newReg.waiting || newReg.active;
- });
- } else {
- console.debug("Loading from existing service worker.");
- return reg.active;
- }
- }
-
- /**
- * Returns a Promise that resolves when the `latestServiceWorker` changes its
- * state to "activated".
- *
- * @param {Promise<ServiceWorker>} latestServiceWorkerPromise
- * @returns {Promise<void>}
- */
- async _waitForServiceWorkerActivation(latestServiceWorkerPromise) {
- const serviceWorker = await latestServiceWorkerPromise;
-
- if (!serviceWorker || serviceWorker.state == "activated") {
- if (!serviceWorker) {
- return Promise.reject(
- new Error("Cannot activate a null service worker!")
- );
- } else {
- console.debug("Service worker already active.");
- return Promise.resolve();
- }
- }
- return new Promise((resolve, _) => {
- serviceWorker.addEventListener("statechange", () => {
- if (serviceWorker.state == "activated") {
- console.debug("Activated new service worker.");
- resolve();
- }
- });
- });
- }
- }
-
- /**
- * Handles injecting the main Flutter web entrypoint (main.dart.js), and notifying
- * the user when Flutter is ready, through `didCreateEngineInitializer`.
- *
- * @see https://docs.flutter.dev/development/platform-integration/web/initialization
- */
- class FlutterEntrypointLoader {
- /**
- * Creates a FlutterEntrypointLoader.
- */
- constructor() {
- // Watchdog to prevent injecting the main entrypoint multiple times.
- this._scriptLoaded = false;
- }
-
- /**
- * Injects a TrustedTypesPolicy (or undefined if the feature is not supported).
- * @param {TrustedTypesPolicy | undefined} policy
- */
- setTrustedTypesPolicy(policy) {
- this._ttPolicy = policy;
- }
-
- /**
- * Loads flutter main entrypoint, specified by `entrypointUrl`, and calls a
- * user-specified `onEntrypointLoaded` callback with an EngineInitializer
- * object when it's done.
- *
- * @param {*} options
- * @returns {Promise | undefined} that will eventually resolve with an
- * EngineInitializer, or will be rejected with the error caused by the loader.
- * Returns undefined when an `onEntrypointLoaded` callback is supplied in `options`.
- */
- async loadEntrypoint(options) {
- const { entrypointUrl = `${baseUri}main.dart.js`, onEntrypointLoaded } =
- options || {};
-
- return this._loadEntrypoint(entrypointUrl, onEntrypointLoaded);
- }
-
- /**
- * Resolves the promise created by loadEntrypoint, and calls the `onEntrypointLoaded`
- * function supplied by the user (if needed).
- *
- * Called by Flutter through `_flutter.loader.didCreateEngineInitializer` method,
- * which is bound to the correct instance of the FlutterEntrypointLoader by
- * the FlutterLoader object.
- *
- * @param {Function} engineInitializer @see https://github.com/flutter/engine/blob/main/lib/web_ui/lib/src/engine/js_interop/js_loader.dart#L42
- */
- didCreateEngineInitializer(engineInitializer) {
- if (typeof this._didCreateEngineInitializerResolve === "function") {
- this._didCreateEngineInitializerResolve(engineInitializer);
- // Remove the resolver after the first time, so Flutter Web can hot restart.
- this._didCreateEngineInitializerResolve = null;
- // Make the engine revert to "auto" initialization on hot restart.
- delete _flutter.loader.didCreateEngineInitializer;
- }
- if (typeof this._onEntrypointLoaded === "function") {
- this._onEntrypointLoaded(engineInitializer);
- }
- }
-
- /**
- * Injects a script tag into the DOM, and configures this loader to be able to
- * handle the "entrypoint loaded" notifications received from Flutter web.
- *
- * @param {string} entrypointUrl the URL of the script that will initialize
- * Flutter.
- * @param {Function} onEntrypointLoaded a callback that will be called when
- * Flutter web notifies this object that the entrypoint is
- * loaded.
- * @returns {Promise | undefined} a Promise that resolves when the entrypoint
- * is loaded, or undefined if `onEntrypointLoaded`
- * is a function.
- */
- _loadEntrypoint(entrypointUrl, onEntrypointLoaded) {
- const useCallback = typeof onEntrypointLoaded === "function";
-
- if (!this._scriptLoaded) {
- this._scriptLoaded = true;
- const scriptTag = this._createScriptTag(entrypointUrl);
- if (useCallback) {
- // Just inject the script tag, and return nothing; Flutter will call
- // `didCreateEngineInitializer` when it's done.
- console.debug("Injecting <script> tag. Using callback.");
- this._onEntrypointLoaded = onEntrypointLoaded;
- document.body.append(scriptTag);
- } else {
- // Inject the script tag and return a promise that will get resolved
- // with the EngineInitializer object from Flutter when it calls
- // `didCreateEngineInitializer` later.
- return new Promise((resolve, reject) => {
- console.debug(
- "Injecting <script> tag. Using Promises. Use the callback approach instead!"
- );
- this._didCreateEngineInitializerResolve = resolve;
- scriptTag.addEventListener("error", reject);
- document.body.append(scriptTag);
- });
- }
- }
- }
-
- /**
- * Creates a script tag for the given URL.
- * @param {string} url
- * @returns {HTMLScriptElement}
- */
- _createScriptTag(url) {
- const scriptTag = document.createElement("script");
- scriptTag.type = "application/javascript";
- // Apply TrustedTypes validation, if available.
- let trustedUrl = url;
- if (this._ttPolicy != null) {
- trustedUrl = this._ttPolicy.createScriptURL(url);
- }
- scriptTag.src = trustedUrl;
- return scriptTag;
- }
- }
-
- /**
- * The public interface of _flutter.loader. Exposes two methods:
- * * loadEntrypoint (which coordinates the default Flutter web loading procedure)
- * * didCreateEngineInitializer (which is called by Flutter to notify that its
- * Engine is ready to be initialized)
- */
- class FlutterLoader {
- /**
- * Initializes the Flutter web app.
- * @param {*} options
- * @returns {Promise?} a (Deprecated) Promise that will eventually resolve
- * with an EngineInitializer, or will be rejected with
- * any error caused by the loader. Or Null, if the user
- * supplies an `onEntrypointLoaded` Function as an option.
- */
- async loadEntrypoint(options) {
- const { serviceWorker, ...entrypoint } = options || {};
-
- // A Trusted Types policy that is going to be used by the loader.
- const flutterTT = new FlutterTrustedTypesPolicy();
-
- // The FlutterServiceWorkerLoader instance could be injected as a dependency
- // (and dynamically imported from a module if not present).
- const serviceWorkerLoader = new FlutterServiceWorkerLoader();
- serviceWorkerLoader.setTrustedTypesPolicy(flutterTT.policy);
- await serviceWorkerLoader.loadServiceWorker(serviceWorker).catch(e => {
- // Regardless of what happens with the injection of the SW, the show must go on
- console.warn("Exception while loading service worker:", e);
- });
-
- // The FlutterEntrypointLoader instance could be injected as a dependency
- // (and dynamically imported from a module if not present).
- const entrypointLoader = new FlutterEntrypointLoader();
- entrypointLoader.setTrustedTypesPolicy(flutterTT.policy);
- // Install the `didCreateEngineInitializer` listener where Flutter web expects it to be.
- this.didCreateEngineInitializer =
- entrypointLoader.didCreateEngineInitializer.bind(entrypointLoader);
- return entrypointLoader.loadEntrypoint(entrypoint);
- }
- }
-
- _flutter.loader = new FlutterLoader();
-})();
diff --git a/packages/flutter_tools/lib/src/web/file_generators/js/flutter_service_worker.js b/packages/flutter_tools/lib/src/web/file_generators/js/flutter_service_worker.js
deleted file mode 100644
index 7a5b124..0000000
--- a/packages/flutter_tools/lib/src/web/file_generators/js/flutter_service_worker.js
+++ /dev/null
@@ -1,172 +0,0 @@
-'use strict';
-const MANIFEST = 'flutter-app-manifest';
-const TEMP = 'flutter-temp-cache';
-const CACHE_NAME = 'flutter-app-cache';
-
-const RESOURCES = $$RESOURCES_MAP;
-// The application shell files that are downloaded before a service worker can
-// start.
-const CORE = $$CORE_LIST;
-
-// During install, the TEMP cache is populated with the application shell files.
-self.addEventListener("install", (event) => {
- self.skipWaiting();
- return event.waitUntil(
- caches.open(TEMP).then((cache) => {
- return cache.addAll(
- CORE.map((value) => new Request(value, {'cache': 'reload'})));
- })
- );
-});
-// During activate, the cache is populated with the temp files downloaded in
-// install. If this service worker is upgrading from one with a saved
-// MANIFEST, then use this to retain unchanged resource files.
-self.addEventListener("activate", function(event) {
- return event.waitUntil(async function() {
- try {
- var contentCache = await caches.open(CACHE_NAME);
- var tempCache = await caches.open(TEMP);
- var manifestCache = await caches.open(MANIFEST);
- var manifest = await manifestCache.match('manifest');
- // When there is no prior manifest, clear the entire cache.
- if (!manifest) {
- await caches.delete(CACHE_NAME);
- contentCache = await caches.open(CACHE_NAME);
- for (var request of await tempCache.keys()) {
- var response = await tempCache.match(request);
- await contentCache.put(request, response);
- }
- await caches.delete(TEMP);
- // Save the manifest to make future upgrades efficient.
- await manifestCache.put('manifest', new Response(JSON.stringify(RESOURCES)));
- // Claim client to enable caching on first launch
- self.clients.claim();
- return;
- }
- var oldManifest = await manifest.json();
- var origin = self.location.origin;
- for (var request of await contentCache.keys()) {
- var key = request.url.substring(origin.length + 1);
- if (key == "") {
- key = "/";
- }
- // If a resource from the old manifest is not in the new cache, or if
- // the MD5 sum has changed, delete it. Otherwise the resource is left
- // in the cache and can be reused by the new service worker.
- if (!RESOURCES[key] || RESOURCES[key] != oldManifest[key]) {
- await contentCache.delete(request);
- }
- }
- // Populate the cache with the app shell TEMP files, potentially overwriting
- // cache files preserved above.
- for (var request of await tempCache.keys()) {
- var response = await tempCache.match(request);
- await contentCache.put(request, response);
- }
- await caches.delete(TEMP);
- // Save the manifest to make future upgrades efficient.
- await manifestCache.put('manifest', new Response(JSON.stringify(RESOURCES)));
- // Claim client to enable caching on first launch
- self.clients.claim();
- return;
- } catch (err) {
- // On an unhandled exception the state of the cache cannot be guaranteed.
- console.error('Failed to upgrade service worker: ' + err);
- await caches.delete(CACHE_NAME);
- await caches.delete(TEMP);
- await caches.delete(MANIFEST);
- }
- }());
-});
-// The fetch handler redirects requests for RESOURCE files to the service
-// worker cache.
-self.addEventListener("fetch", (event) => {
- if (event.request.method !== 'GET') {
- return;
- }
- var origin = self.location.origin;
- var key = event.request.url.substring(origin.length + 1);
- // Redirect URLs to the index.html
- if (key.indexOf('?v=') != -1) {
- key = key.split('?v=')[0];
- }
- if (event.request.url == origin || event.request.url.startsWith(origin + '/#') || key == '') {
- key = '/';
- }
- // If the URL is not the RESOURCE list then return to signal that the
- // browser should take over.
- if (!RESOURCES[key]) {
- return;
- }
- // If the URL is the index.html, perform an online-first request.
- if (key == '/') {
- return onlineFirst(event);
- }
- event.respondWith(caches.open(CACHE_NAME)
- .then((cache) => {
- return cache.match(event.request).then((response) => {
- // Either respond with the cached resource, or perform a fetch and
- // lazily populate the cache only if the resource was successfully fetched.
- return response || fetch(event.request).then((response) => {
- if (response && Boolean(response.ok)) {
- cache.put(event.request, response.clone());
- }
- return response;
- });
- })
- })
- );
-});
-self.addEventListener('message', (event) => {
- // SkipWaiting can be used to immediately activate a waiting service worker.
- // This will also require a page refresh triggered by the main worker.
- if (event.data === 'skipWaiting') {
- self.skipWaiting();
- return;
- }
- if (event.data === 'downloadOffline') {
- downloadOffline();
- return;
- }
-});
-// Download offline will check the RESOURCES for all files not in the cache
-// and populate them.
-async function downloadOffline() {
- var resources = [];
- var contentCache = await caches.open(CACHE_NAME);
- var currentContent = {};
- for (var request of await contentCache.keys()) {
- var key = request.url.substring(origin.length + 1);
- if (key == "") {
- key = "/";
- }
- currentContent[key] = true;
- }
- for (var resourceKey of Object.keys(RESOURCES)) {
- if (!currentContent[resourceKey]) {
- resources.push(resourceKey);
- }
- }
- return contentCache.addAll(resources);
-}
-// Attempt to download the resource online before falling back to
-// the offline cache.
-function onlineFirst(event) {
- return event.respondWith(
- fetch(event.request).then((response) => {
- return caches.open(CACHE_NAME).then((cache) => {
- cache.put(event.request, response.clone());
- return response;
- });
- }).catch((error) => {
- return caches.open(CACHE_NAME).then((cache) => {
- return cache.match(event.request).then((response) => {
- if (response != null) {
- return response;
- }
- throw error;
- });
- });
- })
- );
-}
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 c093ea0..05eda1d 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
@@ -785,40 +785,19 @@
}));
test('Generated service worker is empty with none-strategy', () {
- final String fileGeneratorsPath =
- environment.artifacts.getArtifactPath(Artifact.flutterToolsFileGenerators);
- final String result = generateServiceWorker(
- fileGeneratorsPath,
- <String, String>{'/foo': 'abcd'},
- <String>[],
- serviceWorkerStrategy: ServiceWorkerStrategy.none,
- );
+ final String result = generateServiceWorker(<String, String>{'/foo': 'abcd'}, <String>[], serviceWorkerStrategy: ServiceWorkerStrategy.none);
expect(result, '');
});
test('Generated service worker correctly inlines file hashes', () {
- final String fileGeneratorsPath =
- environment.artifacts.getArtifactPath(Artifact.flutterToolsFileGenerators);
- final String result = generateServiceWorker(
- fileGeneratorsPath,
- <String, String>{'/foo': 'abcd'},
- <String>[],
- serviceWorkerStrategy: ServiceWorkerStrategy.offlineFirst,
- );
+ final String result = generateServiceWorker(<String, String>{'/foo': 'abcd'}, <String>[], serviceWorkerStrategy: ServiceWorkerStrategy.offlineFirst);
- expect(result, contains('{"/foo": "abcd"};'));
+ expect(result, contains('{\n "/foo": "abcd"\n};'));
});
test('Generated service worker includes core files', () {
- final String fileGeneratorsPath =
- environment.artifacts.getArtifactPath(Artifact.flutterToolsFileGenerators);
- final String result = generateServiceWorker(
- fileGeneratorsPath,
- <String, String>{'/foo': 'abcd'},
- <String>['foo', 'bar'],
- serviceWorkerStrategy: ServiceWorkerStrategy.offlineFirst,
- );
+ final String result = generateServiceWorker(<String, String>{'/foo': 'abcd'}, <String>['foo', 'bar'], serviceWorkerStrategy: ServiceWorkerStrategy.offlineFirst);
expect(result, contains('"foo",\n"bar"'));
});
@@ -875,10 +854,7 @@
}));
test('flutter.js sanity checks', () {
- final String fileGeneratorsPath = environment.artifacts
- .getArtifactPath(Artifact.flutterToolsFileGenerators);
- final String flutterJsContents =
- flutter_js.generateFlutterJsFile(fileGeneratorsPath);
+ final String flutterJsContents = flutter_js.generateFlutterJsFile();
expect(flutterJsContents, contains('"use strict";'));
expect(flutterJsContents, contains('main.dart.js'));
expect(flutterJsContents, contains('flutter_service_worker.js?v='));
@@ -897,14 +873,8 @@
await WebBuiltInAssets(globals.fs, globals.cache, false).build(environment);
// No caching of source maps.
- final String fileGeneratorsPath = environment.artifacts
- .getArtifactPath(Artifact.flutterToolsFileGenerators);
- final String flutterJsContents =
- flutter_js.generateFlutterJsFile(fileGeneratorsPath);
- expect(
- environment.outputDir.childFile('flutter.js').readAsStringSync(),
- equals(flutterJsContents),
- );
+ expect(environment.outputDir.childFile('flutter.js').readAsStringSync(),
+ equals(flutter_js.generateFlutterJsFile()));
}));
test('wasm build copies and generates specific files', () => testbed.run(() async {
diff --git a/packages/flutter_tools/test/integration.shard/test_data/project.dart b/packages/flutter_tools/test/integration.shard/test_data/project.dart
index 54d7fb8..2bd9efa 100644
--- a/packages/flutter_tools/test/integration.shard/test_data/project.dart
+++ b/packages/flutter_tools/test/integration.shard/test_data/project.dart
@@ -3,7 +3,6 @@
// found in the LICENSE file.
import 'package:file/file.dart';
-import 'package:flutter_tools/src/artifacts.dart';
import 'package:flutter_tools/src/web/file_generators/flutter_js.dart';
import '../test_utils.dart';
@@ -60,13 +59,9 @@
}
deferredComponents?.setUpIn(dir);
- final String fileGeneratorsPath =
- Artifacts.test().getArtifactPath(Artifact.flutterToolsFileGenerators);
- final String flutterJsContents = generateFlutterJsFile(fileGeneratorsPath);
-
// Setup for different flutter web initializations
writeFile(fileSystem.path.join(dir.path, 'web', 'index.html'), indexHtml);
- writeFile(fileSystem.path.join(dir.path, 'web', 'flutter.js'), flutterJsContents);
+ writeFile(fileSystem.path.join(dir.path, 'web', 'flutter.js'), generateFlutterJsFile());
writeFile(fileSystem.path.join(dir.path, 'web', 'flutter_service_worker.js'), '');
writePackages(dir.path);
await getPackages(dir.path);