-
Notifications
You must be signed in to change notification settings - Fork 15
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
distributing CLI tools as self-contained binaries #32
Comments
Here is some prior art from forever ago: https://github.com/bmeck/noda-loader |
I believe at the moment to do something like this the user has to hack the entry point somehow (e.g. using One thing we need to take into account is the integration of V8 snapshot and code cache. Ideally toolchain for this should provide support for snapshot and code cache somehow so that the bundle can start up as fast as possible. Integration for user land snapshot and code cache builder may be a prerequisite for the toolchain - I can imagine the design of those APIs affecting the design of the APIs required by the toolchain. For example, the V8 snapshot API imposes many restrictions on the scripts executed before the snapshot is captured, thus implying that there should be certain phases in building the bundle when the snapshot is supported. |
I think that there would be willingness on the part of core to make changes to accomadate the building of an app bundler, but someone would have to step up to do the work on the bundler, and make some specific requests of core (or PRs!) that would make the bundling work easier. Besides snapshot and code cache, I think that patching in a VFS would also be a common requirement, because at the least require (and also fs.open for bundled assets?) would have to redirect to files bundled into the executable. Or, @joyeecheung , do I misunderstand what you mean by code cache? Is it the lib/**/*.js files we compiled into node? I think its different, a V8 optimization. Personally, I'd be 👍 to even going so far as to having standard runtime feature like This also might interact with WebPack, I think I've heard some people suggesting it as a way to build self-contained CLI apps, but I don't know enough about it to understand whether that is actually possible, or perhaps I've even misremembered. |
@sam-github By code cache I meant the binary blobs passed into the V8 API along with the source code when compiling scripts. Although for support of this I think it may be more transparent than the snapshot (e.g. we can just use an internal cache map in C++ land for |
FTR we currently run several optimization on the stdlib code.
|
happy to chat more and provide more context in next meeting 👍 thank you for opening the issue @boneskull |
some context: as a CLI developer, I'd like to be able to ensure my users are getting pre-compiled instances of my application, with minimal overhead (only bundle the needed internal dependencies for my app) and with controlable target distribution (i.e. pre-compiled binary, so I don't have to rely on the user's environment and compatibility) examples in the wild that attempt to address this: https://github.com/zeit/pkg as per @joyeecheung all of these (since I last inspected them) rely on hacking the entry point, then proceed to compiled node itself as per-usual, with targetted distributions for different environments (win, darwin, linux, etc ...) I'm not an expert on binary packaging and distribution in this context, but I'll attempt to further articulate my thinking: the main point to make here perhaps is: while these tools are "getting the job done" ... they are actually compiling and distributing node itself, while bundling some vs. Idea 1 node's official binary can somehow wrap an then with an additional command, re-package a secondary binary with the app's logic included? idea 2 provide build tooling and configuration that app developers can customize and optimize for best use of their CLI app ... including the ability to only include relevant APIs to the CLI ... e.g. I don't need |
here’s a new one https://blog.cribl.io/2019/07/08/going-native/ |
As the author of the blog post that @boneskull posted above I'll list some of our requirements and what I think should not be done as part of native bundling work: Native bundling should be:
Native bundling should not be:
|
@joyeecheung, @refack - a couple of questions around snapshots:
I've looked at
When executing Thoughts/ideas? |
@ledbit quick question. Are different linux variants supported (ex power or s390x?) |
Right now the list of supported platforms (in js2bin) is the most common plats I was able to easily get CI/CD going, but the same method should work anywhere NodeJS compiles. I'd recommend moving this convo to the js2bin repo |
Is addressing shortcomings in the "embeddable API" is a prerequisite to an ergonomic way to bundle self-contained binaries? @joyeecheung I'm ignorant about the state of things on that front, so I don't understand from your comment whether exposing more/better embeddable APIs is needed to get to "code cache & snapshots", or whether "code cache & snapshots" is wholly a performance improvement, or if it would also positively impact DX? How would "embedded Node.js", code cache & snapshots be inline with or orthogonal to @ledbit's strategy? In other words, if these were available, would @ledbit change js2bin's approach to leverage them? |
This landed: https://bellard.org/quickjs/ Interesting but also just a JS runtime. It apparently compiles to binary executables |
There are several restrictions, in Node.js core these are enforced with assertions though in user land the restrictions may be relaxed a bit. For example:
There would only be a space overhead in exchange for startup performance. The JS engine cannot just discard the original source code because it still needs to lazily recompile things and allow user to see them for debugging purposes. |
You are describing how To glue the user code and Node.js core together into one binary, you something that generates an executable with one binary and a bunch of other text files - for a C++ compiler on, say, Linux, that's just statically linking a library with another object compiled from some source code (which may come from something like js2c and some glue code that uses the embedder API), then write them out as ELF. If we want to offer the whole thing in our toolchain, the most plausible option that I can think of is some kind of SDK that includes a C++ compiler already. |
As mentioned in #32 (comment) above effectively you need a C++ compiler to generate an executable like this. What Node.js core could do is to make it less painful - say, instead of having to build Node.js core, you can just statically link to some prebuilt Node.js library. In stead of hacking around the entry point and monkey patching It's less of a big deal to include code cache customization in such embedder APIs but it would be trickier for snapshots for the reasons mentioned in #32 (comment) - we could make these optional in the embdder API for bundling, but until we get these done it would be better to keep that API experimental because breaking changes may be often. |
Correct (almost). Now, from a user/developer point of view what I am trying to avoid requiring the C++ toolchain. The approach that I took in js2bin is to embed some placeholder content into
|
This idea has moved to its own initiative: Node.js SEA Team, spawned by a mixed cohort of new and long time Node.js collaborators 🎉 Make sure to follow activity in that repo in case anyone is still interested in distributing CLI tools as self-contained binaries. |
Since Node 20.x.x , it has been there: https://nodejs.org/api/single-executable-applications.html |
@ahmadnassri brought this up at JSConf EU. would like to invite him to a meeting to chat about it, as I think it falls within our scope.
The text was updated successfully, but these errors were encountered: