Differences And Restrictions
WebAssembly intentionally excludes Node/V8 facilities. Public APIs do not
accept filesystem paths, Node streams, Node callbacks, InputFile, OutputFile,
plugin loaders, or synchronous CommonJS loading. Emscripten filesystem support,
where used internally, is not a public storage API.
OpenSSL is excluded, but bundled RC4 and AES-128 support byte-first recrypt
and Recipe encrypt(). PDF 2.0/AES-256 encryption remains unavailable. Existing
byte-backed PDFs can be read, modified, and copied, but persistent-file
continuation, password-protected Recipe source editing, and the path-based Recipe
constructor are unavailable. Wasm recryptAsync() returns a promise like
native's. Native recrypts on a libuv pool thread; Wasm has no thread pool, so it
recrypts in a worker it starts itself: worker_threads in Node, Deno, and Bun,
and a module Worker in browsers. Inside a worker, where no worker can start,
with module options a worker cannot receive, or with the Wasm-only module
option recryptWorker: false, it recrypts on the calling thread, as fast and as
blocking as recrypt(). It also rejects for an unsupported source or option,
where native recryptAsync() throws synchronously for wrong arguments, as every
Wasm *Async method rejects. See
Change PDF Passwords.
Recipe.thirdPartyLicenses() is Wasm-only: it reads the third-party notices
embedded in a .wasm (see License Notices). The native
packages ship their notices as THIRD_PARTY_NOTICES.md and have no such
function.
Recipe bundles Roboto Regular as its default rather than native Recipe's Helvetica family. Bold and italic fall back to regular unless their byte fonts are registered, and the different metrics can change wrapping. The low-level writer does not load the bundled font.
Table header styling follows native precedence and is independent of body text styles. See Create Multi-Page Tables for header overrides; font metrics remain the source of typography differences.
Wasm Recipe does not support native chroma("!load", path) color-file loading.
Register named colors individually, including Separation colors.
The Recipe HTML subset is DOM-free and Worker-safe. It supports URL links
through <a href> and visual nested lists through ul, ol, and li, but
does not provide arbitrary DOM, general CSS inheritance, semantic tagged-PDF
lists, or plugin HTML handlers. It is also more forgiving than the XML-strict
native parser: an omitted </li> ends that item at its next sibling or at the
end of its list rather than throwing. Wasm htmlToTextObjects() returns flat
visual runs with list prefixes and indent values, while native returns its
nested XML-derived layout tree.
In a flowed text(), highlight, underline, strikeOut, and squiggly
annotate the run that sets them, as links do on both ends. Native Recipe
currently takes them from the call that ends the flow and spans each over the
whole line (#909).
Its textBox.textAlign aligns the whole flow as the call that ends it sets
it, merged over the earlier runs' options. Native Recipe places each run by
that run's own alignment, so runs of one line that set different alignments
overlap or leave a gap.
Appending or rebuilding an existing source page does not deep-copy that page's
/Annots graph, although annotations created in the output are written
normally. split() returns named byte arrays rather than writing an output
directory, and structure("json") returns an in-memory summary rather than
writing a diagnostic file.
Wasm-only Recipe.dispose() and Recipe.disposeAssets() release Emscripten
allocations that JavaScript garbage collection cannot reclaim. Native objects
use normal native lifetime management. See the Recipe topic
guides for examples that follow these boundaries.