Builds Node.js as a shared library (libnode.dll) on Windows and packages the
bundled V8 headers + import library into zip files that
FreeSWITCH's mod_v8 can link
against — a drop-in replacement for the retired standalone libv8 packages.
On Linux, mod_v8 builds against the distro's libnode-dev. There is no
equivalent prebuilt package on Windows, so this repo builds one: it compiles a
chosen Node.js version from source as a shared library and exports the full V8 +
libplatform API from libnode.dll. Upload the resulting zips to a CDN and
mod_v8's MSBuild props fetches them at build time.
For Node v20.19.2 (which bundles V8 11.3):
libnode-20.19.2-headers.zip libnode-20.19.2/include/... (all of deps/v8/include)
libnode-20.19.2/LICENSE
libnode-20.19.2-binaries-x64-release.zip libnode-20.19.2/binaries/x64/Release/{libnode.dll, libnode.lib, LICENSE}
libnode-20.19.2-binaries-x64-debug.zip libnode-20.19.2/binaries/x64/Debug/{libnode.dll, libnode.lib, libnode.pdb, LICENSE}
SHA256SUMS.txt
This mirrors the old v8-<ver>-headers.zip / v8-<ver>-binaries-<plat>-<cfg>.zip
layout, so the consuming MSBuild props is nearly identical (see
examples/freeswitch/w32/).
Each zip includes Node's aggregated LICENSE (Node MIT + every bundled
dependency: V8, OpenSSL, ICU, libuv, zlib, c-ares, nghttp2, …), which are
statically linked into libnode.dll and must accompany the redistributed binary.
.github/workflows/build-libnode.yml CI: build on a Windows runner, upload zip artifacts
build-libnode.ps1 the build + package script (shared by CI and Docker)
Dockerfile Windows-container toolchain image (for local/offline builds)
examples/freeswitch/w32/ reference MSBuild props for wiring up mod_v8
├─ libnode.props links libnode.lib, sets USING_V8_SHARED, C++20, etc.
└─ libnode-version.props single place to set the libnode version
README.md
The Build libnode (Windows) workflow runs
on a windows-2022 runner (which already has Visual Studio 2022); it installs the
remaining prerequisites and runs build-libnode.ps1.
- Manually: Actions tab → Build libnode (Windows) → Run workflow, then
enter the Node tag (e.g.
v20.19.2), configs (Release Debug), and arch (x64). - By tag: push a tag like
libnode-v20.19.2. The workflow builds it and also attaches the zips to a GitHub Release.
Download the zips from the run's Artifacts (or the Release), then upload them to your CDN.
A
Release Debugbuild of both configurations takes roughly 1–2 hours on a hosted runner. Build onlyReleaseto halve it.
Useful for offline/air-gapped builds or reproducing CI locally. Requires Docker with Windows containers enabled.
# Build the toolchain image once (installs VS Build Tools + ClangCL, Python, NASM,
# Git, Rust). This layer is large and slow; subsequent version builds reuse it.
docker build -t libnode-packaging .
# Produce zips for a Node tag (writes to .\artifacts on the host):
docker run --rm --cpus 8 --memory 16g `
-e NODE_VERSION=v20.19.2 `
-v ${PWD}\artifacts:C:\artifacts `
libnode-packagingcmd.exe: replace ${PWD} with %cd%.
The host must run a Windows base image of equal-or-older build for process
isolation (the Dockerfile defaults to servercore:ltsc2025); otherwise pass
--build-arg WINDOWS_BASE=...:ltsc2022 or run with --isolation=hyperv.
If you already have the Node.js Windows build prerequisites (VS 2022 + C++ workload, Python 3.13, NASM; Rust only for Node ≥ 26), just run the script directly:
$env:NODE_VERSION = 'v20.19.2'
$env:CONFIGS = 'Release Debug'
$env:OUT_DIR = "$PWD\artifacts"
.\build-libnode.ps1| Var | Default | Notes |
|---|---|---|
NODE_VERSION |
v20.19.2 |
Any Node.js git tag. |
CONFIGS |
Release Debug |
Space-separated; set to Release to skip the slow/large Debug build. |
ARCH |
x64 |
x64 or arm64. 32-bit Windows is unsupported by Node. |
PKG_PREFIX |
libnode |
Zip/folder name prefix. |
OUT_DIR |
C:\artifacts |
Where the zips are written. |
NODE_REPO |
https://github.com/nodejs/node.git |
Override for a fork/mirror. |
Build the same Node.js major version on Windows that your Linux libnode-dev
ships, so the single mod_v8 source compiles on both platforms. Debian trixie
ships libnode-dev 20.19.2 (Node 20 → V8 11.3), so this repo defaults to
v20.19.2.
Newer Node lines remove V8 APIs that mod_v8 still uses (e.g. V8 13 / Node 24
removed FunctionCallbackInfo::Holder(); V8 ~12.9 removed AccessorGetterCallback
and Template::SetAccessor()). Building Node 26 on Windows compiles+links fine but
would require porting mod_v8 to the new API and supplying a matching libnode on
Linux — so match the distro version unless you intend to upgrade both platforms.
Copy the two files from examples/freeswitch/w32/
into your FreeSWITCH build tree's w32\ directory and, in mod_v8.vcxproj, replace:
<Import Project="$(SolutionDir)\w32\v8.props" />with:
<Import Project="$(SolutionDir)\w32\libnode.props" />Set the target version in libnode-version.props, and (if your CDN differs from
the default) edit the package= URLs in libnode.props to point at where you
uploaded the zips. The props handle the three consumer-side requirements
automatically:
- Link
libnode.lib(instead of the three oldv8*.dll.libfiles). - Define
USING_V8_SHARED;USING_V8_PLATFORM_SHAREDso the V8 headers import fromlibnode.dll. - Compile as C++20 with
/Zc:__cplusplus(required by the V8 headers).
build-libnode.ps1:
git clone --depth 1 --branch $NODE_VERSIONthe Node.js source.- Patches
common.gypito addBUILDING_V8_PLATFORM_SHARED=1sov8::platform(e.g.NewDefaultPlatform) is exported fromlibnode.dll. Node ≤ 22 compiles libplatform into libnode but doesn'tdllexportit on Windows (on Linux it's exported via default visibility); without this patch embedders hitLNK2019onNewDefaultPlatform. The patch is skipped on Node versions that already export it (e.g. 26). - For each config:
vcbuild.bat dll <release|debug> <arch>⇒--shared⇒libnode.dll+libnode.lib. The Windows shared build definesBUILDING_V8_SHARED=1, so the V8 + libplatform API is exported. - Packages
deps/v8/include→ headers zip and the per-configlibnode.*→ binaries zips, plus Node'sLICENSEandSHA256SUMS.txt.
- 32-bit Windows is not supported — Node only builds
x64/arm64. The old libv8win32zips have no equivalent here. - Python: Node 20.x rejects Python 3.14; use 3.13 (accepted by Node 20→26).
- Rust: only needed for Node ≥ 26 (Temporal builds
deps/crates). Not needed for Node 20/22. - Refreshing a dev checkout: the props copy
libnode.dllto the output dir only when it isn't already there (copy-once, like the originalv8.props), so after publishing a new zip for the same version, delete the extractedlibs\libnode-<ver>\and thelibnode.dllalready copied next to the FreeSWITCH binary so they get re-fetched/re-copied.