Skip to content

Split "package multiple files together" and "Distribute a script w/ Node.js" #25

Closed

Description

@arcanis

I understand from the discussions I see here that the main use case currently talked about is shipping a completely standalone executable application. It's a reasonable one, but I have another: execute packaged scripts from an existing Node.js installation (and also to be to able to require the entry point from such packaged scripts, from existing Node.js processes) - similar to how Java knows how to run JAR files as if they were regular scripts, but without having to distribute the Java interpreter inside them, or how Python can natively import modules from zip files.

Fortunately, I don't think those two use cases are conflicting. Solving both would simply mean splitting the question statement:

  • How can we distribute an application, resources and all, inside a Node.js binary?

Into two:

  • How can we make Node.js understand the concept of packaged application (just like it understands json, wasm, etc)?
  • How can we distribute a entry point inside a Node.js binary (whether this entry point is js, wasm, or packaged app)?

Then, by answering those two questions, both use cases will be addressed.

"Can't we just postpone this concept of packaged application to a follow-up proposal, once SEA are solved?"

While, in a sense, the original question statement is a subset of the split one (because it allows fewer things), I believe the split question is a better start for a design discussion. Indeed, if we decide to focus the design on the single initial question, then whatever format we pick for storing the SEA resources will either:

  • constrain the packaged application design down the road (because we'll have to use the same format for consistency, even if it doesn't match all the requirements), or
  • bring technical debt on arrival (because we'll have one format for SEA resources and a different one for packaged application, where a single one would have been enough)

Activity

  1. ljharb commented on Aug 20, 2022

    @ljharb
    SponsorMember

    What’s the use case of distributing the equivalent of a jar that requires node, when you can do npx whatever or the equivalent?

  2. arcanis commented on Aug 20, 2022

    @arcanis
    ContributorAuthor

    The same as for any other dependency from any Node.js project. To avoid having to reify the packages' node_modules directory on disk, by keeping them as independent entities.

    While this isn't the approach npm/npx picked, this is the one that Yarn implements with its Plug'n'Play installs: each Node.js dependency is stored as a separate zip archive. When the CJS/ESM loader detects an access to a module stored within these dependencies, it loads the files directly from those places. This approach works very well for us, since each package is easy to cache, copying them is always atomic and can even take a single I/O operation for supporting systems, they can easily be stored within repositories, they are trivial to checksum for corruption checks, they can be signed, etc.

    The drawback is that in order to make that work we have to apply a VFS layer on top of Node.js to make it understand how to access the zip archives files (for the same reason we are discussing one in this repository: some packages need to access their resources via fs operations). We do this (via ZipFS), but it's currently implemented in wasm-land (which makes the perfs worse than they could). If there was a way to use native capabilities instead, it'd be very beneficial.

  3. ovflowd commented on Aug 21, 2022

    @ovflowd
    Member

    The same as for any other dependency from any Node.js project. To avoid having to reify the packages' node_modules directory on disk, by keeping them as independent entities.

    That's a very valid point, but not sure if it fits what SEA intends to be (My personal view of the scenario). Yet, I find the idea interesting, but not sure if there are enough people out there that are also interested on a "jar" approach for node (Haven't honestly given a thought about this)

  4. arcanis commented on Aug 21, 2022

    @arcanis
    ContributorAuthor

    Also keep in mind that SEA binaries won't be portable, by design. Packaged application, however, have no problem being used on different platforms.

    Taking the Yarn case again, we distribute our binary as a single bundled JS file, so that people can just download it and use it immediately. It kinda works, but it makes the initialization slower (the whole file has to be parsed, even if a subset is used) and the file size bigger (we can't store binary data efficiently).

    It wouldn't be difficult for me to imagine that packaged application would have a variety of usage for cloud providers, where the Node.js version is defined in the workflow configuration rather than the build itself.

  5. ovflowd commented on Aug 21, 2022

    @ovflowd
    Member

    Also keep in mind that SEA binaries won't be portable, by design. Packaged application, however, have no problem being used on different platforms.

    That is true, true. SEA applications will very probably (per design) be platform-specific.

    Taking the Yarn case again, we distribute our binary as a single bundled JS file, so that people can just download it and use it immediately. It kinda works, but it makes the initialization slower (the whole file has to be parsed, even if a subset is used) and the file size bigger (we can't store binary data efficiently).

    That is super cool!

    It wouldn't be difficult for me to imagine that packaged application would have a variety of usage for cloud providers, where the Node.js version is defined in the workflow configuration rather than the build itself.

    I see your point! Well, my 2 cents are for what I see right now:

    • SEA might become part of the node-binary itself, allowing to bundle of SEA applications
    • We could find a mid-term (extra functionality) that, instead of outputting a platform-specific binary file, could output the bundled package.
      • This could then be used as node my-bundled-package.extension (Not sure which extension we would use)
      • It would go through all the bundling steps but output a packed file

    I'm just not sure how much it would differentiate from npm pack (I do understand both are different things). Would love to have some more concrete ideas here :D

  6. jviotti commented on Aug 22, 2022

    @jviotti
    Member

    This is a great point @arcanis , and I think it will work very well for making incremental progress on the SEAs approach.

    Referring my initial blog post on SEAs (https://github.com/nodejs/single-executable/blob/main/blog/2022-08-05-an-overview-of-the-current-state.md), what you are suggesting is essentially that we can implement only the Bootstrapper and the VFS ingredients, have something running and then do the Resource Injection.

    If the Bootstrapper is made in a way that it is agnostic on WHERE it loads the bundle from, then this should work by default.

    @RaisinTen This is a requirement for the Boostrapper component we should document: make it read the bundle from anywhere, including from within the binary or as a standalone file.

  7. locked and limited conversation to collaborators on Aug 22, 2022
  8. converted this issue into a discussion #27 on Aug 22, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions