Skip to content

Commit

Permalink
make hot reload reflect changes to asset transformer configurations
Browse files Browse the repository at this point in the history
  • Loading branch information
andrewkolos committed Mar 6, 2024
1 parent bbb0052 commit 5bb43aa
Show file tree
Hide file tree
Showing 3 changed files with 101 additions and 7 deletions.
39 changes: 33 additions & 6 deletions packages/flutter_tools/lib/src/asset.dart
Expand Up @@ -14,6 +14,7 @@ import 'base/deferred_component.dart';
import 'base/file_system.dart';
import 'base/logger.dart';
import 'base/platform.dart';
import 'base/utils.dart';
import 'build_info.dart';
import 'cache.dart';
import 'convert.dart';
Expand Down Expand Up @@ -84,9 +85,8 @@ enum AssetKind {

/// Contains all information about an asset needed by tool the to prepare and
/// copy an asset file to the build output.
@immutable
final class AssetBundleEntry {
const AssetBundleEntry(this.content, {
AssetBundleEntry(this.content, {
required this.kind,
required this.transformers,
});
Expand All @@ -95,7 +95,27 @@ final class AssetBundleEntry {
final AssetKind kind;
final List<AssetTransformerEntry> transformers;

bool _hasModifiedBeenCalled = false;
bool get isModified {
if (!_hasModifiedBeenCalled) {
_hasModifiedBeenCalled = true;
content.isModified;
return true;
}
return content.isModified;
}

final DateTime creationTime = DateTime.now();

bool isModifiedAfter(DateTime dateTime) {
return content.isModifiedAfter(dateTime) || creationTime.isAfter(dateTime);
}

Future<List<int>> contentsAsBytes() => content.contentsAsBytes();

bool hasEquivalentConfigurationWith(AssetBundleEntry other) {
return listEquals(transformers, other.transformers);
}
}

abstract class AssetBundle {
Expand Down Expand Up @@ -425,11 +445,11 @@ class ManifestAssetBundle implements AssetBundle {
final File variantFile = variant.lookupAssetFile(_fileSystem);
inputFiles.add(variantFile);
assert(variantFile.existsSync());
entries[variant.entryUri.path] ??= AssetBundleEntry(
_setIfConfigurationChanged(entries, variant.entryUri.path, AssetBundleEntry(
DevFSFileContent(variantFile),
kind: variant.kind,
transformers: variant.transformers,
);
));
}
}
// Save the contents of each deferred component image, image variant, and font
Expand Down Expand Up @@ -459,11 +479,11 @@ class ManifestAssetBundle implements AssetBundle {
for (final _Asset variant in assetsMap[asset]!) {
final File variantFile = variant.lookupAssetFile(_fileSystem);
assert(variantFile.existsSync());
deferredComponentsEntries[componentName]![variant.entryUri.path] ??= AssetBundleEntry(
_setIfConfigurationChanged(deferredComponentsEntries[componentName]!, variant.entryUri.path, AssetBundleEntry(
DevFSFileContent(variantFile),
kind: AssetKind.regular,
transformers: variant.transformers,
);
));
}
}
}
Expand Down Expand Up @@ -563,6 +583,13 @@ class ManifestAssetBundle implements AssetBundle {
return true;
}

void _setIfConfigurationChanged(Map<String, AssetBundleEntry> entryMap, String key, AssetBundleEntry entry,) {
final AssetBundleEntry? existingEntry = entryMap[key];
if (existingEntry == null || !entry.hasEquivalentConfigurationWith(existingEntry)) {
entryMap[key] = entry;
}
}

void _setLicenseIfChanged(
String combinedLicenses,
TargetPlatform? targetPlatform,
Expand Down
2 changes: 1 addition & 1 deletion packages/flutter_tools/lib/src/devfs.dart
Expand Up @@ -638,7 +638,7 @@ class DevFS {
bundle.entries.forEach((String archivePath, AssetBundleEntry entry) {
// If the content is backed by a real file, isModified will file stat and return true if
// it was modified since the last time this was called.
if (!entry.content.isModified || bundleFirstUpload) {
if (!entry.isModified || bundleFirstUpload) {
return;
}
// Modified shaders must be recompiled per-target platform.
Expand Down
67 changes: 67 additions & 0 deletions packages/flutter_tools/test/general.shard/asset_bundle_test.dart
Expand Up @@ -428,6 +428,73 @@ flutter:
),
);
});

testWithoutContext("AssetBundleEntry::isModified is true when an asset's transformers change in between builds", () async {
final FileSystem fileSystem = MemoryFileSystem.test();

fileSystem.file('my-asset.txt').createSync();

final BufferLogger logger = BufferLogger.test();
final FakePlatform platform = FakePlatform();
fileSystem.file('.packages').createSync();
fileSystem.file('pubspec.yaml')
..createSync()
..writeAsStringSync(r'''
name: example
flutter:
assets:
- path: my-asset.txt
transformers:
- package: my-transformer-one
''');
final ManifestAssetBundle bundle = ManifestAssetBundle(
logger: logger,
fileSystem: fileSystem,
platform: platform,
flutterRoot: Cache.defaultFlutterRoot(
platform: platform,
fileSystem: fileSystem,
userMessages: UserMessages(),
),
);

await bundle.build(
packagesPath: '.packages',
flutterProject: FlutterProject.fromDirectoryTest(
fileSystem.currentDirectory,
),
);

expect(bundle.entries['my-asset.txt']!.isModified, isTrue);

await bundle.build(
packagesPath: '.packages',
flutterProject: FlutterProject.fromDirectoryTest(
fileSystem.currentDirectory,
),
);

expect(bundle.entries['my-asset.txt']!.isModified, isFalse);

fileSystem.file('pubspec.yaml').writeAsStringSync(r'''
name: example
flutter:
assets:
- path: my-asset.txt
transformers:
- package: my-transformer-one
- package: my-transformer-two
''');

await bundle.build(
packagesPath: '.packages',
flutterProject: FlutterProject.fromDirectoryTest(
fileSystem.currentDirectory,
),
);

expect(bundle.entries['my-asset.txt']!.isModified, isTrue);
});
});

group('AssetBundle.build (web builds)', () {
Expand Down

0 comments on commit 5bb43aa

Please sign in to comment.