PhantomJS require() a relative path - requirejs

In a PhantomJS script I would like to load a custom module but it seems relative paths do not works in PhantomJS ?
script.js:
var foo = require('./script/lib/foo.js');
foo.bar('hello world');
phantom.exit();
foo.js:
exports.bar = function(text){
console.log(text);
}
According to fs.workingDirectory I am in the good directory
foo.js is not in the lookup path of phantomjs
Am I missing something ?
EDIT:
inject() is not revelant because I do not need to inject a JS to an HTML page but instead load my own module like require('fs') but with a relative path.

After a lot of time searching for the same thing, here is what I understood, though I might be wrong :
PhantomJS doesn't use Node's require, but its own require, so things are different
when providing a relative path to phantomjs's require, it is always interpreted as relative to the current working directory
PhantomJS doesn't implement node's __dirname, and as such there is no direct way to have the directory of your script
The solution I found least annoying :
if using phantomjs pure, without casperjs :
require(phantom.libraryPath + '/script/lib/foo.js')
if using casperjs :
var scriptName = fs.absolute( require("system").args[3] );
var scriptDirectory = scriptName.substring(0, scriptName.lastIndexOf('/'));
require(scriptDirectory + '/script/lib/foo.js')

To load your own module, the right way to do it is to use module.exports, like this: foo.js
function bar(text) {
console.log(text);
}
exports.bar = bar
And in script.js (which is executed with phantomjs script.js):
var foo = require('./script/lib/foo');
foo.bar('hello world');
phantom.exit();

My solution to load a resource file (like let's say a json file) within a phantomjs subfolder from a outer folder like in this structure:
├── consumer.js
├── assets
├── data.json
├── loader.js
Supposed that data.json must be load by the consumer module and that this module is called by somewhere else on this machine, outside the project root folder, the fs.workingDirectory will not work, since it will be the path of the caller file.
So to solve this, I did a simple loader module within the assets folder, where the files I want to load are:
(function() {
var loader = {
load : function(fileName) {
var res=require('./'+fileName);
return res;
}
}
module.exports=loader;
}).call(this);
I therefore call the loader module from the consumer module like
var loader=require('./data/loader');
var assets=loader.load('data.json');
and that's it.
NOTE. The require here is the phantomjs require not the node version, so it works a bit differently. In this case the data.json was a json array with no module.exports declaration. The array will be backed in the assets variable directly when calling the loader.load(fileName) method.

have you tried to use injectJs(filename)
excerpt form PhantomJS documentation:
Injects external script code from the specified file. If the file can
not be found in the current directory, libraryPath is used for
additional look up.
This function returns true if injection is successful, otherwise it
returns false.

Which PhantomJS version are you running? Support for user provided modules was added in 1.7.

Related

Why can node not find my module?

I am using node v0.12.5 with nwjs and I have defined my own custom module inside of my project so that I can modularise my project (obviously).
I am trying to call my module from another module in my project but every time I attempt to require it I get the error could not find module 'uploader'.
My uploader module is currently very simple and looks like:
function ping_server(dns, cb) {
require('dns').lookup(dns, function(err) {
if (err && err.code == "ENOTFOUND") {
cb(false);
} else {
cb(true);
}
})
}
function upload_files()
{
}
module.exports.ping_server = ping_server;
module.exports.upload_files = upload_files;
With the idea that it will be used to recursively push files to a requested server if it can be pinged when the test device has internet connection.
I believe I have exported the methods correctly here using the module.exports syntax, I then try to include this module in my test.js file by using:
var uploader = require('uploader');
I also tried
var uploader = require('uploader.js');
But I believe node will automatically look for uploader.js if uploader is specified.
The file hierarchy for my app is as follows:
package.json
public
|-> lib
|-> test.js
|-> uploader.js
|-> css
|-> img
The only thing I am thinking, is that I heard node will try and source the node_modules folder which is to be included at the root directory of the application, could this be what is causing node not to find it? If not, why can node not see my file from test.js given they exist in the same directory?
UPDATE Sorry for the confusion, I have also tried using require('./uploader') and I am still getting the error: Uncaught Error: Cannot find module './uploader'.
UPDATE 2 I am normally completely against using images to convey code problems on SO, but I think this will significantly help the question:
It's clear here that test.js and uploader.js reside in the same location
When you don't pass a path (relative or absolute) to require(), it does a module lookup for the name passed in.
Change your require('uploader') to require('./uploader') or require(__dirname + '/uploader').
To load a local module (ie not one from node_modules) you need to prefix the path with ./. https://nodejs.org/api/modules.html#modules_modules
So in your case it would be var uploader = require('./uploader');
This problem stemmed from using Node Webkit instead of straight Node, as stated in their documentation all modules will be source from a node_modules directory at the root of the project.
Any internal non C++ libraries should be placed in the node_modules directory in order for Node webkit to find them.
Therefore to fix, I simply added a node_modules directory at the root of my project (outside of app and public) and placed the uploader.js file inside of there. Now when I call require('uploader') it works as expected.
If you're developing on a mac, check your file system case sensitivity. It could be that the required filename is capitalized wrong.

Overcome differences in node and browserify path resolving

I'm writing a module for a react app that needs to be included on both the backend and frontend.
At some point in my code, I'm requiring some svg file (for which I use a browserify module, but this has nothing to do with the question).
For example I have in my ./src/js/components/tools/svg.js the following bit of code:
// ...
var BACKEND = /* code to detect if this is running on browser or on node */;
var svg;
if ( BACKEND ) {
svg = require("./../../../icon/" + this.props.icon + ".svg");
} else {
svg = require("./src/icon/" + this.props.icon + ".svg");
}
// ....
I use browserify's require option to require all the svg files at bundle-time:
browserify({
paths: ['./src/icon'],
})
.transform(/* svg tansformer */)
.require(glob.sync("./src/icon/*.svg")) // <-- svg's get added here
.add("./src/main.js"); // main entry point
However this conflicts with how node resolves the filenames. It cannot find ./src/icon/ from ./src/js/components/tools/svg.js.
This is why I have to guard the require with the BACKEN clause. This breaks my eyes though and I would like to just be able to write:
var svg = require('./src/icon/' + this.props.icon + '.svg');
I've tried two things so far:
fix node to find ./src/icon
I can use export NODE_PATH=`cwd` to allow node to look for src/icon from ./. This allows me to write:
var svg = require('src/icon/' + this.props.icon + '.svg');
in the backend. But, since browserify only accepts paths that start with ./ (thus, ignoring src/icon) this will not resolve on the frontend.
fix browserify to use ../../../icon/
Haven't got this to work either because of the same reason: browserify only accepts paths that start with ./.
It's considered bad practice doing conditional requires when using Browserify because it can't evaluate the code at "compile time" and will always attempt to load all the files.
To load different files in the browser environment than on node is easy:
Add a "browser" field to your package.json that points to the browser main file. Use "main" for the node main file. Then just require the module.
You can do the same thing with sub folders within your project. Just add a package.json file with "private": true and both, the main and the browser properties and require the folder path.

r.js from node script?

I feel like this must be so obvious but it's escaping me.
I'd like to run requirejs's r.js compilation from a node module instead of from the command line, and every bit of documentation I've seen just shows the command line option. Something like this is what I'm looking for:
var r = require('requirejs');
r('./build/common.js');
r('./build/app-main.js');
Let me explain the underlying motivation in case there's a better way to do it:
I've got a few different build.js files that I want to run r.js on (separate bundles for common dependencies and the main app). I'd like to wrap this up inside a gulpfile or gruntfile that runs both, and without putting all the r.js config in the actual grunt/gulp file like the grunt and gulp require.js plugins all seem to do. Leaving the r.js config in the separate build/*.js files would let us use grunt/gulp OR command line when we want to.
Any way to accomplish this?
Using the optimizer as a Node module is documented but it is not in the most evident place. This is the example that the documentation gives:
var requirejs = require('requirejs');
var config = {
baseUrl: '../appDir/scripts',
name: 'main',
out: '../build/main-built.js'
};
requirejs.optimize(config, function (buildResponse) {
//buildResponse is just a text output of the modules
//included. Load the built file for the contents.
//Use config.out to get the optimized file contents.
var contents = fs.readFileSync(config.out, 'utf8');
}, function(err) {
//optimization err callback
});

Node.js - "Cannot find module", when the module call other module

I'm developing my first Node.js App. and Everything is find, but Now the app is getting bigger. and I'd like to divide the app into different files. So, I used a "require" method to divide a app into files.
but My App display "Cannot find module".
** Call Ordering **
A.js is call B.js <-- call is ok
B.js is call C.js <-- Cannot Find module, B.js can't call 'test222 function'
My Sample Code.
a.js
...
var m=require('./controller/b.js');
m.register(req,res);
b.js
exports.register=function(){
var MyModule=require('./model/c.js');
console.log(MyModule.test222()); <--------- cannot find module
};
c.js
exports.test222=function() {
return "c.js";
};
Help me or advice. thank you.
I want to Call module in another module. but My Node App is not working for "cannot find module". How to solve it?
It seems that you've mistyped by writing var m=require('./controller/a.js'); instead of var m=require('./controller/b.js');
If so, I can see that you have the following file structure:
./a.js
./controller/b.js
./model/c.js
So you run ./a.js which requires ./controller/b.js and it works fine. But when ./controller/b.js requires ./model/c.js, Node resolves c.js as ./controller/model.js, because each module is relative to the file calling require().
This is why error occurs.
To solve this problem you should replace
var MyModule=require('./model/c.js');
with
var MyModule=require('../model/c.js');
the require function automatically search for modules at the node_modules folder
by just typing the name of the module with the js. extension
var b=require('b.js');
var c=require('c.js');
but if you make changes to the structure of your node_modules folder you need to navigate to your moduleusing the relative waie by taping
"../"
to navigate from a child directory to the parent directory and
"./"
to navigate from the parent directory to the child directory
You need to respect the relative way.

How to use Gulp to create a separate vendor bundle with Browserify from Bower components

I'm using Gulp and Browserify to package my Javascript into 2 separate bundles: application.js and vendor.js.
How do I bundle the vendor package if my vendor libraries are installed with Bower?
In my gulpfile, I'm using the following modules:
var gulp = require("gulp");
var browserify = require("browserify");
var debowerify = require("debowerify");
var source = require("vinyl-source-stream");
Assuming that I have only the Phaser framework installed with bower (for this example), my Gulp task to create the application package looks like this:
gulp.task("scripts-app", function () {
browserify("./app/javascripts/index.js")
.external("phaser")
.pipe(source("application.js"))
.pipe(gulp.dest("./tmp/assets"));
});
Meanwhile, the vendor task looks like this:
gulp.task("scripts-vendor", function () {
browserify()
.transform(debowerify)
.require("phaser")
.pipe(source("vendor.js"))
.pipe(gulp.dest("./tmp/assets"));
});
When I run this Gulp task, I get an error that states Error: Cannot find module 'phaser' from and then all the directories it search through (none of which are the bower_components directory).
Any ideas about how to package these up successfully are greatly appreciated. Thanks!
Answered my own question:
When using require in the Gulp task, you need to supply a path to a file, not just a name.
gulp.task("scripts-vendor", function () {
browserify()
.transform(debowerify)
.require("./bower_components/phaser/phaser.js")
.pipe(source("vendor.js"))
.pipe(gulp.dest("./tmp/assets"));
});
Notice that require("phaser") became require("./bower_components/phaser/phaser.js").
Doing this works, although the bundle takes forever to build (around 20 seconds). You're probably better of just loading giant libraries/frameworks directly into your app through a <script> tag and then using Browserify Shim.
This let's you require() (in the NodeJS/Browserify sense) global variables (documentation).
Seems like you figured out how to require the bower file. Hopefully you'll only have to bundle it once initially, and not every build. Including the library via a script tag isn't a bad idea. Another technique I'm using is to use scriptjs (a polyfill would work too), to async load whatever vender libraries I need, but make sure to include any/all require's after the script loads. For example, your index.js could be like:
$script.('/assets/vendor', function() {
var phaser = require('phaser');
//rest of code
});
It's especially nice for loading cdn files or having the ability to defer loading certain libraries that aren't necessarily used in the core app by every user, or loading libraries after client-side routing.

Resources