how to compile nodejs to a single, fully static binary file
Asked Answered
I

7

25

Does anyone know how to statically compile nodejs to a single executable binary? I means no share libraries needed.

There are some guides for old version nodejs, but not work for last one.

Thanks!

Incurve answered 30/7, 2013 at 9:45 Comment(5)
This might help: architects.dzone.com/articles/compiling-nodejs-projectsAciculate
thanks, furydevoid. but I just want the node itself to be static exe, not wanna pack all js together. By this way I can run this single binary on android environment.Incurve
what I want is $ ldd /path/to/bin/node and get not a dynamic executableIncurve
two years later... did you find a solution (have the same problem)?Burnette
Deno provides the compile option and is very similar to NodeJS.Tytybald
C
15

As pointed by Daniel Milde, https://hub.docker.com/r/dundee/nodejs-static/ is a alternative, but its deprecated, and has no Dockerfile exposed, that do not inspire trust.

I've tested the node binary in a container from scratch and it worked.

You can build the node statically linked yourself.

~/src$ git clone https://github.com/nodejs/node
cd node
~/src/node$ ./configure --help | grep static
    --fully-static        Generate an executable without external dynamic
    --partly-static       Generate an executable with libgcc and libstdc++
    --enable-static       build as static library
                        link to a shared http_parser DLL instead of static
    --shared-libuv      link to a shared libuv DLL instead of static linking
    --shared-nghttp2    link to a shared nghttp2 DLL instead of static linking
    --shared-openssl    link to a shared OpenSSl DLL instead of static linking
    --shared-zlib       link to a shared zlib DLL instead of static linking
    --shared-cares      link to a shared cares DLL instead of static linking
~/src/node$ ./configure --fully-static --enable-static
~/src/node$ make
...
~/src/node$ file out/Release/node 
out/Release/node: ELF 64-bit LSB executable, x86-64, version 1 (GNU/Linux), statically linked, for GNU/Linux 3.2.0, BuildID[sha1]=e5be29b02e283d0efdfc313e409b1a0802bd0603, with debug_info, not stripped
~/src/node$ /lib64/ld-linux-x86-64.so.2 --list out/Release/node 
        statically linked
~/src/node$ 

And let's test with a docker container from scratch:

~/src/node$ cat > /tmp/Dockerfile.node-static <<EOF
FROM scratch
COPY out/Release/node /node
CMD /node
EOF
~/src/node$ docker build -t glaudiston/node-scratch -f /tmp/Dockerfile.node-static .
Sending build context to Docker daemon  1.239GB
Step 1/3 : FROM scratch
 ---> 
Step 2/3 : COPY out/Release/node /node
 ---> ec9d62bb7eb0
Step 3/3 : CMD /node
 ---> Running in 2e375fc580f7
Removing intermediate container 2e375fc580f7
 ---> 5d6a2b5f20b8
Successfully built 5d6a2b5f20b8
Successfully tagged glaudiston/node-scratch:latest
$ docker run -ti node-static:latest /node
Welcome to Node.js v14.0.0-pre.
Type ".help" for more information.
> var x = { 'test': 123 };
undefined
> x.test
123
> 

You can build it in a Dockerfile too:

Dockerfile.node file:

FROM alpine:3.11.3
RUN apk add git python gcc g++ linux-headers make
RUN git clone https://github.com/nodejs/node && \
        cd node && \
        ./configure --fully-static --enable-static && \
        make
FROM scratch
COPY --from=0 out/Release/node /node
CMD /node

And to build:

$ docker build -f Dockerfile.node -t node-static .
Sending build context to Docker daemon  121.9kB
Step 1/6 : FROM alpine:3.11.3
 ---> e7d92cdc71fe
Step 2/6 : RUN apk add git python gcc g++ linux-headers make
 ---> Using cache
 ---> c343d63a3094
Step 3/6 : RUN git clone https://github.com/nodejs/node &&      cd node &&      ./configure --fully-static --enable-static &&   make
 ---> Using cache
 ---> e7f9fc931827
Step 4/6 : FROM scratch
 ---> 
Step 5/6 : COPY --from=0 /node/out/Release/node /node
 ---> 045ad784eadc
Step 6/6 : CMD /node
 ---> Running in f48178348e7b
Removing intermediate container f48178348e7b
 ---> ff1d93da95c8
Successfully built ff1d93da95c8
Successfully tagged node-static:latest

or, if you trust me, you can use my public docker image glaudiston/node-scratch.

~/src/node$ docker push glaudiston/node-scratch
The push refers to repository [docker.io/glaudiston/node-scratch]
9251f7e82698: Pushed 
latest: digest: sha256:c6f2154daa0144abafc0a7070c48f0c4031a036901c75d432b8c826ae793a1d7 size: 529
Calipee answered 17/4, 2019 at 21:52 Comment(1)
You may use github.com/nodejs/docker-node/tree/master/10/alpine3.10 (or other versions) as a starting point for docker build.Tola
O
2

Here's another one that can package your application in a single executable https://www.npmjs.com/package/pkg

Olson answered 31/8, 2017 at 22:39 Comment(1)
This does not appear to have a static option.Arezzini
E
2

I´m looking for this today and I found this options:

https://github.com/vercel/pkg
PKG has an option to compile for platform linuxstatic
Note that fully static Node binaries are not capable of loading native bindings, so you may not use Node bindings with linuxstatic.

https://github.com/vercel/ncc

Both of them are being developed in 2021

There is also NEXE that latest release was in 2017

enter image description here

Eadith answered 24/10, 2021 at 14:32 Comment(0)
A
1

You can use nodejs-static docker image to get statically compiled Node.JS binary linked with musl libc.

https://hub.docker.com/r/dundee/nodejs-static/

Augustin answered 20/11, 2015 at 9:11 Comment(1)
This is like completly out of damn topic, what Docker have to Node.js SEA?Aragon
E
1

If you are talking about compiling Javascript code, you might get close using pkg

It somehow creates a self-contained binary executable from Javascript, including module dependencies and asset files and produces a self-contained executable.

Installation and use is easy:

$ npm install -g pkg
$ pkg index.js -o my-program
$ ./my-program

My understanding is that this binary contains nodejs bytecode. It also appears that you can cross-compile.

Ethology answered 13/11, 2021 at 14:23 Comment(1)
pkg is archived and overall is not recommended since Node.js got a support for SEAAragon
A
0

Meanwhile there is http://enclosejs.com/ which seems to be able to generate a single binary.

Antedate answered 16/3, 2016 at 16:5 Comment(1)
This appears to no longer be maintained. That pkg project in another answer seems to be the alternative.Estrella
A
0

Node.js is runtime and JavaScript is interpreted language which means it runs code without compilation step. The problem you're trying to solve is a huge waste of time and manifest of holes in knowledge. De facto, it would be actally faster to learn another programming language than compile Node.js application into single executable binary.

Some runtimes (Bun and Deno) are able to ship runtime and which will run bundled code which may look as compiled application but de facto it's not - outcome may be similar for end-user as they see single file but these two are completly two different things.

I recommend trying out building code with Bun and with enough luck thing will work out but if they do not and bun will not implement fixes on their own I would risk statement that is completly impossible to do so. https://bun.sh/docs/bundler/executables

In ~2022..2023 the preferred way of doing such things was usage of pkg yet it was archived and probably will not be longer maintained as Node.js introduced experimental support for Single Executable Applications (SEA) which means there is no longer need for tools like pkg, same goes for nexe and all other tools that we're used before ecosystem change to ESmodule from CommonJS and others.

I've been in similar place before and also come down with similar question - I recommend reading up https://mcmap.net/q/539722/-how-to-bundle-node-js-application-to-single-executable-application-sea-along-native-modules-napi

Aragon answered 2/6 at 4:41 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.