diff --git a/README.md b/README.md index eba913a..8420da1 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,3 @@ -## This repository is not actively maintained. - ### Nexe 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 -- 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. - Starts faster. - 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 - Windows: Python 2.6 or 2.7 (in PATH), Visual Studio 2010 or 2012 -##Caveats +## Caveats ### 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. - -###Doesn't support dynamic require statments +- 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 statements + Such As: -``` + +```javascript var x = require(someVar); ``` In this case nexe won't bundle the file -``` +```javascript var x; if (someCheck) { x = require("./ver1.js"); - } - else { + } else { x = require("./var2.js"); } ``` In this case nexe will bundle both files. - + 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; if (dummyToForceIncludeForBundle) { require("./loadedDynamicallyLater.js"); - ... + // ... } ``` this will trick the bundler into including them. - + 2) for dynamic files getting included that you don't want to be -``` + +```javascript var moduleName = "./ver2.js"; if (someCheck) { moduleName = "./ver1.js"; } - var x = require(moduleName) + var x = require(moduleName); ``` 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 -and a file at /dev/myNodeApp/stateManager/handler/loader.js -``` +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. + +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")); ``` -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 @@ -99,13 +101,13 @@ Via NPM: Or git: ```bash - git clone + git clone ``` ### CLI Usage -````text - +```text + Usage: nexe -i [sources] -o [binary] Options: @@ -115,12 +117,12 @@ Options: -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] -```` +``` ### Code Usage -````javascript +```javascript var nexe = require('nexe'); @@ -131,7 +133,12 @@ nexe.compile({ nodeTempDir: __dirname, flags: true }, 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) diff --git a/bin/nexe b/bin/nexe index 65ed643..e17ea09 100755 --- a/bin/nexe +++ b/bin/nexe @@ -34,6 +34,11 @@ options('f', { options('v', { alias: 'version', description: 'Display version number' +}). +options('p', { + alias: 'python', + description: 'Set path of python to use.', + default: 'python' }); var argv = cli.argv; @@ -54,12 +59,12 @@ function toRelative(pt) { return path.join(process.cwd(), pt); } - -require('../lib').compile({ +require('../lib').compile({ input : require.resolve(toRelative(argv.i)), - output : toRelative(argv.o), + output : toRelative(argv.o), flags : argv.f, - nodeVersion : argv.r, + nodeVersion : argv.r, + python : argv.python, nodeTempDir : toRelative(argv.t) }, function(error) { if(error) console.log(error.message); diff --git a/examples/hello-world/build.js b/examples/hello-world/build.js index 0bd179a..be97c6b 100644 --- a/examples/hello-world/build.js +++ b/examples/hello-world/build.js @@ -3,9 +3,10 @@ var nexe = require('nexe'); nexe.compile( { input: "./index.js", - output: "./helloWorld.exe", + output: "", nodeVersion: "0.10.33", nodeTempDir: "", + python: "C:\\Python27\\python.exe", flags: true, resourceFiles: ["./message.txt"] }, @@ -14,4 +15,4 @@ nexe.compile( console.log(err); } } -); \ No newline at end of file +); diff --git a/lib/exe.js b/lib/exe.js index 47bce75..824aa8a 100644 --- a/lib/exe.js +++ b/lib/exe.js @@ -19,8 +19,10 @@ var _log = require("./log"), _monkeypatch = require("./monkeypatch"); var isWin = /^win/.test(process.platform); +var isPy; /** + * Compiliation process. */ exports.compile = function (options, complete) { @@ -28,11 +30,31 @@ exports.compile = function (options, complete) { var nodeCompiler, nexeEntryPath; 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 */ - function downloadNode (next) { _downloadNode(options.nodeVersion, options.nodeTempDir, next); }, @@ -104,11 +126,16 @@ exports.compile = function (options, complete) { */ function makeExe (next) { - _log("make"); + if(isWin) { + _log("vcbuild [make stage]"); + } else { + _log("make"); + } nodeCompiler.make(next); }, /** + * we create the output directory if needed */ function makeOutputDirectory (next) { @@ -116,11 +143,20 @@ exports.compile = function (options, complete) { }, /** + * Copy the compilied binary to the output specified. */ function copyBinaryToOutput (next) { _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); } @@ -228,7 +264,27 @@ function _getNodeCompiler (nodeFileDir, complete) { version: path.basename(nodeFileDir), releasePath: path.join(dir, "Release", "node.exe"), 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.stderr.pipe(process.stderr); vcbuild.on("close", function() { @@ -242,7 +298,13 @@ function _getNodeCompiler (nodeFileDir, complete) { version: path.basename(nodeFileDir), releasePath: path.join(dir, "out", "Release", "node"), 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.stderr.pipe(process.stderr); configure.on("close", function () { @@ -281,7 +343,7 @@ function _monkeyPatchNodeConfig (compiler, complete) { }, /** - * monkeypatch main entry point + * monkeypatch main entry point */ function (next) { @@ -299,7 +361,7 @@ function _monkeyPatchGyp (compiler, complete) { var gypPath = path.join(compiler.dir, "node.gyp"); _monkeypatch( - gypPath, + gypPath, function (content) { return ~content.indexOf("nexe.js"); }, @@ -317,7 +379,7 @@ function _monkeyPatchMainJs (compiler, complete) { var mainPath = path.join(compiler.dir, "src", "node.js"); _monkeypatch( - mainPath, + mainPath, function (content) { return ~content.indexOf("nexe"); }, @@ -395,9 +457,9 @@ function _logProgress (req) { req.on("response", function (resp) { var len = parseInt(resp.headers["content-length"], 10), - bar = new ProgressBar("[:bar]", { - complete: "=", - incomplete: " ", + bar = new ProgressBar("[:bar]", { + complete: "=", + incomplete: " ", total: len, width: process.stdout.columns - 2 }); @@ -409,4 +471,3 @@ function _logProgress (req) { return req; } - diff --git a/lib/index.js b/lib/index.js index d7c212c..459e3d1 100644 --- a/lib/index.js +++ b/lib/index.js @@ -1,3 +1 @@ module.exports = require("./exe"); - -