Working with PhantomJS in node is a bit cumbersome since you need to spawn a new PhantomJS process for every single task. However, spawning a new process is quite expensive and thus can slow down your application significantly.

phridge provides an api to easily

spawn new PhantomJS processes

run functions with arguments inside PhantomJS

return results from PhantomJS to node

manage long-running PhantomJS instances

Unlike other node-PhantomJS bridges phridge provides a way to run code directly inside PhantomJS instead of turning every call and assignment into an async operation.

phridge uses PhantomJS' stdin and stdout for inter-process communication. It stringifies the given function, passes it to PhantomJS via stdin, executes it in the PhantomJS environment and passes back the results via stdout. Thus you can write your PhantomJS scripts inside your node modules in a clean and synchronous way.

Please note that the phantom-object provided by phridge is completely different to the phantom-object inside PhantomJS. So is the page-object. Check out the api for further information.

Since communication via stdin/stdout is always asynchronous phridge returns promises most of the time. It uses when.js which is Promises/A+ compliant, so using your favorite promise library should be no problem.

Since the function passed to phantom.run() can't declare variables in the global scope, it is impossible to maintain state in PhantomJS. That's why phantom.run() calls all functions on the same context object. Thus you can easily store state variables.

phantom.run(function(){

this.message ="Hello from the first call";

}).then(function(){

phantom.run(function(){

console.log(this.message);// 'Hello from the first call'

});

});

For further convenience all PhantomJS modules are already available in the global scope.

Most of the time its more useful to work in a specific webpage context. This is done by creating a Page via phantom.createPage() which calls internally require("webpage").create(). The returned page wrapper will then execute all functions bound to a PhantomJS webpage instance.

var page = phantom.createPage();

page.run(function(resolve, reject){

// `this` is now a webpage instance

this.open("http://example.com",function(status){

if(status !=="success"){

return reject(newError("Cannot load "+this.url));

}

resolve();

});

});

And for the busy ones: You can just call phantom.openPage(url) which is basically the same as above:

which will terminate the process cleanly by calling phantom.exit(0) internally. You don't need to dispose all pages manuallly when you call phantom.dispose().

However, calling

phridge.disposeAll().then(function(){

console.log("All processes created by phridge.spawn() have been terminated");

});

will terminate all processes.

I strongly recommend to callphridge.disposeAll()when the node process exits as this is the only way to ensure that all child processes terminate as well. Since disposeAll() is async it is not safe to call it on process.on("exit"). It is better to call it on SIGINT, SIGTERM and within your regular exit flow.

Spawns a new PhantomJS process with the given config. Read the PhantomJS documentation for all available config options. Use camelCase style for option names. The promise will be fulfilled with an instance of Phantom.

Phantom (instance)

.childProcess.cleanStdout: ReadableStream

phridge extends the ChildProcess-instance by a new stream called cleanStdout. This stream is piped to process.stdout by default. It provides all data not dedicated to phridge. Streaming data is considered to be dedicated to phridge when the new line is preceded by the classifier string "message to node: ".

.run(args..., fn): Promise → *

Stringifies fn, sends it to PhantomJS and executes it there again. args... are stringified using JSON.stringify() and passed to fn again. fn may simply return a result or throw an error or call resolve() or reject() respectively if it is asynchronous. phridge compares fn.length with the given number of arguments to determine whether fn is sync or async. The returned promise will be resolved with the result or rejected with the error.

From opening a bug report to creating a pull request: every contribution is appreciated and welcome. If you're planing to implement a new feature or change the api please create an issue first. This way we can ensure that your precious work is not in vain.

All pull requests should have 100% test coverage (with notable exceptions) and need to pass all tests.