use link hooks and const loading
diff --git a/packages/vector_graphics/lib/src/loader.dart b/packages/vector_graphics/lib/src/loader.dart index 8b49e3a..c4640a0 100644 --- a/packages/vector_graphics/lib/src/loader.dart +++ b/packages/vector_graphics/lib/src/loader.dart
@@ -2,9 +2,12 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +// ignore_for_file: experimental_member_use + import 'package:flutter/services.dart'; import 'package:flutter/widgets.dart'; import 'package:http/http.dart' as http; +import 'package:meta/meta.dart' show RecordUse, mustBeConst; /// An interface that can be implemented to support decoding vector graphic /// binary assets from different byte sources. @@ -36,6 +39,27 @@ Object cacheKey(BuildContext? context) => this; } +/// The magic prefix to prevent accidental non-const loading. +/// +/// Must be the same as when storing the asset in build.dart. +/// +/// TODO: move to a common location. +const magicPrefix = 'svg1234:'; + +/// Loads vector graphics data from an asset bundle. +@RecordUse() +class ConstAssetBytesLoader extends AssetBytesLoader { + /// + const ConstAssetBytesLoader( + @mustBeConst super.assetName, { + super.packageName, + super.assetBundle, + }); + + @override + String get assetName => magicPrefix + super.assetName; +} + /// Loads vector graphics data from an asset bundle. /// /// This loader does not cache bytes by default. The Flutter framework @@ -73,9 +97,11 @@ @override Future<ByteData> loadBytes(BuildContext? context) { - return _resolveBundle(context).load( - packageName == null ? assetName : 'packages/$packageName/$assetName', - ); + final String key = packageName == null + ? assetName + : 'packages/$packageName/$assetName'; + print('load $key'); + return _resolveBundle(context).load(key); } @override
diff --git a/packages/vector_graphics/lib/vector_graphics.dart b/packages/vector_graphics/lib/vector_graphics.dart index 6eecdc6..3b8d72a 100644 --- a/packages/vector_graphics/lib/vector_graphics.dart +++ b/packages/vector_graphics/lib/vector_graphics.dart
@@ -6,6 +6,7 @@ show AssetBytesLoader, BytesLoader, + ConstAssetBytesLoader, NetworkBytesLoader, PictureInfo, VectorGraphic,
diff --git a/packages/vector_graphics/pubspec.yaml b/packages/vector_graphics/pubspec.yaml index f759063..dcc860e 100644 --- a/packages/vector_graphics/pubspec.yaml +++ b/packages/vector_graphics/pubspec.yaml
@@ -12,6 +12,7 @@ flutter: sdk: flutter http: ^1.0.0 + meta: ^1.17.0 vector_graphics_codec: ^1.1.11+1 dev_dependencies:
diff --git a/packages/vector_graphics_compiler/example/hook/build.dart b/packages/vector_graphics_compiler/example/hook/build.dart index 868c886..36d62a9 100644 --- a/packages/vector_graphics_compiler/example/hook/build.dart +++ b/packages/vector_graphics_compiler/example/hook/build.dart
@@ -7,12 +7,11 @@ void main(List<String> args) { build(args, (BuildInput input, BuildOutputBuilder output) async { - await compileSvg( + await addSvg( input, output, - name: 'example_file', - file: input.packageRoot.resolve('assets/example.svg'), - options: const Options(dumpDebug: true, concurrency: 2), + file: 'assets/example.svg', + treeshakeable: true, ); }); }
diff --git a/packages/vector_graphics_compiler/example/lib/main.dart b/packages/vector_graphics_compiler/example/lib/main.dart index d775769..2f4cdf8 100644 --- a/packages/vector_graphics_compiler/example/lib/main.dart +++ b/packages/vector_graphics_compiler/example/lib/main.dart
@@ -22,7 +22,10 @@ home: const Scaffold( body: Center( child: VectorGraphic( - loader: AssetBytesLoader('example_file', packageName: 'example'), + loader: ConstAssetBytesLoader( + 'assets/example.svg', + packageName: 'example', + ), ), ), ),
diff --git a/packages/vector_graphics_compiler/hook/link.dart b/packages/vector_graphics_compiler/hook/link.dart new file mode 100644 index 0000000..389d2ac --- /dev/null +++ b/packages/vector_graphics_compiler/hook/link.dart
@@ -0,0 +1,15 @@ +import 'package:data_assets/data_assets.dart'; +import 'package:hooks/hooks.dart'; +import 'package:vector_graphics_compiler/build.dart'; + +Future<void> main(List<String> arguments) async { + await link(arguments, (input, output) async { + await compileSvgs( + input, + output, + nameToFile: Map.fromEntries( + input.assets.data.map((e) => MapEntry(e.name, e.file)), + ), + ); + }); +}
diff --git a/packages/vector_graphics_compiler/lib/build.dart b/packages/vector_graphics_compiler/lib/build.dart index bd154ff..02f415a 100644 --- a/packages/vector_graphics_compiler/lib/build.dart +++ b/packages/vector_graphics_compiler/lib/build.dart
@@ -11,27 +11,85 @@ import 'src/util/isolate_processor.dart'; import 'vector_graphics_compiler.dart'; -/// Helper to build svg -Future<void> compileSvg( +/// The magic prefix to prevent accidental non-const loading. +const magicPrefix = 'svg1234:'; + +/// Helper to add svg +Future<void> addSvg( BuildInput input, BuildOutputBuilder output, { - required String name, - required Uri file, + required String file, Options options = const Options(), -}) async => compileSvgs( - input, - output, - nameToFile: <String, Uri>{name: file}, - options: options, -); + + /// Whether this asset should be treeshaken if it's not used. Means that it + /// can only be loaded by the [ConstAssetBytesLoader] which knows about the + /// magic prefix to prevent accidental treeshaking. + required bool treeshakeable, +}) async { + final String prefix = treeshakeable ? magicPrefix : ''; + // If we are linking, then do the compilation there, as we can compile all SVGs at once + if (input.config.linkingEnabled) { + output.assets.data.add( + DataAsset( + package: input.packageName, + name: prefix + file, + file: input.packageRoot.resolve(file), + ), + routing: const ToLinkHook('vector_graphics_compiler'), + ); + } else { + // If we are not linking, then do the compilation here + final Map<String, IOPair> pairs = await _compileSvgs(options, { + prefix + file: input.packageRoot.resolve(file), + }, input.outputDirectory); + for (final MapEntry<String, IOPair>( + key: String name, + value: IOPair(output: String outputPath), + ) + in pairs.entries) { + output.assets.data.add( + DataAsset( + package: input.packageName, + name: name, + file: Uri.file(outputPath), + ), + ); + } + } +} /// Helper to build svgs Future<void> compileSvgs( - BuildInput input, - BuildOutputBuilder output, { + LinkInput input, + LinkOutputBuilder output, { required Map<String, Uri> nameToFile, Options options = const Options(), }) async { + final Map<String, IOPair> pairs = await _compileSvgs( + options, + nameToFile, + input.outputDirectory, + ); + for (final MapEntry<String, IOPair>( + key: String name, + value: IOPair(output: String outputPath), + ) + in pairs.entries) { + output.assets.data.add( + DataAsset( + package: input.packageName, + name: name, + file: Uri.file(outputPath), + ), + ); + } +} + +Future<Map<String, IOPair>> _compileSvgs( + Options options, + Map<String, Uri> nameToFile, + Uri outputDirectory, +) async { final processor = IsolateProcessor( options.libpathops, options.libtessellator, @@ -43,7 +101,7 @@ name, IOPair( file.path, - '${p.join(input.outputDirectory.path, p.basenameWithoutExtension(file.path))}.vec', + '${p.join(outputDirectory.path, p.basenameWithoutExtension(file.path))}.vec', ), ), ); @@ -61,19 +119,7 @@ 'Did not succeed for ${pairs.map((String name, IOPair e) => MapEntry<String, String>(name, '$name: ${e.input} -> ${e.output}')).values}', ); } - for (final MapEntry<String, IOPair>( - key: String name, - value: IOPair(output: String outputPath), - ) - in pairs.entries) { - output.assets.data.add( - DataAsset( - package: input.packageName, - name: name, - file: Uri.file(outputPath), - ), - ); - } + return pairs; } /// Options for the processor.
diff --git a/packages/vector_graphics_compiler/pubspec.yaml b/packages/vector_graphics_compiler/pubspec.yaml index 1400650..98bc35e 100644 --- a/packages/vector_graphics_compiler/pubspec.yaml +++ b/packages/vector_graphics_compiler/pubspec.yaml
@@ -39,6 +39,10 @@ vector_graphics: ^1.1.13 vector_math: ^2.1.2 +dependency_overrides: + vector_graphics: + path: ../vector_graphics + flutter: config: enable-dart-data-assets: true