Modify readme, implement cross-plat --python <loc> closes #94
This commit is contained in:
@@ -1,5 +1,3 @@
|
|||||||
## This repository is not actively maintained.
|
|
||||||
|
|
||||||
### Nexe
|
### Nexe
|
||||||
|
|
||||||
Nexe is a command-line utility that compiles your Node.js application into a single executable file.
|
Nexe is a command-line utility that compiles your Node.js application into a single executable file.
|
||||||
@@ -9,7 +7,7 @@ Nexe is a command-line utility that compiles your Node.js application into a sin
|
|||||||
|
|
||||||
### Motivation
|
### Motivation
|
||||||
|
|
||||||
- Ability to run multiple applications with *different* node.js runtimes.
|
- Ability to run multiple applications with *different* node.js runtimes.
|
||||||
- Distributable binaries without needing node / npm.
|
- Distributable binaries without needing node / npm.
|
||||||
- Starts faster.
|
- Starts faster.
|
||||||
- Lockdown specific application versions, and easily rollback.
|
- Lockdown specific application versions, and easily rollback.
|
||||||
@@ -20,69 +18,73 @@ Nexe is a command-line utility that compiles your Node.js application into a sin
|
|||||||
- Linux / Mac / BSD / Windows
|
- Linux / Mac / BSD / Windows
|
||||||
- Windows: Python 2.6 or 2.7 (in PATH), Visual Studio 2010 or 2012
|
- Windows: Python 2.6 or 2.7 (in PATH), Visual Studio 2010 or 2012
|
||||||
|
|
||||||
##Caveats
|
## Caveats
|
||||||
|
|
||||||
### Doesn't support native modules
|
### Doesn't support native modules
|
||||||
|
|
||||||
- Use the techniques below for working around dynamic require statments to exclude the module from the bundling, and deploy along side the executable in a node_module folder so your app can find it. Note: On windows you may need to have your app be named node.exe if .node file depends on node.
|
- Use the techniques below for working around dynamic require statements to exclude the module from the bundling, and deploy along side the executable in a node_module folder so your app can find it. Note: On windows you may need to have your app be named node.exe if .node file depends on node.
|
||||||
|
|
||||||
###Doesn't support dynamic require statments
|
### Doesn't support dynamic require statements
|
||||||
|
|
||||||
Such As:
|
Such As:
|
||||||
```
|
|
||||||
|
```javascript
|
||||||
var x = require(someVar);
|
var x = require(someVar);
|
||||||
```
|
```
|
||||||
|
|
||||||
In this case nexe won't bundle the file
|
In this case nexe won't bundle the file
|
||||||
|
|
||||||
```
|
```javascript
|
||||||
var x;
|
var x;
|
||||||
if (someCheck) {
|
if (someCheck) {
|
||||||
x = require("./ver1.js");
|
x = require("./ver1.js");
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
x = require("./var2.js");
|
x = require("./var2.js");
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
In this case nexe will bundle both files.
|
In this case nexe will bundle both files.
|
||||||
|
|
||||||
Workarounds:
|
Workarounds:
|
||||||
1) for dyanmic requires that you want bundled add the following into your project
|
1) for dynamic requires that you want bundled add the following into your project
|
||||||
```
|
|
||||||
|
```javascript
|
||||||
var dummyToForceIncludeForBundle = false;
|
var dummyToForceIncludeForBundle = false;
|
||||||
if (dummyToForceIncludeForBundle) {
|
if (dummyToForceIncludeForBundle) {
|
||||||
require("./loadedDynamicallyLater.js");
|
require("./loadedDynamicallyLater.js");
|
||||||
...
|
// ...
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
this will trick the bundler into including them.
|
this will trick the bundler into including them.
|
||||||
|
|
||||||
2) for dynamic files getting included that you don't want to be
|
2) for dynamic files getting included that you don't want to be
|
||||||
```
|
|
||||||
|
```javascript
|
||||||
var moduleName = "./ver2.js";
|
var moduleName = "./ver2.js";
|
||||||
if (someCheck) {
|
if (someCheck) {
|
||||||
moduleName = "./ver1.js";
|
moduleName = "./ver1.js";
|
||||||
}
|
}
|
||||||
var x = require(moduleName)
|
var x = require(moduleName);
|
||||||
```
|
```
|
||||||
Note: neither file will be bundled.
|
Note: neither file will be bundled.
|
||||||
|
|
||||||
Using these two techniques you can change your application code so mdoules are not bundles, and generate a includes.js file as part of your build process so that the right files get bundled for your build configuration.
|
|
||||||
|
|
||||||
### __dirname
|
Using these two techniques you can change your application code so modules are not bundles, and generate a includes.js file as part of your build process so that the right files get bundled for your build configuration.
|
||||||
|
|
||||||
Once the module is budnled it is part of the executable. __dirname is therefore the executable dir (process.execPath). Thus if you put resources on a realtive path from the the executable your app will be able to access them.
|
### __dirname
|
||||||
|
|
||||||
If you had a data file at /dev/myNodeApp/stateManager/handler/data/some.csv
|
Once the module is bundled it is part of the executable. __dirname is therefore the executable dir (process.execPath). Thus if you put resources on a relative path from the the executable your app will be able to access them.
|
||||||
and a file at /dev/myNodeApp/stateManager/handler/loader.js
|
|
||||||
```
|
If you had a data file at `/dev/myNodeApp/stateManager/handler/data/some.csv`
|
||||||
|
and a file at `/dev/myNodeApp/stateManager/handler/loader.js`
|
||||||
|
|
||||||
|
```javascript
|
||||||
module.exports = fw.readFileSync(path.join(__dirname, "./data/some.csv"));
|
module.exports = fw.readFileSync(path.join(__dirname, "./data/some.csv"));
|
||||||
```
|
```
|
||||||
you would need to deploy some.csv in a sub dir data/ along side your executable
|
You would need to deploy some.csv in a sub dir `data/` along side your executable
|
||||||
|
|
||||||
There are potential use cases for __dirname where the executable path is not the correct substitution, and could result in a silent error (possibly even in a dependciey that you are unaware of).
|
There are potential use cases for __dirname where the executable path is not the correct substitution, and could result in a silent error (possibly even in a dependency that you are unaware of).
|
||||||
|
|
||||||
Note: __filename will be 'undefined'
|
Note: __filename will be 'undefined'
|
||||||
|
|
||||||
### child_process.fork
|
### child_process.fork
|
||||||
|
|
||||||
@@ -99,13 +101,13 @@ Via NPM:
|
|||||||
Or git:
|
Or git:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
git clone
|
git clone
|
||||||
```
|
```
|
||||||
|
|
||||||
### CLI Usage
|
### CLI Usage
|
||||||
|
|
||||||
````text
|
```text
|
||||||
|
|
||||||
Usage: nexe -i [sources] -o [binary]
|
Usage: nexe -i [sources] -o [binary]
|
||||||
|
|
||||||
Options:
|
Options:
|
||||||
@@ -115,12 +117,12 @@ Options:
|
|||||||
-t, --temp The path to store node.js sources [default: /tmp/nexe]
|
-t, --temp The path to store node.js sources [default: /tmp/nexe]
|
||||||
-f, --flags Don't parse node and v8 flags, pass through app flags [default: false]
|
-f, --flags Don't parse node and v8 flags, pass through app flags [default: false]
|
||||||
|
|
||||||
````
|
```
|
||||||
|
|
||||||
|
|
||||||
### Code Usage
|
### Code Usage
|
||||||
|
|
||||||
````javascript
|
```javascript
|
||||||
|
|
||||||
var nexe = require('nexe');
|
var nexe = require('nexe');
|
||||||
|
|
||||||
@@ -131,7 +133,12 @@ nexe.compile({
|
|||||||
nodeTempDir: __dirname,
|
nodeTempDir: __dirname,
|
||||||
flags: true
|
flags: true
|
||||||
}, function(err) {
|
}, function(err) {
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
````
|
```
|
||||||
|
|
||||||
|
## Maintainers
|
||||||
|
|
||||||
|
* __Jared Allard__ ([@rainbowdashdc](https://github.com/RainbowDashDC)) <[rainbowdashdc@mezgrman.de](mailto:rainbowdashdc@mezgrman.de)> (Active)
|
||||||
|
* __Craig Jefferds__ ([@crcn](https://github.com/crcn)) <[craig.j.condon@gmail.com](mailto:craig.j.condon@gmail.com)> (Not Active)
|
||||||
|
|||||||
@@ -34,6 +34,11 @@ options('f', {
|
|||||||
options('v', {
|
options('v', {
|
||||||
alias: 'version',
|
alias: 'version',
|
||||||
description: 'Display version number'
|
description: 'Display version number'
|
||||||
|
}).
|
||||||
|
options('p', {
|
||||||
|
alias: 'python',
|
||||||
|
description: 'Set path of python to use.',
|
||||||
|
default: 'python'
|
||||||
});
|
});
|
||||||
|
|
||||||
var argv = cli.argv;
|
var argv = cli.argv;
|
||||||
@@ -54,12 +59,12 @@ function toRelative(pt) {
|
|||||||
return path.join(process.cwd(), pt);
|
return path.join(process.cwd(), pt);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
require('../lib').compile({
|
||||||
require('../lib').compile({
|
|
||||||
input : require.resolve(toRelative(argv.i)),
|
input : require.resolve(toRelative(argv.i)),
|
||||||
output : toRelative(argv.o),
|
output : toRelative(argv.o),
|
||||||
flags : argv.f,
|
flags : argv.f,
|
||||||
nodeVersion : argv.r,
|
nodeVersion : argv.r,
|
||||||
|
python : argv.python,
|
||||||
nodeTempDir : toRelative(argv.t) }, function(error) {
|
nodeTempDir : toRelative(argv.t) }, function(error) {
|
||||||
|
|
||||||
if(error) console.log(error.message);
|
if(error) console.log(error.message);
|
||||||
|
|||||||
@@ -3,9 +3,10 @@ var nexe = require('nexe');
|
|||||||
nexe.compile(
|
nexe.compile(
|
||||||
{
|
{
|
||||||
input: "./index.js",
|
input: "./index.js",
|
||||||
output: "./helloWorld.exe",
|
output: "",
|
||||||
nodeVersion: "0.10.33",
|
nodeVersion: "0.10.33",
|
||||||
nodeTempDir: "",
|
nodeTempDir: "",
|
||||||
|
python: "C:\\Python27\\python.exe",
|
||||||
flags: true,
|
flags: true,
|
||||||
resourceFiles: ["./message.txt"]
|
resourceFiles: ["./message.txt"]
|
||||||
},
|
},
|
||||||
@@ -14,4 +15,4 @@ nexe.compile(
|
|||||||
console.log(err);
|
console.log(err);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|||||||
+73
-12
@@ -19,8 +19,10 @@ var _log = require("./log"),
|
|||||||
_monkeypatch = require("./monkeypatch");
|
_monkeypatch = require("./monkeypatch");
|
||||||
|
|
||||||
var isWin = /^win/.test(process.platform);
|
var isWin = /^win/.test(process.platform);
|
||||||
|
var isPy;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* Compiliation process.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
exports.compile = function (options, complete) {
|
exports.compile = function (options, complete) {
|
||||||
@@ -28,11 +30,31 @@ exports.compile = function (options, complete) {
|
|||||||
var nodeCompiler, nexeEntryPath;
|
var nodeCompiler, nexeEntryPath;
|
||||||
|
|
||||||
async.waterfall([
|
async.waterfall([
|
||||||
|
/** check relevant options
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
function checkOpts (next) {
|
||||||
|
/*
|
||||||
|
* Have we been given a custom flag for python executable?
|
||||||
|
*/
|
||||||
|
if(options.python!=='python' && options.python!=="") {
|
||||||
|
if(isWin) {
|
||||||
|
isPy=options.python.replace(/\//gm, "\\"); // use windows file paths, batch is sensitive.
|
||||||
|
} else {
|
||||||
|
isPy=options.python;
|
||||||
|
}
|
||||||
|
|
||||||
|
_log("set python as "+isPy);
|
||||||
|
} else {
|
||||||
|
isPy="python";
|
||||||
|
}
|
||||||
|
|
||||||
|
next();
|
||||||
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* first download node
|
* first download node
|
||||||
*/
|
*/
|
||||||
|
|
||||||
function downloadNode (next) {
|
function downloadNode (next) {
|
||||||
_downloadNode(options.nodeVersion, options.nodeTempDir, next);
|
_downloadNode(options.nodeVersion, options.nodeTempDir, next);
|
||||||
},
|
},
|
||||||
@@ -104,11 +126,16 @@ exports.compile = function (options, complete) {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
function makeExe (next) {
|
function makeExe (next) {
|
||||||
_log("make");
|
if(isWin) {
|
||||||
|
_log("vcbuild [make stage]");
|
||||||
|
} else {
|
||||||
|
_log("make");
|
||||||
|
}
|
||||||
nodeCompiler.make(next);
|
nodeCompiler.make(next);
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* we create the output directory if needed
|
||||||
*/
|
*/
|
||||||
|
|
||||||
function makeOutputDirectory (next) {
|
function makeOutputDirectory (next) {
|
||||||
@@ -116,11 +143,20 @@ exports.compile = function (options, complete) {
|
|||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* Copy the compilied binary to the output specified.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
function copyBinaryToOutput (next) {
|
function copyBinaryToOutput (next) {
|
||||||
_log("cp %s %s", nodeCompiler.releasePath, options.output);
|
_log("cp %s %s", nodeCompiler.releasePath, options.output);
|
||||||
ncp(nodeCompiler.releasePath, options.output, next);
|
ncp(nodeCompiler.releasePath, options.output, function (err) {
|
||||||
|
if (err) {
|
||||||
|
console.log("* NOTICE * Failed to copy binary. Did the build fail?");
|
||||||
|
throw err; // dump raw error object
|
||||||
|
}
|
||||||
|
_log('copied');
|
||||||
|
|
||||||
|
next();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
], complete);
|
], complete);
|
||||||
}
|
}
|
||||||
@@ -228,7 +264,27 @@ function _getNodeCompiler (nodeFileDir, complete) {
|
|||||||
version: path.basename(nodeFileDir),
|
version: path.basename(nodeFileDir),
|
||||||
releasePath: path.join(dir, "Release", "node.exe"),
|
releasePath: path.join(dir, "Release", "node.exe"),
|
||||||
make: function(next) {
|
make: function(next) {
|
||||||
var vcbuild = spawn("vcbuild.bat", ["nosign", "release"], { cwd: dir });
|
// create a new env with minimal impact on old one
|
||||||
|
var newEnv = process.env
|
||||||
|
|
||||||
|
if(isPy!=="python") {
|
||||||
|
_log("vcbuild: python => "+isPy);
|
||||||
|
|
||||||
|
// replace vcbuild contents
|
||||||
|
var data = fs.readFileSync(dir+"\\vcbuild.bat", 'utf8');
|
||||||
|
var result = data.replace(/[\s]python/gm, isPy); // I can't regex
|
||||||
|
var err = fs.writeFileSync(dir+"\\vcbuild.bat", result, 'utf8');
|
||||||
|
if(err) throw err;
|
||||||
|
|
||||||
|
// temporary fix, should edit whatever is gening the project files at somepoint.
|
||||||
|
newEnv.path = process.env.PATH+";"+path.dirname(isPy)
|
||||||
|
}
|
||||||
|
|
||||||
|
// spawn a vcbuild process with our custom enviroment.
|
||||||
|
var vcbuild = spawn("vcbuild.bat", ["nosign", "release"], {
|
||||||
|
cwd: dir,
|
||||||
|
env: newEnv
|
||||||
|
});
|
||||||
vcbuild.stdout.pipe(process.stdout);
|
vcbuild.stdout.pipe(process.stdout);
|
||||||
vcbuild.stderr.pipe(process.stderr);
|
vcbuild.stderr.pipe(process.stderr);
|
||||||
vcbuild.on("close", function() {
|
vcbuild.on("close", function() {
|
||||||
@@ -242,7 +298,13 @@ function _getNodeCompiler (nodeFileDir, complete) {
|
|||||||
version: path.basename(nodeFileDir),
|
version: path.basename(nodeFileDir),
|
||||||
releasePath: path.join(dir, "out", "Release", "node"),
|
releasePath: path.join(dir, "out", "Release", "node"),
|
||||||
make: function (next) {
|
make: function (next) {
|
||||||
var configure = spawn("./configure", [], { cwd: dir });
|
var cfg = "./configure", configure;
|
||||||
|
if(isPy !== "python") {
|
||||||
|
configure = spawn(isPy, [cfg], { cwd: dir });
|
||||||
|
} else {
|
||||||
|
configure = spawn(cfg, [], { cwd: dir });
|
||||||
|
}
|
||||||
|
|
||||||
configure.stdout.pipe(process.stdout);
|
configure.stdout.pipe(process.stdout);
|
||||||
configure.stderr.pipe(process.stderr);
|
configure.stderr.pipe(process.stderr);
|
||||||
configure.on("close", function () {
|
configure.on("close", function () {
|
||||||
@@ -281,7 +343,7 @@ function _monkeyPatchNodeConfig (compiler, complete) {
|
|||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* monkeypatch main entry point
|
* monkeypatch main entry point
|
||||||
*/
|
*/
|
||||||
|
|
||||||
function (next) {
|
function (next) {
|
||||||
@@ -299,7 +361,7 @@ function _monkeyPatchGyp (compiler, complete) {
|
|||||||
var gypPath = path.join(compiler.dir, "node.gyp");
|
var gypPath = path.join(compiler.dir, "node.gyp");
|
||||||
|
|
||||||
_monkeypatch(
|
_monkeypatch(
|
||||||
gypPath,
|
gypPath,
|
||||||
function (content) {
|
function (content) {
|
||||||
return ~content.indexOf("nexe.js");
|
return ~content.indexOf("nexe.js");
|
||||||
},
|
},
|
||||||
@@ -317,7 +379,7 @@ function _monkeyPatchMainJs (compiler, complete) {
|
|||||||
var mainPath = path.join(compiler.dir, "src", "node.js");
|
var mainPath = path.join(compiler.dir, "src", "node.js");
|
||||||
|
|
||||||
_monkeypatch(
|
_monkeypatch(
|
||||||
mainPath,
|
mainPath,
|
||||||
function (content) {
|
function (content) {
|
||||||
return ~content.indexOf("nexe");
|
return ~content.indexOf("nexe");
|
||||||
},
|
},
|
||||||
@@ -395,9 +457,9 @@ function _logProgress (req) {
|
|||||||
req.on("response", function (resp) {
|
req.on("response", function (resp) {
|
||||||
|
|
||||||
var len = parseInt(resp.headers["content-length"], 10),
|
var len = parseInt(resp.headers["content-length"], 10),
|
||||||
bar = new ProgressBar("[:bar]", {
|
bar = new ProgressBar("[:bar]", {
|
||||||
complete: "=",
|
complete: "=",
|
||||||
incomplete: " ",
|
incomplete: " ",
|
||||||
total: len,
|
total: len,
|
||||||
width: process.stdout.columns - 2
|
width: process.stdout.columns - 2
|
||||||
});
|
});
|
||||||
@@ -409,4 +471,3 @@ function _logProgress (req) {
|
|||||||
|
|
||||||
return req;
|
return req;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1 @@
|
|||||||
module.exports = require("./exe");
|
module.exports = require("./exe");
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user