Code Monkey home page Code Monkey logo

bytenode's Introduction

Bytenode

A minimalist bytecode compiler for Node.js.

This tool truly compiles your JavaScript code into V8 bytecode, so that you can protect your source code. It can be used with Node.js, as well as Electron and NW.js (check examples/ directory).


Install

npm install --save bytenode

Or globally:

sudo npm install -g bytenode

Known Issues and Limitations

  • In Node 10.x, Bytenode does not work in debug mode. See #29.

  • Any code depends on Function.prototype.toString function will break, because Bytenode removes the source code from .jsc files and puts a dummy code instead. See #34. For a workaround, see #163

  • Async Arrow Functions (and Arrow Functions in general) cause crashes in Puppeteer and in Electron apps. See #106, #47. They also cause issues with the ndb debugger. See #135. It seems that whenever there is a context change (or even when called from another file or module), arrow functions break because V8 inspects them internally using Function.prototype.toString in these cases. See #157.


Resources


Bytenode CLI

  Usage: bytenode [option] [ FILE... | - ] [arguments]

  Options:
    -h, --help                        show help information.
    -v, --version                     show bytenode version.

    -c, --compile [ FILE... | - ]     compile stdin, a file, or a list of files
    --compress                        compress bytecode
    -n, --no-module                   compile without producing commonjs module
    -e, --electron                    compile for Electron
    -ep, --electron-path              path to Electron executable

    -l, --loader [ FILE | PATTERN ]   create a loader file and optionally define
                                      loader filename or pattern using % as
                                      filename replacer
                                      defaults to %.loader.js
    --no-loader                       do not create a loader file, conflicts
                                      with -l
    -t, --loader-type type            create a loader file of type commonjs or
                                      module. Defaults to CommonJS

  Examples:

  $ bytenode -c script.js             compile `script.js` to `script.jsc`.
  $ bytenode -c server.js app.js
  $ bytenode -c src/*.js              compile all `.js` files in `src/` directory.

  $ bytenode -c *.js -l %.load.js     create `filename.load.js` loader files along side `.jsc` files

  $ bytenode script.jsc [arguments]   run `script.jsc` with arguments.
  $ bytenode                          open Node REPL with bytenode pre-loaded.

Examples:

  • Compile express-server.js to express-server.jsc.
user@machine:~$ bytenode --compile express-server.js
  • Run your compiled file express-server.jsc.
user@machine:~$ bytenode express-server.jsc
Server listening on port 3000
  • Compile all .js files in ./app directory.
user@machine:~$ bytenode --compile ./app/*.js
  • Compile all .js files in your project.
user@machine:~$ bytenode --compile ./**/*.js

Note: you may need to enable globstar option in bash (you should add it to ~/.bashrc): shopt -s globstar

  • Starting from v1.0.0, bytenode can compile from stdin.
echo 'console.log("Hello");' | bytenode --compile - > hello.jsc

Bytenode API

const bytenode = require('bytenode');

bytenode.compileCode(javascriptCode) → {Buffer}

Generates v8 bytecode buffer.

  • Parameters:
Name Type Description
javascriptCode string JavaScript source that will be compiled to bytecode.
  • Returns:

{Buffer} The generated bytecode.

  • Example:
let helloWorldBytecode = bytenode.compileCode(
  `console.log('Hello World!');
  43;  // this will be returned`
);

This helloWorldBytecode bytecode can be saved to a file. However, if you want to use your code as a module (i.e. if your file has some exports), you have to compile it using bytenode.compileFile({compileAsModule: true}), or wrap your code manually, using Module.wrap() function.


bytenode.compileElectronCode(javascriptCode, options) → {Promise<Buffer>}

Asynchronous function which generates v8 bytecode buffer for Electron.

Same as bytenode.compileCode(), but generates bytecode for the version of Electron currently installed in node_modules.

  • Parameters:
Name Type Description
javascriptCode string JavaScript source that will be compiled to bytecode.
options object Options object.
options.electronPath string Path to Electron executable.
  • Returns:

{Promise<Buffer>} A Promise which resolves with the generated bytecode.

  • Example:
let helloWorldBytecode = await bytenode.compileElectronCode(
  `console.log('Hello World!');
  43;  // this will be returned`
);

This helloWorldBytecode bytecode can be saved to a file. However, if you want to use your code as a module (i.e. if your file has some exports), you have to compile it using bytenode.compileFile({compileAsModule: true}), or wrap your code manually, using Module.wrap() function.


bytenode.runBytecode(bytecodeBuffer) → {any}

Runs v8 bytecode buffer and returns the result.

  • Parameters:
Name Type Description
bytecodeBuffer Buffer The buffer object that was created using compileCode function.
  • Returns:

{any} The result of the very last statement executed in the script.

  • Example:
const result = bytenode.runBytecode(helloWorldBytecode);
// prints: Hello World!
console.log(result)
// prints: 43

bytenode.compileFile(args, output) → {Promise<string>}

Asynchronous function which compiles JavaScript file to .jsc file.

  • Parameters:
Name Type Description
args object | string
args.filename string The JavaScript source file that will be compiled.
args.compileAsModule boolean If true, the output will be a commonjs module. Default: true.
args.electron boolean If true, the output will be a compiled through Electron. Default: false.
args.electronPath string Path to Electron executable. Default: Electron binary from node_modules.
args.output string The output filename. Defaults to the same path and name of the original file, but with .jsc extension.
args.createLoader boolean | string If true, create a CommonJS loader file. As a string, select between module or commonjs loader. Default: false
args.loaderFilename string Filename or pattern for generated loader files. Defaults to originalFilename.loader.js. Use % as a substitute for originalFilename.
output string The output filename. (Deprecated: use args.output instead)
  • Returns:

{Promise<string>}: A Promise that resolves as the compiled filename.

  • Examples:
let compiledFilename = bytenode.compileFile({
  filename: '/path/to/your/file.js',
  output: '/path/to/compiled/file.jsc' // if omitted, it defaults to '/path/to/your/file.jsc'
});

Previous code will produce a commonjs module that can be required using require function.

let compiledFilename = await bytenode.compileFile({
  filename: '/path/to/your/file.js',
  output: '/path/to/compiled/file.jsc',
  compileAsModule: false
});

Previous code will produce a direct .jsc file, that can be run using bytenode.runBytecodeFile() function. It can NOT be required as a module. Please note that compileAsModule MUST be false in order to turn it off. Any other values (including: null, "", etc) will be treated as true. (It had to be done this way in order to keep the old code valid.)


bytenode.runBytecodeFile(filename) → {any}

Runs .jsc file and returns the result.

  • Parameters:
Name Type
filename string
  • Returns:

{any} The result of the very last statement executed in the script.

  • Example:
// test.js
console.log('Hello World!');
43;  // this will be returned
const result = bytenode.runBytecodeFile('/path/to/test.jsc');
// prints: Hello World!
console.log(result)
// prints: 43

require(filename) → {any}

  • Parameters:
Name Type
filename string
  • Returns:

{any} exported module content

  • Example:
let myModule = require('/path/to/your/file.jsc');

Just like regular .js modules. You can also omit the extension .jsc.

.jsc file must have been compiled using bytenode.compileFile(), or have been wrapped inside Module.wrap() function. Otherwise it won't work as a module and it can NOT be required.

Please note .jsc files must run with the same Node.js version that was used to compile it (using same architecture of course). Also, .jsc files are CPU-agnostic. However, you should run your tests before and after deployment, because V8 sanity checks include some checks related to CPU supported features, so this may cause errors in some rare cases.


Acknowledgements

I had the idea of this tool many years ago. However, I finally decided to implement it after seeing this issue by @hashseed. Also, some parts were inspired by v8-compile-cache by @zertosh.

bytenode's People

Contributors

clansty avatar dopry avatar g122622 avatar haoolee avatar herberttn avatar jjeff avatar meyertime avatar osamaabbas avatar piranna avatar s100 avatar zhshch2002 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

bytenode's Issues

question: how to use with pm2?

thanx for this package. How can i start my jsc file with bytenode using pm2?
i am trying to start jsc as a service using pm2

Does *.jsc file is safe?

I am newbie at it, so don't judge plz.
How should i know if *.jsc could be decompiled?
Does it really hide source code of my app? Because i have tried many ways to protect it in WASM, PKG (npm), etc...
PKG creates binary file, which i can read by simple notepad and find pure JS. So it hides code a bit.

Error: unrecognized flag --no-flush-bytecode

Regrettably it looks as if the fix introduced for issue #41 - setting the V8 flag, --no-flush-bytecode - has made it so that bytenode can no longer be loaded on earlier versions of Node.js where this flag does not exist. In our case:

nvm use 10.16.3
npm install bytenode
node -e "require('bytenode')"

outputs:

Error: unrecognized flag --no-flush-bytecode
Try --help for options

This occurs with [email protected] onwards. Pinning to [email protected] resolves the issue. Upgrading to Node.js 12.10.0 also resolves it.

Unfortunately V8's flags are exceedingly poorly documented and I'm not aware of any API for listing the flags so we can check whether the flag exists before trying to set it...

invalid or unexpected token at Layer.handle_error

i am using webpack:

   new BytenodeWebpackPlugin({
                compileAsModule: true,
            })

and use pm2 with launcher:

require('bytenode');
require('./server.jsc');

and then:
pm2 start launcher.js

below error with version 13.3.0
image

below error with version 12.13.1
image

Error while upgrading Electron 5.0.8 to Electron 7.1.1

Hi OsamaAbbas!

I'm building an Electron app with Bytenode and faced a weird problem.

I open the app and close it after a few seconds, it works well. But I open and wait a few minutes then close, it throws errors like this:

err1
err2

Can you give me some suggestions?
Thanks you so much.

Info:
Windows 10
Node 12.8.1
Electron 7.1.1
Bytenode 1.1.2

Cannot read property 'sync' of undefined

LST@lst-genesis:~/Documents/seqproj3$ bytenode index.jsc
evalmachine.:1
"​​​​​​​​​​�

TypeError: Cannot read property 'sync' of undefined
at Object. (evalmachine.:1:269)
at Object.Module._extensions.(anonymous function) [as .jsc] (/home/genesis/.npm-global/lib/node_modules/bytenode/index.js:216:26)
at Module.load (module.js:566:32)
at tryModuleLoad (module.js:506:12)
at Function.Module._load (module.js:498:3)
at Function.Module.runMain (module.js:694:10)
at startup (bootstrap_node.js:204:16)
at bootstrap_node.js:625:3

Performance

With API server having 100k lines of code (2.89 MB), compiled jsc - 4.36 MB.

With bytenode:

avg rps: 14443.6
avg. latency: 0.22 ms

Without bytenode:

avg rps:  17303.64
avg latency: 0.08 ms

Error: Invalid or incompatible cached data (cachedDataRejected)

I am trying to compile some nodejs that im using inside and electron app. I used nvm and selected the same versions of node as the node js i use inside the project to run the file compilation.
But when it try to npm start i get : Error: Invalid or incompatible cached data (cachedDataRejected).

Here you can see the node version used to compile the app is the same as the one running in my project.
wtf

Thanks for this awesome tool by the way :)

encryption cache inheritable/accessible?

I'm not very sure how is the cache mechanism is implemented but currently I'm having trouble running the compiled code in container.

So If I compile the js to jsc in the build statge, eg.travis then run the app in the container from fresh, it would install the bytenode as new (different copy), and then caused the cache inconsistency problem.

Or maybe enable an option to disable encryptcache?

jsc file content is "undefined"

jsc file content is "undefined" with nothing else. My main-src.js file runs fine.

Getting this error:
Unable to open 'main.js': File not found node_modules/electron/dist/resources/default_app.asar/main.js).

compiledWrapper.apply is not a function

This is Node.js v10.16.0 on Windows 10 64-bit. We also see this on Node.js v10.16.2 on Linux 64-bit.

This is a really puzzling and intermittent error and I must apologise but it's been very difficult to come up with consistent steps to reproduce it. I feel as if the problem may be environmental but there are aspects of how bytenode works which I do not understand so I'm not sure what kind of environmental issue could be causing this, which is why I'm reaching out for help. Here's the minimal scenario I've managed to concoct:

src/main.js:

console.log('hello world')

build/build.js (this consumes src/main.js and outputs dist/main.jsc):

const bytenode = require('bytenode')
const fsExtra = require('fs-extra')
const tmp = require('tmp')

fsExtra.removeSync('./dist')
fsExtra.ensureDirSync('./dist')

const source = fsExtra.readFileSync('./src/main.js')

const tmpFile = tmp.fileSync()
fsExtra.writeFileSync(tmpFile.name, source)

bytenode.compileFile({
  filename: tmpFile.name,
  compileAsModule: true,
  output: './dist/main.jsc'
})

dist/main.jsc is about 1kB of bytecode, of course, and I can't attach it, but here's the Base64 for it if that's any use:

tQPewIr01PReAAAA/wMAAOyrzzQGAAAAAAAAAGgDAAC6UcawNe4pcAAAAIAgAACAwAQAgAAAAIAAAACAAAAAgAIskwIkFsjAAAAAAAgAAAACDIzAAAAAAAEAAAACLJMCLPDAAAAAABcAAAACFIzAAAAAAAMAAAACEJHCutOeVQAAAAAAAAAABwAAAGNvbnNvbGUAAhCRwobZQrcAAAAAAAAAAAMAAABsb2cAAAAAAAIUkcP+HxH6AAAAAAAAAAALAAAAaGVsbG8gd29ybGQAAAAAAAIIi8AAAAAAAAAAAAIQi8IAAAAACgAAAAEWAmgLEBUADCoAAAAAAADFGAAAADAAAAAAAAAAAEACAAAAoBMAACb6KPoBAib7EgIm+Vf7+vkEDaQAAAAAAAAAAkSSxAAAAAAPAAAAAAAAAMFdAAAAAAAABQAAAAAAAAAAAAAAAAAAAAAAAAACEJHCLvpbsAAAAAAAAAAABwAAAGV4cG9ydHMAAhCRwp7Ws14AAAAAAAAAAAcAAAByZXF1aXJlAAIQkcLSPVIMAAAAAAAAAAAGAAAAbW9kdWxlAAACFJHDlgXFAgAAAAAAAAAACgAAAF9fZmlsZW5hbWUAAAAAAAACFJHDUlynEgAAAAAAAAAACQAAAF9fZGlybmFtZQAAAAAAAADAAAAAAAAAAACJwAAAAAD/////hMEAAAAACgAAAAAAAABcAAAAAggWuMAGAAAABhRAAAJEFs0HFwACGJHEIpY3ZQAAAAAAAAAAFwAAAGV2YWxtYWNoaW5lLjxhbm9ueW1vdXM+AMEAAAAAAAAAAAAAAAAAAAAAhODAAAAAAAIAAACEwAAAAACHAAAAhMAAAAAAAAAAAAEQFi0BwAAAAAACAAAAfgoAfgpcwAAAAAACAAAAhOCewAAAAAAEAAAAicMBAAAABQAAAAUAAAAKAAAAKAAAAFwAAAABAAAAAAgAAAIIi8AAAAAAAAAAAAIMi8EAAAAABwAAAAECAgAMugEAwwgAAAAIAAAAAAAAAABAAgAAAKB8AAAAJvukAAAAAAAAAjCSxQAAAAAKAAAAAAAAAEMMAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAABblA4nCAAAAAP////8AAAAAAAAAAAAAAABeAAAAAgjxwAEAAAASAAAACrkBwAAAAAAEAAAAicMAAAAAAAAAAAAAAAAKAAAAAgAAAF4AAAD/////AAgAABwvLy8vLy8v

index.js (this serves as the entry point):

require('bytenode')
module.exports = require('./dist/main.jsc')

When I run index.js, I get

hello world

Process finished with exit code 0

When I debug index.js (my debugger in this case is WebStorm 2019.2), I get

Debugger listening on ws://127.0.0.1:59811/0c14ba72-bbe5-476b-9ba7-979b3b9a6b03
For help, see: https://nodejs.org/en/docs/inspector
Debugger attached.
C:\Users\...\node_modules\bytenode\index.js:216
  return compiledWrapper.apply(module.exports, args);
                         ^

TypeError: compiledWrapper.apply is not a function
    at Object.Module._extensions.(anonymous function) [as .jsc] (C:\Users\...\node_modules\bytenode\index.js:216:26)
    at Module.load (internal/modules/cjs/loader.js:653:32)
    at tryModuleLoad (internal/modules/cjs/loader.js:593:12)
    at Function.Module._load (internal/modules/cjs/loader.js:585:3)
    at Module.require (internal/modules/cjs/loader.js:690:17)
    at require (internal/modules/cjs/helpers.js:25:18)
    at Object.<anonymous> (C:\Users\...\index.js:2:18)
    at Module._compile (internal/modules/cjs/loader.js:776:30)
    at Object.Module._extensions..js (internal/modules/cjs/loader.js:787:10)
    at Module.load (internal/modules/cjs/loader.js:653:32)
Waiting for the debugger to disconnect...

Process finished with exit code 1

I also see this problem when not debugging, in some scenarios where the bytenoded source is much larger. In this case I find that trying to load the module interactively, e.g.

node
> require('my-module')
TypeError: compiledWrapper.apply is not a function

> require('my-module')
TypeError: compiledWrapper.apply is not a function

causes the compiledWrapper error to repeat on each attempt... but simply exiting the interactive session and running node again can cause the problem to go away semi-permanently.

Closer inspection of Module._extensions[.jsc] indicates that under normal circumstances, the value returned from compiledWrapper = script.runInThisContext(...) is a function, whose string representation is 91 copies of U+200B ZERO WIDTH SPACE in a row. But in the failure case, compiledWrapper is simply a 92-character string consisting of U+200B ZERO WIDTH SPACEs. In both cases length = readSourceHash(bytecodeBuffer) returned 94. A string has no apply method on it, hence the error.

What could be causing this?

Compiled code only working if bytenode.compileFile is executed using the dev console

I'm running into a very strange issue while using bytenode to compile the .js files of my Electron app.
I have a compile.js file, which will compile all my code into bytecode. If i try to use it by running require("./compile") from any .js file within the render process the compiled code won't work and gives me an error message. If I on the other hand run require("./compile") from the dev tools console the compiled code works just fine.

compile.js:

const bytenode = require("bytenode")
const fs = require('fs');
const v8 = require('v8');

v8.setFlagsFromString('--no-lazy');

bytenode.compileFile("./src/modules/file.js", "./src/modules/file.jsc");

Error message:

#
# Fatal error in , line 0
# ignored
#
#
#
#FailureMessage Object: 0x7ffeee8750900   Electron Framework                  0x0000000108da5a59 v8::internal::SetupIsolateDelegate::SetupHeap(v8::internal::Heap*) + 12223577
1   Electron Framework                  0x0000000108cfe163 v8::internal::SetupIsolateDelegate::SetupHeap(v8::internal::Heap*) + 11537251
2   Electron Framework                  0x000000010aa3771b v8::internal::SetupIsolateDelegate::SetupHeap(v8::internal::Heap*) + 42180891
3   Electron Framework                  0x000000010aa19823 v8::internal::SetupIsolateDelegate::SetupHeap(v8::internal::Heap*) + 42058275
4   Electron Framework                  0x0000000107737f84 v8::internal::Parser::DoParseFunction(v8::internal::Isolate*, v8::internal::ParseInfo*, v8::internal::AstRawString const*) + 340
5   Electron Framework                  0x0000000107737a4c v8::internal::Parser::ParseFunction(v8::internal::Isolate*, v8::internal::ParseInfo*, v8::internal::Handle<v8::internal::SharedFunctionInfo>) + 524
6   Electron Framework                  0x0000000107a7c1e8 v8::internal::parsing::ParseFunction(v8::internal::ParseInfo*, v8::internal::Handle<v8::internal::SharedFunctionInfo>, v8::internal::Isolate*, v8::internal::parsing::ReportErrorsAndStatisticsMode) + 248
7   Electron Framework                  0x00000001077fbae1 v8::internal::Compiler::CollectSourcePositions(v8::internal::Isolate*, v8::internal::Handle<v8::internal::SharedFunctionInfo>) + 1025
8   Electron Framework                  0x0000000107885d32 v8::internal::Factory::NewProperSubString(v8::internal::Handle<v8::internal::String>, int, int) + 2258
9   Electron Framework                  0x0000000107885bb6 v8::internal::Factory::NewProperSubString(v8::internal::Handle<v8::internal::String>, int, int) + 1878
10  Electron Framework                  0x00000001078acd58 v8::internal::Factory::NewStackFrameInfo(v8::internal::Handle<v8::internal::FrameArray>, int) + 264
11  Electron Framework                  0x0000000107a62f39 v8::internal::ScopeInfo::InferredFunctionName() const + 11849
12  Electron Framework                  0x0000000107a623e7 v8::internal::ScopeInfo::InferredFunctionName() const + 8951
13  Electron Framework                  0x000000010765c3b8 v8::StackFrame::GetFunctionName() const + 56
14  Electron Framework                  0x0000000107dba93e v8_inspector::V8StackTraceId::V8StackTraceId(unsigned long, std::__1::pair<long long, long long>) + 78
15  Electron Framework                  0x0000000107da7ae2 v8_inspector::V8StackTraceId::V8StackTraceId() + 21282
16  Electron Framework                  0x0000000107dbb357 v8_inspector::V8StackTraceId::V8StackTraceId(unsigned long, std::__1::pair<long long, long long>) + 2663
17  Electron Framework                  0x0000000107da6056 v8_inspector::V8StackTraceId::V8StackTraceId() + 14486
18  Electron Framework                  0x0000000107da35df v8_inspector::V8StackTraceId::V8StackTraceId() + 3615
19  Electron Framework                  0x0000000107d8a2e3 v8_inspector::DumpAsyncTaskStacksStateForTest(v8_inspector::V8Inspector*) + 30947
20  Electron Framework                  0x0000000107d88694 v8_inspector::DumpAsyncTaskStacksStateForTest(v8_inspector::V8Inspector*) + 23700
21  Electron Framework                  0x0000000107d88753 v8_inspector::DumpAsyncTaskStacksStateForTest(v8_inspector::V8Inspector*) + 23891
22  Electron Framework                  0x00000001077e3444 v8::internal::Accessors::MakeAccessor(v8::internal::Isolate*, v8::internal::Handle<v8::internal::Name>, void (*)(v8::Local<v8::Name>, v8::PropertyCallbackInfo<v8::Value> const&), void (*)(v8::Local<v8::Name>, v8::Local<v8::Value>, v8::PropertyCallbackInfo<v8::Boolean> const&)) + 283572
23  Electron Framework                  0x00000001077ad235 v8::internal::Accessors::MakeAccessor(v8::internal::Isolate*, v8::internal::Handle<v8::internal::Name>, void (*)(v8::Local<v8::Name>, v8::PropertyCallbackInfo<v8::Value> const&), void (*)(v8::Local<v8::Name>, v8::Local<v8::Value>, v8::PropertyCallbackInfo<v8::Boolean> const&)) + 61861
24  Electron Framework                  0x0000000108167fb9 v8::internal::compiler::ZoneStats::ReturnZone(v8::internal::Zone*) + 839161
25  Electron Framework                  0x00000001080ee001 v8::internal::compiler::ZoneStats::ReturnZone(v8::internal::Zone*) + 339521
26  Electron Framework                  0x00000001081186d0 v8::internal::compiler::ZoneStats::ReturnZone(v8::internal::Zone*) + 513296
27  Electron Framework                  0x000000010813c972 v8::internal::compiler::ZoneStats::ReturnZone(v8::internal::Zone*) + 661426

Can you run bytenode .jsc compiled with app using Vue.js

I have a normal application that is built in node.js and Vue js. To run the application I have to use an index.html file which in turn calls the .js files.

I am wondering if it is possible to use the files compiled with .jsc with an index.html file that calls them.

So my question is: Is it possible to compile an index.html file in the .jsc format in such a way that it can then be run with bytenode?

Supporting TypeScript

This looks super interesting, especially the Electron part which is an issue for proprietary apps. One thing that might increase its adoption would be to also support compiling TS files. Of course one can always redirect the CLI to pickup the resulting js files from tsc but having this built-in - maybe with ts-node - would make it even more comfortable.

how to use it with pm2?

// start.js
var process = require('child_process');
process.exec('npx bytenode app.jsc',function (error, stdout, stderr) {
if (error !== null) {
console.log('exec error: ' + error);
}
});

 pm2 start start.js

Is that right?

Creating app using webpack, electron and bytenode

Hi,
I am trying to create a app using webpack and electron. My end goal is to hide the sources for my application.
I created the bytecode for bundle.js and I am trying to use the bundle.jsc in my index.html
So I did the following

require("bytenode");
module.exports = require("./build/bundle.jsc");

Named the above file as dist.js and used in index.html as follows

<script src="dist.js"></script>

When I launch the electron app with electron .

I get the following error

Uncaught Error: Invalid or incompatible cached data (cachedDataRejected)
    at Object.Module._extensions.<computed> [as .jsc]

bundle.jsc is 2.1MB
Node version is v12.13.0

Thanks,

unable to execute /bin/bytenode: Argument list too long

Hello, Appreciate your advice.

When trying the following command sudo bytenode --compile ../projectName/**/*.js i get the stated error "unable to execute /bin/bytenode: Argument list too long"

Note: project node modules are included and when trying without them, I get an error of "cannot find express module" when running the project .jsc

Node Version: 10.0.0
Environment: RedHat 7 server

Can't make it work executing inside .js file

I'm trying to run those:

main.js

let myModule = require('./code.jsc');
myModule.print();

code.js

module.exports = {
	print(){
		console.log('works!');
	}
};

It works when I use bytenode code.jsc directly but doesn't work when I use node main.js (output nothing)

I compiled with the following command:
bytenode -c code.js

Am I missing something?

Platform: Mac OS

Why is compiled code bigger than regular code?

I tested compiling a 10kb file I had and the resulting .jsc file was 19kb. I really expected it to be way smaller. Is this expected behavior? Is the code made longer as a side-effect of making it run faster?

especify output file.

Hi, i search but not finded, the way to especify the output file.
So i created thwo files to automatize the process.
Would very nice, if we can especify the path to output file.

First file [ compile.Bat ]

call bytenode --compile %cd%\src%1.js
move /y %cd%\src%1.jsc %cd%\bin.

Second file [ run.bat ]

MD %cd%\bin
Del %cd%\bin. /s /q
Copy %cd%\src*.json %cd%\bin. /y

rem List of files to compile

call compile.bat index
call compile.bat router
call compile.bat conn
call compile.bat mongod
call compile.bat cliente\cliente

bytenode %cd%\bin\index.jsc

Buffer is undefined in electron

If I compile a .jsc file inside an electron process with bytenode.compileFile('./test.js', './test.jsc'); and that file contains references to node-js's Buffer object. It is undefined.

So a "new Buffer(1);" gives a TypeError: undefined is not a constructor exception. And this exception only occurs when requiring the .jsc file of course. The .js file works fine.

Support for Directory?

user@machine:~$ bytenode --compile ./**/*.js

This command doesn't compile all .js files actually.

I had a demo like this, and I ran bytenode --compile ./**/*.js.
image

Only a.js was compiled. Can bytenode support the directory mode? Something like:

user@machine:~$ bytenode --compile ./dist

Using modules

Is there a way of including npm modules in the compile? Would make it easier to have the same versions of modules running everywhere without having to actually install them on the machine where itll run

A JavaScript error occurred in the main process

Uncaught Exception:
SyntaxError: Invalid or unexpected token
  at Timeout._onTimeout
  at listOnTimeout (internal/timers.js:531:17)
  at processTimers (internal/timers.js:475:7)

I'm using Electron, and have a file that requires a .jsc file which requires a .jsc file. I did use the same Electron to compile these files to bytecode. And the app was working fine for a minute, until this error randomly popped up. And everytime I clicked ok it popped up again. I had to use Task Manager to kill the process. This was an executable created with electron-builder.

I probably won't be able to get a minimum example but maybe this will be useful for future reference.

SyntaxError: Invalid or unexpected token

Sending messages to worker:

(node:30) UnhandledPromiseRejectionWarning: SyntaxError: Invalid or unexpected token
at runMicrotasks (<anonymous>)
at processTicksAndRejections (internal/process/task_queues.js:93:5)
(node:30) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). (rejection id: 2)

Express random error when i enter a route that doesn't exists

SyntaxError: Invalid or unexpected token
    at Layer.handle [as handle_request] (/sistema/server/node_modules/express/lib/router/layer.js:95:5)
    at next (/sistema/server/node_modules/express/lib/router/route.js:137:13)
    at Route.dispatch (/sistema/server/node_modules/express/lib/router/route.js:112:3)
    at Layer.handle [as handle_request] (/sistema/server/node_modules/express/lib/router/layer.js:95:5)
    at /sistema/server/node_modules/express/lib/router/index.js:281:22
    at param (/sistema/server/node_modules/express/lib/router/index.js:354:14)
    at param (/sistema/server/node_modules/express/lib/router/index.js:365:14)
    at Function.process_params (/sistema/server/node_modules/express/lib/router/index.js:410:3)
    at next (/sistema/server/node_modules/express/lib/router/index.js:275:10)
    at SendStream.error (/sistema/server/node_modules/serve-static/index.js:121:7)
    at SendStream.emit (events.js:210:5)
    at SendStream.error (/sistema/server/node_modules/send/index.js:270:17)
    at SendStream.onStatError (/sistema/server/node_modules/send/index.js:421:12)
    at next (/sistema/server/node_modules/send/index.js:735:16)
    at onstat (/sistema/server/node_modules/send/index.js:724:14)
    at FSReqCallback.oncomplete (fs.js:158:21)

This is one of the many errors i get when i run my project compiled with bytenode. Any help? My project is stable with the source code. But i need to protect it.

Electron example, console.log does not work

console.log doesnt work in *.jsc files somehow. I mean nothing displays in console.

//the main.js file
'use strict';
const bytenode = require('../../');
const fs = require('fs');
const v8 = require('v8');
v8.setFlagsFromString('--no-lazy');
if (!fs.existsSync('./main-window.jsc')) {
  bytenode.compileFile('./main-window.src.js', './main-window.jsc');
}
require('./main-window.jsc');
//the main-window.src.js file
'use strict';
let DEBUG = true;                       //aded this
function deb(arg1="",arg2 ="") {
    if (DEBUG) {
        console.log(arg1,arg2);
    }
}
const electron = require('electron');
const { app, BrowserWindow } = require('electron');
let okHTML = `
<h1>Hello World!</h1>
<p>Feel free to use this free trial.</p>
`;
let noHTML = `
<h1>Hello World!</h1>
<p>This app is expired.</p>
`;
let mainWindow;
function createWindow() {
  mainWindow = new BrowserWindow({ width: 800, height: 600 });
  mainWindow.loadFile('index.html');
  setTimeout(function () {
    if (Date.now() > 1234567891000) {
      mainWindow.webContents.send('set-html', noHTML);
      deb("noHTML:","just sent");                      //aded this
    } else {
      mainWindow.webContents.send('set-html', okHTML);
      deb("okHTML:","just sent");                      //aded this
    }
  }, 1000);
  mainWindow.on('close', _ => {
    mainWindow = null;
  });
}
app.on('ready', createWindow);
app.on('window-all-closed', _ => {
  if (process.platform !== 'darwin') {
    app.quit();
  }
});
app.on('activate', _ => {
  if (mainWindow === null) {
    createWindow();
  }
});
exports.app = app;
exports.mainWindow = mainWindow;

What am i doing wrong? Thx in advance.

It doesn't work with main.js

I tried moving most of my main code to another file (built a jsc ofcourse )and included that to main.js file, is there a better way to achieve this?

RangeError: Invalid string length

Nice idea, but for some reason it doesn't want to work out of the box.

This example:

const bytenode = require('bytenode');

let helloWorldBytecode = bytenode.compileCode(`console.log('Hi there')`)
bytenode.runBytecode(helloWorldBytecode);

Produce

let dummyCode = ' '.repeat(length);
                      ^

RangeError: Invalid string length
let length = bytecodeBuffer.slice(8, 12).reduce((sum, number, power) => sum += number * 256 ** power, 0);
let dummyCode = ' '.repeat(length); // length is too big

I wonder, what's the magic behind this line?

Node version: v8.9.3, Mac

error when run in node 12

const Koa = require('koa');
const KoaRouter = require('koa-router');
const app = new Koa();
const router = new KoaRouter();

module.exports = class HttpServer {
  start() {
    router.get('/a', async ctx => {
      ctx.body = 'a';
    });

    router.get('/b', async ctx => {
      ctx.body = 'b';
    });

    router.get('/c', async ctx => {
      ctx.body = 'c';
    });

    router.get('/d', async ctx => {
      ctx.body = 'd';
    });

    app.use(router.routes()).use(router.allowedMethods());
    app.listen(3000);
  }
};

it raise libc++abi.dylib: terminating with uncaught exception of type std::out_of_range: vector
when compile and run in node 12 with mac 10.14 (bytenode -c app.js && bytenode app.jsc)
but it is ok when compile and run in node 10

change the code to

const Koa = require('koa');
const KoaRouter = require('koa-router');
const app = new Koa();
const router = new KoaRouter();

module.exports = class HttpServer {
  start() {
    router.get('/a', async ctx => {
      ctx.body = 'a';
    });

    router.get('/b', async ctx => {
      ctx.body = 'b';
    });

    router.get('/c', async ctx => {
      ctx.body = 'c';
    });

    // router.get('/d', async ctx => {
    //   ctx.body = 'd';
    // });

    app.use(router.routes()).use(router.allowedMethods());
    app.listen(3000);
  }
};

it is ok compile and run in node 12

Debugging from log

Hi, first of all, this is really cool

im planning to use bytenode in one of my production environment,
one issue tho, say my app crashed, any idea how can i pinpoint where is the crash ?

example:
this is the crash log i got from a .jsc file

TypeError: Cannot read property 'push' of undefined
    at Router.get (evalmachine.<anonymous>:1:250)
    at Layer.handle [as handle_request] (/home/engineer2/Vouch/sandbox/nexe-test/node_modules/express/lib/router/layer.js:95:5)
...
...

from that, i can't really see which line is the culprit.
just want to hear your thought on this,
i'm guessing this is a trade off for using this kind of tool ?

thanks!


edit:

also, theoretically, is there a way to reverse engineer complied file ?

JavaScript heap out of memory

I'm getting this error when I try running my app using bytenode in a container

<--- Last few GCs --->                                  

[1654:0x33e0190]    21287 ms: Mark-sweep 1398.4 (1424.8) -> 1398.4 (1424.8) MB, 2439.7 / 0.0 ms  (+ 0.1 ms in 54 steps since start of marking, biggest step 0.0 ms, walltime since start of marking 2464 ms) (average mu = 0.149, current mu = 0.022) allocatio[1654:0x33e0190]    23754 ms: Mark-sweep 1399.8 (1424.8) -> 1399.8 (1425.8) MB, 2464.9 / 0.0 ms  (+ 0.0 ms in 23 steps since start of marking, biggest step 0.0 ms, walltime since start of marking 2467 ms) (average mu = 0.079, current mu = 0.001) allocatio                                                  

<--- JS stacktrace --->                                 

==== JS stack trace =========================================                                                   

    0: ExitFrame [pc: 0x20edef0dbe1d]                   
    1: StubFrame [pc: 0x20edef0dd1df]                   
Security context: 0x024abec1e6e9 <JSObject>             
    2: setCookie [0x19ad8bbb19f1] [evalmachine.<anonymous>:~1] [pc=0x20edef16e729](this=0x19ad8bbb1a69 <Object map = 0x146bbbf55df1>,i=0x2ceeeceafe79 <JSArray[8642921]>,j=0x0afdd57064f1 <String[7]: counter>,k=1,l=0x2ceeeceafe99 <Object map = 0x146bbbf02571>)                      
    3: arguments adaptor frame: 3->4                    
    4: g [0x19ad8bbb1b29] ...                           

FATAL ERROR: Ineffective mark-compacts near heap limit Allocation failed - JavaScript heap out of memory        
 1: 0x8dc510 node::Abort() [/usr/local/bin/node]        
 2: 0x8dc55c  [/usr/local/bin/node]                     
 3: 0xad9b5e v8::Utils::ReportOOMFailure(v8::internal::Isolate*, char const*, bool) [/usr/local/bin/node]       
 4: 0xad9d94 v8::internal::V8::FatalProcessOutOfMemory(v8::internal::Isolate*, char const*, bool) [/usr/local/bin/node]                                                                                                         
 5: 0xec7bf2  [/usr/local/bin/node]                     
 6: 0xec7cf8 v8::internal::Heap::CheckIneffectiveMarkCompact(unsigned long, double) [/usr/local/bin/node]       
 7: 0xed3dd2 v8::internal::Heap::PerformGarbageCollection(v8::internal::GarbageCollector, v8::GCCallbackFlags) [/usr/local/bin/node]                                                                                            
 8: 0xed4704 v8::internal::Heap::CollectGarbage(v8::internal::AllocationSpace, v8::internal::GarbageCollectionReason, v8::GCCallbackFlags) [/usr/local/bin/node]                                                                
 9: 0xed7371 v8::internal::Heap::AllocateRawWithRetryOrFail(int, v8::internal::AllocationSpace, v8::internal::AllocationAlignment) [/usr/local/bin/node]                                                                        
10: 0xea07f4 v8::internal::Factory::NewFillerObject(int, bool, v8::internal::AllocationSpace) [/usr/local/bin/node]                                                                                                             
11: 0x114018e v8::internal::Runtime_AllocateInNewSpace(int, v8::internal::Object**, v8::internal::Isolate*) [/usr/local/bin/node]                                                                                               
12: 0x20edef0dbe1d                                      

Mixed environments

Hi Osama,
Thanks for your nice product. I use it now in a product of mine.

As an enhancement would be nice to think about mixed environments. Think about projects that depend on stable lts version of node but new projects use latest.

When developing many IDE tools give the opportunity to work with a certain version of node.
Using bytenode it uses global install and compiles with the current system-wide node.

thanks again.
Jan

How to compile worker_threads

Hi, I'm using bytenode, this is a reallly great stuff for protection your code, but i have a problem, the problem is that i can't compile my source project with worker_threads. If i compile it, when i run my project i get this error:

TypeError [ERR_WORKER_UNSUPPORTED_EXTENSION]: The worker script extension must be ".js" or ".mjs". Received ".jsc"

How can I solve the error?
Great thanks in advance.

Support for compiling whole project

I don't know if it is already possible to compile the entire project, including the required modules inside the project folder and node_modules.
I wonder if it is possible to compile everything in one giant file. Any tip?

Random crashes in electron when using spawned FFMPEG

Took me awhile to pinpoint what was causing these random crashes. No logs or error events. Just random crashes usually when clicking the app icon to being the app back in focus on OSX. I have no way to trace this issue, any advice would be great.

(Not using FFMPEG the compiler code works just great!)

BUG: runBytecodeFile not working!

Hi,

I am trying to programmatically run a simple compiled jsc file but nothing happens!

My code is: (index.js)

'use strict';

const v8 = require('v8');
const path = require('path');
const bytenode = require('bytenode');

v8.setFlagsFromString('--no-lazy');

const file = path.join(process.cwd(), 'test.jsc');

bytenode.runBytecodeFile(file);

test.js (test.jsc)

console.log('Hello World');

There is no output when running: node index.js

What am i doing wrong?

production ready?

Thank you for working on this project.

Is this ready for production use? Is there a wiki page with list of projects using it in production?

Thoughts about bytecode flushing

Thanks for your inspiring project 👍.

I have a question about implementation. Currently, a dummy source string is used to instantiate vm.Script. However, V8 docs(https://v8.dev/blog/v8-release-74#bytecode-flushing) says

Any bytecode which crosses an aging threshold is eligible to be collected by the next garbage collection, and the function resets to lazily recompile its bytecode if it is ever executed again in the future.

It seems that V8 lazily recompiles a function's source string if it is executed after its bytecode is garbage collected. Will the dummy string make a potential bug because of the bytecode-flushing technique?

Example for runBytecodeFile not working

Hi,

I compiled a file test.js with console.log('Hello World!') inside. Nothing else.
Compilation is done by bytenode -c test.js

Then I use this file (testexe.js) to execute test.jsc
const bytenode = require("bytenode");
bytenode.runBytecodeFile('test.jsc');

I use
node testexe.js
for execution.

I get no 'Hello World!'
But if I use bytenode test.jsc it works.

I use node v10.13.0 in WIn10 x64

Any ideas?

fail test - bytenode, ncc, fastify ?

#!/usr/bin/env bash

export __TEST_DIR__="bytenode-ncc-fastify-test"

mkdir $__TEST_DIR__
cd $__TEST_DIR__

npm init --yes
npm i fastify -E
npm i bytenode @zeit/ncc -E -D

touch index.js

read -r -d '' INDEX_JS << EOF
  'use strict';
  const build = require('fastify');
  const server = build({ logger: true });
  server.all('/', async () => ({ ok: 'ok' }));
  (async () => await server.listen())();
EOF

echo $INDEX_JS > index.js

npx @zeit/ncc build index.js --out dist
npx bytenode --compile dist/index.js

# this should run?
# but it does not...
# npx bytenode $__TEST_DIR__/dist/index.jsc
npx bytenode dist/index.jsc

# Error =>
# undefined:6
#     ?
#
# SyntaxError: Invalid or unexpected token
#     at Function (<anonymous>)
#     at build (evalmachine.<anonymous>:1:70996)
#     at Object.560 (evalmachine.<anonymous>:1:521710)
#     at __webpack_require__ (evalmachine.<anonymous>:1:769)
#     at Object.360 (evalmachine.<anonymous>:1:395429)
#     at __webpack_require__ (evalmachine.<anonymous>:1:769)
#     at Object.104 (evalmachine.<anonymous>:1:66439)
#     at __webpack_require__ (evalmachine.<anonymous>:1:769)
#     at startup (evalmachine.<anonymous>:1:1228)
#     at evalmachine.<anonymous>:1:1390


#### this however runs ok
####
#### node dist/index.js
#### node $__TEST_DIR__/dist/index.js
#### node ./bytenode-ncc-fastify-test/dist/index.js

Can you run a bytenode compiled .jsc file with mocha?

I am trying to do the following with .jsc files. Is that possible? (see below)
var Mocha = require('mocha'),
fs = require('fs'),
path = require('path');
// Instantiate a Mocha instance.
var mocha = new Mocha();

var testDir = '[path to test dir]';

// Add each .js file to the mocha instance
fs.readdirSync(testDir).filter(function(file) {
// Only keep the .js files
return file.substr(-3) === '.js';

}).forEach(function(file) {
mocha.addFile(
path.join(testDir, file)
);
});

// Run the tests.
mocha.run(function(failures) {
process.exitCode = failures ? 1 : 0; // exit with non-zero status if there were failures
});
The compiled file would be a mocha script
I hope it make sense

"http2" module

Hi, thank you very much for your great project!

I used bytenode very much. I had an error "Cannot resolve dependency 'http2'" where I used:

const http2 = require("http2");

I confirmed require("http"); and require("https"); worked well. Could you tell me bytenode currently doesn't support "http2" module?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.