Skip to content
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

Enhancement — more modular loading #65

Open
alexandergunnarson opened this issue Feb 23, 2024 · 3 comments
Open

Enhancement — more modular loading #65

alexandergunnarson opened this issue Feb 23, 2024 · 3 comments
Labels
enhancement New feature or request

Comments

@alexandergunnarson
Copy link

alexandergunnarson commented Feb 23, 2024

First off, let me say how impressed I am with wasm-vips — amazing job 🤩👏🥳 Can't tell you how great your lib "just works" in comparison to about 8 other browser-based image manipulation libs I've tried, despite its supposed alpha quality. (If this is alpha quality, all the other libs are laughably early pre-alphas!)

The suggestion here is around more modular loading. The dynamicLibraries option is super helpful and shaves off quite a few unnecessary MB. However, I was wondering whether we could extend the concept to some of the more "core" Vips functionality. For instance, I only need webp resizing and encoding. I realize tree-shaking WASM is not yet a thing and may never be, but perhaps it's possible to further granulate wasm-vips analogously to dynamicLibraries. For instance I can imagine passing only features: ["resize", "web-encode"] or however the API might look.

Probably a big ask because ostensibly libvips itself isn't modular in the way I'm describing, but worth a discussion, I think.

Thanks again!

@alexandergunnarson
Copy link
Author

alexandergunnarson commented Feb 23, 2024

In practice, WASM streaming mitigates this, but I can imagine situations where it won't be the definitive band-aid.
image

@kleisauke kleisauke added the enhancement New feature or request label Mar 31, 2024
@kleisauke
Copy link
Owner

kleisauke commented Mar 31, 2024

Hi @alexandergunnarson,

Sorry for the delay. A significant portion of the vips.wasm file size comes from the foreign loaders and savers. A minimal libvips (i.e. with only core functionality) can be configured using this patch:

--- a/build.sh
+++ b/build.sh
@@ -488,11 +488,7 @@ node --version
   sed -i "/subdir('man')/{N;N;N;N;d;}" meson.build
   meson setup _build --prefix=$TARGET --cross-file=$MESON_CROSS --default-library=static --buildtype=release \
     -Ddeprecated=false -Dexamples=false -Dcplusplus=$LIBVIPS_CPP -Dauto_features=disabled \
-    ${ENABLE_MODULES:+-Dmodules=enabled} -Dcgif=enabled -Dexif=enabled ${ENABLE_AVIF:+-Dheif=enabled} \
-    -Dheif-module=enabled -Dimagequant=enabled -Djpeg=enabled ${ENABLE_JXL:+-Djpeg-xl=enabled} \
-    -Djpeg-xl-module=enabled -Dlcms=enabled ${ENABLE_SIMD:+-Dhighway=enabled} ${ENABLE_SVG:+-Dresvg=enabled} \
-    -Dresvg-module=enabled -Dspng=enabled -Dtiff=enabled -Dwebp=enabled -Dnsgif=true -Dppm=true -Danalyze=true \
-    -Dradiance=true -Dzlib=enabled
+    -Dnsgif=false -Dppm=false -Danalyze=false -Dradiance=false
   meson install -C _build --tag runtime,devel
   # Emscripten requires linking to side modules to find the necessary symbols to export
   module_dir=$(printf '%s\n' $TARGET/lib/vips-modules-* | sort -n | tail -1)

And by compiling with -Oz instead of -O3, using:

--- a/build.sh
+++ b/build.sh
@@ -111,7 +111,7 @@ done
 export RUSTFLAGS="-Ctarget-feature=+atomics,+bulk-memory,+nontrapping-fptoint"
 
 # Common compiler flags
-COMMON_FLAGS="-O3 -pthread"
+COMMON_FLAGS="-Oz -pthread"
 if [ "$LTO" = "true" ]; then
   COMMON_FLAGS+=" -flto"
   export RUSTFLAGS+=" -Clto -Cembed-bitcode=yes"

With that, I see:

$ ls -lh lib/*.wasm | awk '{print $5,$9}'
2.9M lib/vips-O3.wasm
2.2M lib/vips-Oz.wasm

However, most WebAssembly files are served Brotli-compressed nowadays. In the ideal case, with v0.0.8, this would mean that ~1.5MiB is transferred over the network.

$ brotli node_modules/wasm-vips/lib/vips.wasm --best -v
Compressed [node_modules/wasm-vips/lib/vips.wasm]: 5.388 MiB -> 1.509 MiB in 8.49 sec

(usually the size is ~1.8MiB due to the use of compression level 4, as shown in your screenshot)

Running the same command over the produced WebAssembly binaries above, I see:

$ brotli lib/vips-O{3,z}.wasm --best -v
Compressed [lib/vips-O3.wasm]: 2.872 MiB -> 968.115 KiB in 4.98 sec
Compressed [lib/vips-Oz.wasm]: 2.144 MiB -> 896.830 KiB in 4.26 sec

I think that modularizing every operation within wasm-vips adds unnecessary complexity to the build logic without yielding any significant benefits. We could, however, experiment with making more foreign loaders/savers as dynamic module.

Let's tag this as an enhancement.

@alexandergunnarson
Copy link
Author

Sorry for my own delay. Thanks for your thorough response — some great ideas here!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

2 participants