Exclosured Precompiled
Copy MarkdownThis project makes it easy to distribute precompiled WASM modules for libraries built with Exclosured.
With Exclosured Precompiled, library consumers do not need the Rust
toolchain, cargo, or wasm-bindgen installed. The precompiled .wasm
and .js files are downloaded from a GitHub Release during mix compile.
Since all Exclosured modules compile to wasm32-unknown-unknown, there
is only one compilation target per module. No platform detection or
cross-compilation matrix needed.
Check the documentation for API details and the Precompilation Guide for a step-by-step walkthrough including CI automation.
Installation
def deps do
[
{:exclosured_precompiled, "~> 0.1.0"}
]
endGuide for Library Authors
1. Add dependencies
Your library needs both exclosured (for compilation) and
exclosured_precompiled (for distribution):
def deps do
[
{:exclosured, "~> 0.1.1"},
{:exclosured_precompiled, "~> 0.1.0"}
]
end2. Create a precompiled module
Define a module that declares which WASM modules should be downloaded and where to find them:
defmodule MyLibrary.Precompiled do
use ExclosuredPrecompiled,
otp_app: :my_library,
base_url: "https://github.com/user/my_library/releases/download/v0.1.0",
version: "0.1.0",
modules: [:my_processor, :my_filter]
end3. Build and package
One command compiles from source and packages into archives (requires
the Rust toolchain). Modules are auto-discovered from your
ExclosuredPrecompiled config:
mix exclosured_precompiled.precompile --version 0.1.0
You can also specify modules manually:
mix exclosured_precompiled.precompile --version 0.1.0 --modules my_processor,my_filter
This creates one .tar.gz and one .sha256 per module in _build/precompiled/:
_build/precompiled/
my_processor-v0.1.0-wasm32.tar.gz
my_processor-v0.1.0-wasm32.tar.gz.sha256
my_filter-v0.1.0-wasm32.tar.gz
my_filter-v0.1.0-wasm32.tar.gz.sha256Each archive contains the wasm-bindgen output:
my_processor-v0.1.0-wasm32.tar.gz
my_processor_bg.wasm # compiled WASM binary
my_processor.js # wasm-bindgen JS shim
my_processor.d.ts # TypeScript definitions (if present)
my_processor_bg.wasm.d.ts # WASM TypeScript definitions (if present)4. Upload to GitHub Release
Upload both archives and their .sha256 sidecar files:
gh release create v0.1.0 _build/precompiled/*.tar.gz _build/precompiled/*.sha256
5. Generate checksums
Generate a checksum file for inclusion in your Hex package. This ensures download integrity for consumers.
# From local archives (reads .sha256 sidecar files):
mix exclosured_precompiled.checksum \
--local \
--dir _build/precompiled \
--module MyLibrary.Precompiled
# Or from GitHub Release (downloads only the small .sha256 files,
# not the full archives):
mix exclosured_precompiled.checksum \
--base-url https://github.com/user/my_library/releases/download/v0.1.0 \
--module MyLibrary.Precompiled
This generates checksum-Elixir.MyLibrary.Precompiled.exs in the
project root.
6. Publish to Hex
Include the checksum file in your package:
defp package do
[
files: ~w(lib priv mix.exs README.md LICENSE checksum-*.exs)
]
endThen publish:
mix hex.publish
Guide for Library Consumers
Just add the library to your dependencies. The WASM files are
downloaded automatically during mix compile:
def deps do
[{:my_library, "~> 0.1.0"}]
endNo Rust, cargo, or wasm-bindgen installation needed.
Force build from source
If you want to compile from source instead of downloading precompiled WASM (e.g., for development or auditing):
# In config/config.exs:
config :exclosured_precompiled, force_build: true
# Or for specific modules only:
config :exclosured_precompiled, force_build: [:my_processor]Or via environment variable:
EXCLOSURED_PRECOMPILED_FORCE_BUILD=1 mix compile
This requires the Rust toolchain to be installed.
How It Works
- At compile time,
ExclosuredPrecompiledchecks if the WASM files exist inpriv/static/wasm/MODULE/ - If missing, downloads
MODULE-vVERSION-wasm32.tar.gzfrom the GitHub Release URL specified by the library author - Verifies the SHA-256 checksum against the checksum file shipped with the Hex package
- Extracts
.wasmand.jsfiles topriv/static/wasm/MODULE/ - Writes
.sha256files next to each extracted file for independent verification
Downloaded archives are cached in a user-level cache directory
(~/Library/Caches on macOS, ~/.cache on Linux) to avoid redundant
downloads across projects.
Environment Variables
| Variable | Purpose |
|---|---|
EXCLOSURED_PRECOMPILED_FORCE_BUILD_ALL | Set to "1" or "true" to skip downloads and build from source |
EXCLOSURED_PRECOMPILED_GLOBAL_CACHE_PATH | Override the cache directory (useful for NixOS) |
HTTP_PROXY / http_proxy | HTTP proxy for downloads |
HTTPS_PROXY / https_proxy | HTTPS proxy for downloads |
HEX_CACERTS_PATH | Custom CA certificate bundle for HTTPS |
MIX_XDG | Use Linux XDG base directories for cache |
Differences from Rustler Precompiled
| Rustler Precompiled | Exclosured Precompiled | |
|---|---|---|
| Artifact type | NIF .so/.dll | WASM .wasm + .js |
| Targets | ~20+ (OS x arch x NIF version) | 1 (wasm32-unknown-unknown) |
| Platform detection | Complex (OS, arch, ABI, NIF version) | None needed |
| Variants | Yes (glibc versions, CPU features) | None needed |
| Where it runs | Server (BEAM VM) | Browser (WebAssembly) |
The single-target design makes Exclosured Precompiled significantly simpler: no cross-compilation matrix, no platform detection, no variant resolution.
Acknowledgements
This project is inspired by Rustler Precompiled by Philip Sampaio. The design of the checksum verification, caching, and download-with-retry mechanisms follows patterns established in that project. Adapted for Exclosured's single-target WASM use case.
License
Copyright 2025 Cocoa Xu
Licensed under the MIT License. See LICENSE for details.