Replies: 2 comments 8 replies
-
I think the reason why we opted for injecting the original JS file was because of simplicity but of course that can be changed since SEA is experimental. V8 snapshot
I'm assuming you're referring to https://nodejs.org/api/cli.html#--build-snapshot? The docs mention:
Since a regular JS file supports all built-in modules and snapshots don't, it means that using the original JS file would have more capabilities for now. Now let's look at the advantages this has over using a JS file:
I don't think that's always true. Take a look at this example of using a tiny JS file: require('v8').startupSnapshot.setDeserializeMainFunction(() => {
const { stat } = require('fs/promises');
(async () => {
console.log(await stat('./index.js'));
})()
}); If I create a snapshot file using du -sh index.js snapshot.blob
4.0K index.js
4.0M snapshot.blob I tried doing this on a real world js bundle, something we use at postman, which is 14 MB and building snapshots don't work for that because it relies on certain built-in modules that aren't supported in snapshots, like tty, child_process, vm, https, http, tls, readline, http2. Also, it seems like building / using a snapshot fails when we use the
That's true.
If you inspect the snapshot blob in the example above, you'll be able to see the exact source code (you can search for Usage - We can use this once we have a way to bake CLI options and a VFS (not implemented yet but there are plans to do that), so that we can bake something like V8 code cache
I haven't dug into hermes yet but here's my assessment on the advantages of using the bytenode approach (which uses a code cache, not a snapshot, which is different) over a plan JS file:
For small files, like the one I showed above, the sizes are pretty much the same but it's slightly higher for the output file (specifically, 103 bytes for the input and 1008 bytes for the output). Doesn't seem to be true for a large JS file either: du -sh file.cjs file..jsc
14M index.js
17M index.jsc So I wouldn't consider this to be an advantage.
True.
According to https://swarm.ptsecurity.com/how-we-bypassed-bytenode-and-decompiled-node-js-bytecode-in-ghidra, it seems like something that can be reverse engineered? I can also think of a disadvantage: I tried checking if exception info, like line number is preserved and it looks like that doesn't happen in bytenode, i.e., the stack trace of exceptions show that the source of the error is at Usage - I think this can be used already if you inject an entry point that uses bytenode's API - |
Beta Was this translation helpful? Give feedback.
-
I wonder if @joyeecheung has more thoughts on this because she's leading the snapshots work? Also, cc @nodejs/single-executable |
Beta Was this translation helpful? Give feedback.
-
Since we are creating a single executable application, source code is not intended to be modified, so it doesn't makes sense to just add a Javascript bundle to the Node.js executable. What not add instead a v8 snapshot? Code would be the same, but final file size will be smaller, start time shorter, and since we are going to target just the exact version of v8 included in the attached Node.js binary, there would not be runtime incompatibilities, in addition to make it more difficult to disassemble the original Javascript source code. There's similar previous aproaches with bytenode and Hermes engine.
Beta Was this translation helpful? Give feedback.
All reactions