@muhammara/native-with-source
v7.2.2
Published
HummusJS-compatible native PDF addon with C++ source for local Node.js and Electron builds
Maintainers
Readme
@muhammara/native-with-source
Create, read, and modify PDF files from Node.js and Electron.
@muhammara/native-with-source is the source-capable package of MuhammaraJS:
it downloads a prebuilt native binary when one matches your platform and
otherwise compiles the bundled C++ sources locally.
npm install @muhammara/native-with-sourceIt has the same API as
@muhammara/native, which is
the smaller prebuilt-only package. Choose this one when no prebuilt matches your
platform or when Electron needs to rebuild the addon.
How The Packages Fit Together
MuhammaraJS is one PDF engine shipped in two ways. The same C++ library, PDF-Writer, sits at the bottom of every package; what differs is how it reaches your JavaScript.
PDF-Writer (C++)
┌────────────┴────────────┐
Node.js native addon WebAssembly build
│ │
@muhammara/native-core @muhammara/wasm
(shared JS, internal) (browsers, Workers, Node.js)
┌───────┴────────┐
@muhammara/native @muhammara/native-with-source
(prebuilt only) (prebuilt or source build)| Package | Install it when |
| ---------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------- |
| @muhammara/native | You run Node.js on a platform with a prebuilt binary. This is the default choice. |
| @muhammara/native-with-source | No prebuilt matches your platform, or Electron must rebuild the addon. |
| @muhammara/wasm | You work in a browser or Web Worker, or cannot load native addons (for example some serverless runtimes). |
| @muhammara/native-core | Never directly. Both native packages depend on it and install it for you. |
Both native packages expose the identical API, so switching between them is a
dependency change, not a code change. The Wasm package produces the same PDFs,
but it is byte-first (Uint8Array, ArrayBuffer, Blob, File) instead of
path-, stream-, and Buffer-oriented, so its JavaScript API is separate.
Why There Is Also A Wasm Package
Native addons need a compiled binary for the exact platform and a Node.js (or
Electron) runtime to load it. Browsers, Web Workers, and some edge or
serverless runtimes offer neither. For those, @muhammara/wasm compiles the
same PDF-Writer engine to WebAssembly: nothing to build at install time, one
package for every platform, and PDFs in and out as bytes. Stay on the native
package when you work in Node.js with files, streams, or Buffers, or need an
API the Wasm build does not have; the
Wasm differences
list what is native-only.
Supported Platforms
- Node.js 20, 22, 24, and 25 or later.
- Electron 36 or later, tested up to 44.
- Prebuilt binaries for Linux x64 and arm64 (glibc and musl), Linux riscv64 (glibc), macOS x64 and arm64, and Windows x64. One Node-API 8 binary per platform serves every supported Node.js and Electron version.
Installation problems, pnpm 10 build approval, and source-build requirements are covered in Installation.
Quick Start
Create a PDF with the high-level Recipe API:
var { Recipe } = require("@muhammara/native-with-source");
new Recipe("new", "hello.pdf")
.createPage("A4")
.text("Hello, PDF", 72, 72, { size: 24 })
.endPage()
.endPDF();Add text to the first page of an existing PDF held in a Buffer:
var { Recipe } = require("@muhammara/native-with-source");
var output = new Recipe(inputBuffer)
.editPage(1)
.text("Reviewed", 72, 72)
.endPage()
.endPDF((bytes) => bytes);output is a new Buffer; inputBuffer is not changed. Recipe page
numbers are one-based and coordinates start at the top-left corner.
Drop down to the low-level API when you need exact control over the PDF content stream. Its coordinates start at the bottom-left corner, as in the PDF specification:
var muhammara = require("@muhammara/native-with-source");
var stream = new muhammara.PDFWStreamForBuffer();
var writer = muhammara.createWriter(stream);
var page = writer.createPage(0, 0, 595, 842);
writer
.startPageContentContext(page)
.drawRectangle(72, 700, 200, 60, { type: "fill", color: 0x1777d1 });
writer.writePage(page);
writer.end();
var pdfBuffer = stream.buffer;Next steps:
- Recipe guide and low-level API
- How-to guides — watermarks, tables, annotations, passwords, deleting pages, serving a PDF response, and more
Building From Source
A source build compiles the addon together with its bundled OpenSSL; no separate OpenSSL installation is needed. It requires:
- Linux and macOS: the platform C/C++ toolchain, Perl, and
make. - Windows: Perl, NMake, and Visual Studio Build Tools. The build uses
OPENSSL_VS_INSTALL_PATH,GYP_MSVS_OVERRIDE_PATH,VSINSTALLDIR, ornpm_config_msbuild_pathwhen set, and otherwise discovers Visual Studio withvswhere.
RPM-based distributions such as Fedora, RHEL, and openSUSE split the Perl core
library into separate packages, and a source build needs several of them. See
Perl Packages On RPM Distributions
for the list. Debian and Ubuntu ship these modules with perl itself.
Source builds use all available CPU cores. On Unix-like systems, ccache can
speed up repeated rebuilds when configured through CC and CXX.
OpenSSL is statically linked into the result, so no OpenSSL libraries are needed at runtime.
Remove The Sources Before Packaging
After a successful build, remove the bundled source tree before packaging an application:
muhammara-clean-sourceThe compiled addon keeps working. Rebuilds, including @electron/rebuild, need
the source tree, so reinstall @muhammara/native-with-source first; npm ci
restores it from npm's package cache.
Keep An @muhammara/native Import
To keep require("@muhammara/native") in your code while installing the
source-capable package, install it as an npm alias:
npm install @muhammara/native@npm:@muhammara/native-with-source@<version>Prepare A Release Prebuild
npm run package --workspace=@muhammara/native-with-source