diff --git a/lib/web_ui/lib/src/engine/assets.dart b/lib/web_ui/lib/src/engine/assets.dart index b200f824e4145..3daa73cfc21e3 100644 --- a/lib/web_ui/lib/src/engine/assets.dart +++ b/lib/web_ui/lib/src/engine/assets.dart @@ -24,48 +24,26 @@ const Map testFontUrls = { /// This class downloads assets over the network. /// -/// Assets are resolved relative to [assetsDir] inside the absolute base -/// specified by [assetBase] (optional). -/// -/// By default, URLs are relative to the `` of the current website. +/// The assets are resolved relative to [assetsDir] inside the directory +/// containing the currently executing JS script. class AssetManager { - /// Initializes [AssetManager] with paths. - AssetManager({ - this.assetsDir = _defaultAssetsDir, - String? assetBase, - }) : assert( - assetBase == null || assetBase.endsWith('/'), - '`assetBase` must end with a `/` character.', - ), - _assetBase = assetBase; + /// Initializes [AssetManager] with path to assets relative to baseUrl. + const AssetManager({this.assetsDir = _defaultAssetsDir}); static const String _defaultAssetsDir = 'assets'; /// The directory containing the assets. final String assetsDir; - /// The absolute base URL for assets. - String? _assetBase; - - // Cache a value for `_assetBase` so we don't hit the DOM multiple times. - String get _baseUrl => _assetBase ??= _deprecatedAssetBase ?? ''; - - // Retrieves the `assetBase` value from the DOM. - // - // This warns the user and points them to the new initializeEngine style. - String? get _deprecatedAssetBase { - final DomHTMLMetaElement? meta = domWindow.document - .querySelector('meta[name=assetBase]') as DomHTMLMetaElement?; - - final String? fallbackBaseUrl = meta?.content; - - if (fallbackBaseUrl != null) { - // Warn users that they're using a deprecated configuration style... - domWindow.console.warn('The `assetBase` meta tag is now deprecated.\n' - 'Use engineInitializer.initializeEngine(config) instead.\n' - 'See: https://docs.flutter.dev/development/platform-integration/web/initialization'); - } - return fallbackBaseUrl; + String? get _baseUrl { + return domWindow.document + .querySelectorAll('meta') + .where((DomElement domNode) => domInstanceOfString(domNode, + 'HTMLMetaElement')) + .map((DomElement domNode) => domNode as DomHTMLMetaElement) + .firstWhereOrNull( + (DomHTMLMetaElement element) => element.name == 'assetBase') + ?.content; } /// Returns the URL to load the asset from, given the asset key. @@ -89,7 +67,7 @@ class AssetManager { if (Uri.parse(asset).hasScheme) { return Uri.encodeFull(asset); } - return Uri.encodeFull('$_baseUrl$assetsDir/$asset'); + return Uri.encodeFull('${_baseUrl ?? ''}$assetsDir/$asset'); } /// Loads an asset and returns the server response. @@ -112,7 +90,7 @@ class AssetManager { } /// An asset manager that gives fake empty responses for assets. -class WebOnlyMockAssetManager extends AssetManager { +class WebOnlyMockAssetManager implements AssetManager { /// Mock asset directory relative to base url. String defaultAssetsDir = ''; @@ -135,6 +113,9 @@ class WebOnlyMockAssetManager extends AssetManager { @override String get assetsDir => defaultAssetsDir; + @override + String get _baseUrl => ''; + @override String getAssetUrl(String asset) => asset; @@ -146,7 +127,7 @@ class WebOnlyMockAssetManager extends AssetManager { status: 200, payload: MockHttpFetchPayload( byteBuffer: _toByteData(utf8.encode(defaultAssetManifest)).buffer, - ), + ) ); } if (asset == getAssetUrl('FontManifest.json')) { @@ -155,7 +136,7 @@ class WebOnlyMockAssetManager extends AssetManager { status: 200, payload: MockHttpFetchPayload( byteBuffer: _toByteData(utf8.encode(defaultFontManifest)).buffer, - ), + ) ); } diff --git a/lib/web_ui/lib/src/engine/configuration.dart b/lib/web_ui/lib/src/engine/configuration.dart index 36da43017ec01..5e2d2b24b8764 100644 --- a/lib/web_ui/lib/src/engine/configuration.dart +++ b/lib/web_ui/lib/src/engine/configuration.dart @@ -153,32 +153,6 @@ class FlutterConfiguration { // runtime. Runtime-supplied values take precedence over environment // variables. - /// The absolute base URL of the location of the `assets` directory of the app. - /// - /// This value is useful when Flutter web assets are deployed to a separate - /// domain (or subdirectory) from which the index.html is served, for example: - /// - /// * Application: https://www.my-app.com/ - /// * Flutter Assets: https://cdn.example.com/my-app/build-hash/assets/ - /// - /// The `assetBase` value would be set to: - /// - /// * `'https://cdn.example.com/my-app/build-hash/'` - /// - /// It is also useful in the case that a Flutter web application is embedded - /// into another web app, in a way that the `` tag of the index.html - /// cannot be set (because it'd break the host app), for example: - /// - /// * Application: https://www.my-app.com/ - /// * Flutter Assets: https://www.my-app.com/static/companion/flutter/assets/ - /// - /// The `assetBase` would be set to: - /// - /// * `'/static/companion/flutter/'` - /// - /// Do not confuse this configuration value with [canvasKitBaseUrl]. - String? get assetBase => _configuration?.assetBase; - /// The base URL to use when downloading the CanvasKit script and associated /// wasm. /// @@ -288,10 +262,6 @@ external JsFlutterConfiguration? get _jsConfiguration; class JsFlutterConfiguration {} extension JsFlutterConfigurationExtension on JsFlutterConfiguration { - @JS('assetBase') - external JSString? get _assetBase; - String? get assetBase => _assetBase?.toDart; - @JS('canvasKitBaseUrl') external JSString? get _canvasKitBaseUrl; String? get canvasKitBaseUrl => _canvasKitBaseUrl?.toDart; diff --git a/lib/web_ui/lib/src/engine/initialization.dart b/lib/web_ui/lib/src/engine/initialization.dart index 7db4df0821b93..664bb43ac54e8 100644 --- a/lib/web_ui/lib/src/engine/initialization.dart +++ b/lib/web_ui/lib/src/engine/initialization.dart @@ -211,7 +211,7 @@ Future initializeEngineServices({ } }; - assetManager ??= AssetManager(assetBase: configuration.assetBase); + assetManager ??= const AssetManager(); _setAssetManager(assetManager); Future initializeRendererCallback () async => renderer.initialize(); diff --git a/lib/web_ui/test/engine/assets_test.dart b/lib/web_ui/test/engine/assets_test.dart deleted file mode 100644 index 9c6993b5d510f..0000000000000 --- a/lib/web_ui/test/engine/assets_test.dart +++ /dev/null @@ -1,141 +0,0 @@ -// Copyright 2013 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. - -@TestOn('browser') - -import 'package:test/bootstrap/browser.dart'; -import 'package:test/test.dart'; -import 'package:ui/src/engine.dart'; - -import '../matchers.dart'; - -void main() { - internalBootstrapBrowserTest(() => testMain); -} - -void testMain() { - group('AssetManager getAssetUrl', () { - setUp(() { - // Remove the meta-tag from the environment before each test. - removeAssetBaseMeta(); - }); - - test('initializes with default values', () { - final AssetManager assets = AssetManager(); - - expect( - assets.getAssetUrl('asset.txt'), - 'assets/asset.txt', - reason: 'Default `assetsDir` is "assets".', - ); - }); - - test('assetsDir changes the directory where assets are stored', () { - final AssetManager assets = AssetManager(assetsDir: 'static'); - - expect(assets.getAssetUrl('asset.txt'), 'static/asset.txt'); - }); - - test('assetBase must end with slash', () { - expect(() { - AssetManager(assetBase: '/deployment'); - }, throwsAssertionError); - }); - - test('assetBase can be relative', () { - final AssetManager assets = AssetManager(assetBase: 'base/'); - - expect(assets.getAssetUrl('asset.txt'), 'base/assets/asset.txt'); - }); - - test('assetBase can be absolute', () { - final AssetManager assets = AssetManager( - assetBase: 'https://www.gstatic.com/my-app/', - ); - - expect( - assets.getAssetUrl('asset.txt'), - 'https://www.gstatic.com/my-app/assets/asset.txt', - ); - }); - - test('assetBase in conjunction with assetsDir, fully custom paths', () { - final AssetManager assets = AssetManager( - assetBase: '/asset/base/', - assetsDir: 'static', - ); - - expect(assets.getAssetUrl('asset.txt'), '/asset/base/static/asset.txt'); - }); - - test('Fully-qualified asset URLs are untouched', () { - final AssetManager assets = AssetManager(); - - expect( - assets.getAssetUrl('https://static.my-app.com/favicon.ico'), - 'https://static.my-app.com/favicon.ico', - ); - }); - - test('Fully-qualified asset URLs are untouched (even with assetBase)', () { - final AssetManager assets = AssetManager( - assetBase: 'https://static.my-app.com/', - ); - - expect( - assets.getAssetUrl('https://static.my-app.com/favicon.ico'), - 'https://static.my-app.com/favicon.ico', - ); - }); - }); - - group('AssetManager getAssetUrl with tag', () { - setUp(() { - removeAssetBaseMeta(); - addAssetBaseMeta('/dom/base/'); - }); - - test('reads value from DOM', () { - final AssetManager assets = AssetManager(); - - expect(assets.getAssetUrl('asset.txt'), '/dom/base/assets/asset.txt'); - }); - - test('reads value from DOM (only once!)', () { - final AssetManager firstManager = AssetManager(); - expect( - firstManager.getAssetUrl('asset.txt'), - '/dom/base/assets/asset.txt', - ); - - removeAssetBaseMeta(); - final AssetManager anotherManager = AssetManager(); - - expect( - firstManager.getAssetUrl('asset.txt'), - '/dom/base/assets/asset.txt', - reason: 'The old value of the assetBase meta should be cached.', - ); - expect(anotherManager.getAssetUrl('asset.txt'), 'assets/asset.txt'); - }); - }); -} - -/// Removes all meta-tags with name=assetBase. -void removeAssetBaseMeta() { - domWindow.document - .querySelectorAll('meta[name=assetBase]') - .forEach((DomElement element) { - element.remove(); - }); -} - -/// Adds a meta-tag with name=assetBase and the passed-in [value]. -void addAssetBaseMeta(String value) { - final DomHTMLMetaElement meta = createDomHTMLMetaElement() - ..name = 'assetBase' - ..content = value; - - domDocument.head!.append(meta); -}