Skip to content

Conversation

@jviotti
Copy link
Member

@jviotti jviotti commented Aug 5, 2022

This document is a bit like blog post, in that in documents the state at
this point in time and will likely be out of date at some point. For
this reason, I put this document inside a blog/ directory, prefixed
with its date.

Signed-off-by: Juan Cruz Viotti jv@jviotti.com

| 3 | Support the injection of any arbitrary data, irrelevant of its format and contents |
| 4 | Provide a complementary cross-platform native API for runtime reflection |
| 5 | Should be a pure JavaScript solution or not require native add-ons |
| 6 | Allow injection on any supported binary format in any platform |
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In point 2 which talks about supporting every binary format supported by Node.js, by support I am assuming it means the ability to inject. So in point 6 does it mean that the scope to go beyond that?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Point 2 talks about the capability of injecting data in each platform. For example, using Windows to inject the data into an EXE, using macOS to inject the data into a Mach-O, etc.

Point 6 is about being able to do any injection on any operating system. For example, being able to use macOS to produce a Windows SEA, etc.

We support this at the moment on Postject thanks to LIEF, and its pretty handy for i.e. continuous integration purposes, as you can generate all binaries for your app through a single Linux runner, etc.

I'll try to clarify this better now.

| 2 | Support every binary format adopted by the platforms supported by Node.js |
| 3 | Support the injection of any arbitrary data, irrelevant of its format and contents |
| 4 | Provide a complementary cross-platform native API for runtime reflection |
| 5 | Should be a pure JavaScript solution or not require native add-ons |
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So considering both point 4 and 5 together, we are looking at two different components? One in javascript which performs the injecting and the other is native code which forms the native API? I probably don't understand this really well.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, they are two sides of the same coin.

  • Injecting a new section into a binary can be done (in theory) with just fs (like PKG does), or even by compiling something like LIEF to web assembly. The main motivator for wanting a pure-JS implementation of the injector is that injecting is something that developers would run on their own systems. Adding a native add-on dependency means they need a full blown compiler toolchain installed, etc which makes the setup more complicated and would likely result in many people submitting issues when they cannot make it work
  • Reading from the section at runtime is a C/C++ feature only, and it is useful for integrators of i.e. Postject (like Node.js itself)

While we could argue they are different components, both read and write access are important and must be always kept in sync.

| 2 | Support every binary format adopted by the platforms supported by Node.js |
| 3 | Support the injection of any arbitrary data, irrelevant of its format and contents |
| 4 | Provide a complementary cross-platform native API for runtime reflection |
| 5 | Should be a pure JavaScript solution or not require native add-ons |
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is the uses of only javascript for the solution a hard requirement?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It was framed as a hard requirement by @jesec based on his experience managing PKG. A lot of people are likely to face troubles setting things up locally (i.e. mainly on Windows), resulting in unnecessary maintenance overhead.

Maybe "pure JavaScript" is not the right term... Something like WebAssembly would do as well. I'll clarify

@guest271314
Copy link

guest271314 commented Aug 6, 2022

Node.js executable may seem daunting at first, but its not!

"its" should be "it's".

First, we start with the assets that make a typical Node.js application. These
typically consist of JavaScript files from the application code

"typically" is redundant in 2d sentence, where "typical" is used in 1st sentence.

Suggest substituting "These consist of one or more JavaScript files from the application code".

Most interesting Node.js programs are composed by more than one file.

Is this opinion or fact? There should not be a difference from the user viewpoint between creating a SEA with 1 or 100 input files.

  • Require maintaining custom Node.js patches. These patches typically touch
    on the initialization logic of Node.js and are different across Node.js
    versions. These patches result in high maintenance burden and make it
    difficult for SEA implementations to support new Node.js versions as soon as
    they are released.

This is what I was alluding to in my posts in #1. That is, the process should be as simple as a user visisting the Node.js downloads Website, uploading their existsing Node.js-specific JavaScript code and the site producing out an executable with tip-of-tree (nightly) node executable for download. That way the SEA is always up to date, and/or is capable of being re-compiled daily/nightly. Perhaps that is a point that needs to be coordinated with the team/WG that published node nightly.

No support for non-JavaScript assets. Some SEA implementations
concatenate JavaScript assets and inject the resulting "single" file into the
executable. While this approach works for simple programs, many Node.js
applications require application resources that are not typically
concatenated as part of the JavaScript code, such as Node.js native add-ons,
text files, executable scripts and more. These assets are often dynamically
consumed using fs and child_process.

I'll point out here that QuickJS has its own compiler, qjsc https://bellard.org/quickjs/quickjs.html#qjsc-compiler.

@Trott
Copy link
Member

Trott commented Aug 6, 2022

Node.js executable may seem daunting at first, but its not!

"its" should be "it's".

Please use GitHub's review comment feature for comments like this. Even better if you use their suggestion feature so someone can simply commit your suggestion within the interface.

@guest271314
Copy link

I thought I did. Then couldn't find the same commit again until someone a collaborator/member replied to my suggestion to remove the bit about "interesting" 2f5c6ac. Done.

@jviotti jviotti force-pushed the first-note branch 2 times, most recently from 1594539 to 6a9961f Compare August 8, 2022 15:00
@jviotti
Copy link
Member Author

jviotti commented Aug 8, 2022

@guest271314 Thanks for the suggestions!

Is this opinion or fact? There should not be a difference from the user viewpoint between creating a SEA with 1 or 100 input files.

Very true. What I wanted to exemplify is that a notion of a VFS is often needed for apps consisting of more than one file (which might not even be require()-able files or are dynamically loaded). A VFS is not very useful for an app built as a single JS file.

This is what I was alluding to in my posts in #1. That is, the process should be as simple as a user visisting the Node.js downloads Website, uploading their existsing Node.js-specific JavaScript code and the site producing out an executable with tip-of-tree (nightly) node executable for download. That way the SEA is always up to date, and/or is capable of being re-compiled daily/nightly. Perhaps that is a point that needs to be coordinated with the team/WG that published node nightly.

Exactly. Projects like PKG involve significant maintenance overhead to produce Node.js binaries that can injected into. If we can provide that capability with upstream Node.js builds, then this entire complexity goes away! I tried to clarify this better now on the "Problems with current SEAs" section.

I'll point out here that QuickJS has its own compiler, qjsc https://bellard.org/quickjs/quickjs.html#qjsc-compiler.

Thanks for sharing! We should definitely document this

jviotti added a commit that referenced this pull request Aug 8, 2022
As pointed-out by @guest271314 in
#8 (comment).

Signed-off-by: Juan Cruz Viotti <jv@jviotti.com>
jviotti added a commit that referenced this pull request Aug 10, 2022
As pointed-out by @guest271314 in
#8 (comment).

Signed-off-by: Juan Cruz Viotti <jv@jviotti.com>
jviotti added a commit that referenced this pull request Aug 10, 2022
As pointed-out by @guest271314 in
#8 (comment).

Signed-off-by: Juan Cruz Viotti <jv@jviotti.com>
Copy link
Member

@RaisinTen RaisinTen left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This document is a bit like blog post

Should we place this in a directory called blog then?

@jviotti
Copy link
Member Author

jviotti commented Aug 10, 2022

Should we place this in a directory called blog then?

Works for me! Done!

@guest271314
Copy link

Doesn't Native Client do something like what is being worked on here?

I tried to reverse-engineer a .nexe file; contains the entire program in one file.

This document is a bit like blog post, in that in documents the state at
this point in time and will likely be out of date at some point. For
this reason, I put this document inside a `blog/` directory, prefixed
with its date.

Signed-off-by: Juan Cruz Viotti <jv@jviotti.com>
@jviotti
Copy link
Member Author

jviotti commented Aug 11, 2022

I don't know a lot about Native Client. Can you open a GitHub Discussion on this repo about it so we get more eyes on it? It'd be great if you can explain in more detail what it does (for people who are not super familiar) and even show some of the results you've seen from reverse engineering that .nexe file.

According to https://developer.chrome.com/docs/native-client/welcome-to-native-client/, it is deprecated technology for anything other than ChromeOS, but there might definitely be some lessons we can learn from it.

Copy link
Member

@RaisinTen RaisinTen left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM in its current state. Would anyone else from @nodejs/single-executable like to drop your LGTMs / request changes on this one?

@jviotti
Copy link
Member Author

jviotti commented Aug 12, 2022

Awesome. I'll merge now so we can get the ball rolling, but happy to address other comments on further PRs.

@jviotti jviotti merged commit 3800245 into main Aug 12, 2022
@jviotti jviotti deleted the first-note branch August 12, 2022 22:31
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

7 participants