import 'dart:io'; import 'dart:typed_data'; import 'package:archive/archive_io.dart'; /// Packs a directory of static files into a gzip-compressed tar archive /// (contents at the archive root) for a single-shot upload + remote extract. class WebArchive { /// Returns the .tar.gz bytes of [dir]'s contents and the number of files. static (Uint8List, int) tarGz(Directory dir) { final archive = createArchiveFromDirectory(dir, includeDirName: false); // CRITICAL: on Windows the entry names use backslashes; a POSIX `tar` on // the server would then create single files literally named // `assets\main.js` instead of the `assets/main.js` tree — breaking any // app with subdirectories (Angular/React assets, etc.). Force forward // slashes so the archive is valid on Linux. for (final f in archive.files) { f.name = f.name.replaceAll('\\', '/'); } final tar = TarEncoder().encode(archive); final gz = GZipEncoder().encode(tar); final count = archive.files.where((f) => f.isFile).length; // Release the file handles opened while reading the directory so the // source tree isn't left locked (notably on Windows). for (final f in archive.files) { f.closeSync(); } return (Uint8List.fromList(gz), count); } } /// Top-level entry so packaging can run off the UI isolate via `compute`. (Uint8List, int) packageWebDir(String path) => WebArchive.tarGz(Directory(path));