-
Notifications
You must be signed in to change notification settings - Fork 0
Compresses the wasm binary to reduce its size when hosted #8
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: dev
Are you sure you want to change the base?
Changes from all commits
a705e6c
78d784f
1cc1f0c
aabdafa
51994a7
e654ec3
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,66 @@ | ||
| export async function loadCompressedWasm(url) { | ||
| try { | ||
| // Fetch the compressed WASM file | ||
| const response = await fetch(url.toString(), { | ||
| method: 'GET', | ||
| cache: 'force-cache', // Use cache if available | ||
| }); | ||
|
|
||
| if (!response.ok) { | ||
| throw new Error( | ||
| `Failed to fetch compressed WASM: ${response.status} ${response.statusText}` | ||
| ); | ||
| } | ||
|
|
||
| // Check if browser supports DecompressionStream | ||
| if (!('DecompressionStream' in globalThis)) { | ||
| throw new Error( | ||
| 'Browser does not support DecompressionStream API. Please use a modern browser.' | ||
| ); | ||
| } | ||
|
|
||
| // Ensure response.body is available | ||
| if (!response.body) { | ||
| throw new Error( | ||
| 'Response body is not available. Streaming not supported or body already consumed.' | ||
| ); | ||
| } | ||
|
|
||
| // Create a decompression stream for gzip | ||
| const decompressionStream = new DecompressionStream('gzip'); | ||
|
|
||
| // Pipe the response through the decompression stream | ||
| const decompressedStream = response.body.pipeThrough(decompressionStream); | ||
|
|
||
| // Read the decompressed stream into an ArrayBuffer | ||
| const reader = decompressedStream.getReader(); | ||
| const chunks = []; | ||
|
|
||
| while (true) { | ||
| const { done, value } = await reader.read(); | ||
| if (done) break; | ||
| chunks.push(value); | ||
| } | ||
|
|
||
| // Combine all chunks into a single ArrayBuffer | ||
| const totalLength = chunks.reduce((acc, chunk) => acc + chunk.length, 0); | ||
| const result = new Uint8Array(totalLength); | ||
| let offset = 0; | ||
|
|
||
| for (const chunk of chunks) { | ||
| result.set(chunk, offset); | ||
| offset += chunk.length; | ||
| } | ||
|
|
||
| //console.log(`WASM decompressed: ${(totalLength / 1024 / 1024).toFixed(2)} MB`); | ||
|
|
||
| return result.buffer; | ||
| } catch (error) { | ||
| console.error('Failed to load compressed WASM:', error); | ||
| throw error; | ||
| } | ||
| } | ||
|
|
||
| export function supportsGzipDecompression() { | ||
| return 'DecompressionStream' in globalThis; | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -140,7 +140,6 @@ class CopyPlatformAssetsBuildStep extends BuildStep { | |
| await for (final entity in sourceDir.list(recursive: true)) { | ||
| if (entity is File) { | ||
| final relativePath = path.relative(entity.path, from: sourceDir.path); | ||
| final destFile = File(path.join(destDir.path, relativePath)); | ||
|
|
||
| if (skipDir != null && | ||
| path.isWithin( | ||
|
|
@@ -151,13 +150,44 @@ class CopyPlatformAssetsBuildStep extends BuildStep { | |
| continue; | ||
| } | ||
|
|
||
| if (!destFile.parent.existsSync()) { | ||
| destFile.parent.createSync(recursive: true); | ||
| // Check if this is a WASM file that needs compression | ||
| if (path.basename(entity.path) == 'kdflib_bg.wasm') { | ||
| // Compress and save as .wasm.gz | ||
| final destFile = File(path.join(destDir.path, relativePath + '.gz')); | ||
|
|
||
| if (!destFile.parent.existsSync()) { | ||
| destFile.parent.createSync(recursive: true); | ||
| } | ||
| if (destFile.existsSync()) { | ||
| destFile.deleteSync(); | ||
| } | ||
|
|
||
| // Read, compress, and write | ||
| final wasmBytes = await entity.readAsBytes(); | ||
| final originalSize = wasmBytes.length; | ||
| final compressedBytes = gzip.encode(wasmBytes); | ||
|
Comment on lines
+165
to
+168
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
The new compression branch calls Useful? React with 👍 / 👎. |
||
| final compressedSize = compressedBytes.length; | ||
| await destFile.writeAsBytes(compressedBytes); | ||
|
|
||
| final compressionRatio = | ||
| ((originalSize - compressedSize) / originalSize * 100).toStringAsFixed(1); | ||
| _log.info( | ||
| 'Compressed kdflib_bg.wasm during copy: ' | ||
| '${originalSize} bytes -> ${compressedSize} bytes ' | ||
| '($compressionRatio% reduction)', | ||
| ); | ||
| } else { | ||
| // Normal file copy | ||
| final destFile = File(path.join(destDir.path, relativePath)); | ||
|
|
||
| if (!destFile.parent.existsSync()) { | ||
| destFile.parent.createSync(recursive: true); | ||
| } | ||
| if (destFile.existsSync()) { | ||
| destFile.deleteSync(); | ||
| } | ||
| entity.copySync(destFile.path); | ||
| } | ||
| if (destFile.existsSync()) { | ||
| destFile.deleteSync(); | ||
| } | ||
| entity.copySync(destFile.path); | ||
| } | ||
| } | ||
| _log.info( | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If
loadCompressedWasmthrows (e.g., missingkdflib_bg.wasm.gzor noDecompressionStreamsupport), the error occurs before_initPromiseis assigned, so_isInitializingremainstrueand no catch handler clears it. Subsequentinit_wasmcalls hit the_isInitializingbranch that polls for_initPromiseand will wait forever, leaving the KDF unusable after a single fetch failure.Useful? React with 👍 / 👎.