Odd behavior of fs.readdirSync - javascript

I use nodejs 5.5.0, and pm2 1.0.1. I run the script with:
npm start
And in package.json, it is defined as:
"scripts": {
"start": "pm2 start bin/www --watch"
},
I have this simple script that returns a list of videos and it works:
var express = require('express');
var router = express.Router();
router.get('/', function(req, res, next) {
const fs = require('fs');
shows = fs.readdirSync(`public/videos`);
res.render('index', shows);
});
module.exports = router;
But I observed something interesting... If I make the below modification, it no longer works, and returns an empty list:
//shows = fs.readdirSync(`public/videos`);
res.render('index', fs.readdirSync(`public/videos`));
To make it more interesting, the following works:
shows = fs.readdirSync(`public/videos`);
res.render('index', fs.readdirSync(`public/videos`));
It almost seems to me, if there is some sort of delay or caching, fs.readdirSync works fine, but not if it is called straight on the same line.
Did I miss something simple?

Somebody correct me if I'm wrong..
But I believe it is because res.render has a third argument that you don't see which is callback noted here
So when you create the variable in your first example, you block until you get the variable, and then your render the template with the variables available at run time.
But in your second example, you're passing in that option, but res.render's callback is calling before readdirSync can finish populating.

I figured it out and it was actually something really simple that I missed. The name of the local variable is significant.
In case 3, although shows is not explicitly passed in, it is actually visible to the page being rendered using swig.
If I do not want to introduce the variable shows, I could have done the following and it works:
res.render('index', {shows: fs.readdirSync('public/videos')});

Related

Expressjs middleware keeps variable changed

I am trying to do a simple thing which is obvious I believe in the code below:
module.exports = function(req, res, next) {
var dop = require('../../config/config').DefaultOptions;
console.log(require('../../config/config').DefaultOptions);
console.log(dop);
dop.firstPage = 'test.sjs';
next();
};
This is an Expressjs middle ware which is very simple but the interesting point is that next time I load a page both of the console.log results has been changed to 'firstPage: test.sjs'. It shouldn't act like this and it should only change the dop variable.
Anyone with the knowledge why this creepy thing is happening?
Thank you
The main issue is require() is cached, so require('../../config/config') returns reference to the same instance, and as a result changing in one place causes all other references and subsequent requires to get that modified instance.
The simplest solution would be have a function in config to return a config object, that way every time invoking the get config function you will get a new instance with essentially the same content. I.e.:
config.js:
module.exports = {
getDefaultOptions: function(){
return {foo: 'bar', ip: '1.1.1.1'}
}
};

Difference between require('module')() and const mod = require('module') mod() in node/express

I have two files: server.js and db.js
server.js looks as such:
...
const app = express();
app.use('/db', db());
app.listen(3000, () => {
console.log('Server started on port 3000')
});
...
and db.js as such:
...
function init() {
const db = require('express-pouchdb')(PouchDB, {
mode: 'minimumForPouchDB'
});
return db;
}
...
This works just fine, and I am able to reach the pouchdb http-api from my frontend. But before, I had const PouchDBExpress = require('pouchdb-express'); in the top of db.js, and the first line in init() looked like this; const db = PouchDBExpress(PouchDB, {. This gave an error in one of the internal files in pouchdb saying cannot set property query on req which only has getters (paraphrasing).
So this made me copy the exaples from pouchdb-servers GitHub examples which requires and invokes pouched-express directly, and everthing worked fine. Is there an explanation for this? I'm glad it works now, but I'm sort of confused as to what could cause this.
The only difference between:
require('module')()
and
const mod = require('module');
mod();
is that in the second case, you retain a reference to the module exports object (perhaps for other uses) whereas in the first one you do not.
Both cases load the module and then call the exported object as a function. But, if the module export has other properties or other methods that you need access to then, obviously, you need to retain a reference to it as in the second option.
For us to comment in more detail about the code scenario that you said did not work, you will have to show us that exact code scenario. Describing what is different in words rather than showing the actual code makes it too hard to follow and impossible to spot anything else you may have inadvertently done wrong to cause your problem.
In require('module')(), you don't retain a reference of the module imported.
While in const mod = require('module'); mod(), you retain a reference and can use the same reference later in your code.
This problem might be due to some other reason like -
Are you using a some another global instance of the db, and your code works in the given case as you are making a local instance
Some other code dependent scenario.
Please provide more details for the same

In Node.js, asking for a value using Prompt, and using that value in a main js file

I'm pretty new to node.js and it seems fairly easy to use but when it comes to getting a value using the command line and returning that value to be used in another package or .js, it seems harder than I expected.
Long story short, I've used a npm package (akamai-ccu-purge), to enter a file to purge on the akamai network successfully.
I want to make it more dynamic though by prompting the user to enter the file they want purged and then using that in the akamai package.
After making a few tries using var stdin = process.openStdin(); I actually found another npm package called Prompt that seemed to be easier. Both ways seem to have the same problem though.
Node doesn't seem to want to stop for the input. It seems to want to automatically make the purge without waiting for input even though I've called that module first. It actually gets to the point where I should enter the file but it doesn't wait.
I am definitely missing something in my understanding or usage here, what am I doing wrong?
My code so far is:
var purgeUrl = require('./getUrl2');
var PurgerFactory = require('../../node_modules/akamai-ccu-purge/index'); // this is the directory where the index.js of the node module was installed
// area where I placed the authentication tokens
var config = {
clientToken: //my tokens and secrets akamai requires
};
// area where urls are placed. More than one can be listed with comma separated values
var objects = [
purgeUrl // I am trying to pull this from the getUrl2 module
];
// Go for it!
var Purger = PurgerFactory.create(config);
Purger.purgeObjects(objects, function(err, res) {
console.log('------------------------');
console.log('Purge Result:', res.body);
console.log('------------------------');
Purger.checkPurgeStatus(res.body.progressUri, function(err, res) {
console.log('Purge Status', res.body);
console.log('------------------------');
Purger.checkQueueLength(function(err, res) {
console.log('Queue Length', res.body);
console.log('------------------------');
});
});
});
The getUrl2 module looks like this:
var prompt = require('../../node_modules/prompt');
//
// Start the prompt
//
prompt.start();
//
// Get property from the user
//
prompt.get(['newUrl'], function (err, result) {
//
// Log the results.
//
console.log('Command-line input received:');
console.log(' http://example.com/custom/' + result.newUrl);
var purgeUrl = 'http://example.com/custom/' + result.newUrl;
console.log(purgeUrl);
module.exports = purgeUrl;
});
Thanks again for the help!
I would probably just allow getURL2 to expose a method that will be invoked in the main module. For example:
// getURL2
var prompt = require('../../node_modules/prompt');
module.exports = {
start: function(callback) {
prompt.start();
prompt.get(['newUrl'], function (err, result) {
// the callback is defined in your main module
return callback('http://example.com/custom/' + result.newUrl);
});
}
}
Then in your main module:
require('./getUrl2').start(function(purgeURL) {
// do stuff with the purgeURL defined in the other module
});
The implementation may differ, but conceptually, you need to make your second module, which requires some sort of input from the user, happen as a result of that input. Callbacks are a common way to do this (as are Promises). However, as prompt is not necessarily exposing a method that would necessitate a Promise, you can do it with plain old callbacks.
You might also want to search around for articles on writing command line tools (sometimes referenced as CLIs) or command line apps with Node. I found the following article to be helpful when trying to figure this out myself:
http://javascriptplayground.com/blog/2015/03/node-command-line-tool/
Also, the command-line-args module worked well for me (though there's a number of other modules out there to choose from):
https://www.npmjs.com/package/command-line-args
Good luck!

Better middleware chaining in Express

This is my Express configuration code:
var server = express()
.use(express.cookieParser())
.use(express.session({secret: buffer.toString('hex')}))
.use(express.bodyParser())
.use(express.static('./../'));
server.use(server.router);
It's quite annoying that the last .use is not chained like the rest.
How can I do full chaining of my Express middleware definitions?
The express use implementation returns this every time and is thus always chainable. The chainability problem comes from your unnecessary use of server.use(server.router), which is automatically done for you by express when your first non-middleware route is added via server.get, server.post, etc. This can can be seen in the express source code here, although this is a common point of confusion and problems (most of which come from doing server.user(server.router) at all as opposed to just letting the router go where it goes by default, which is almost always the correct place for it. So here's the forumla:
Properly ordered server.use calls to set up your middleware
Your specific routes with server.get('/home') and the other HTTP method functions
Any error handling, 404 middleware, etc
Express will add the router after 1 but before 2, and all will be well.
In the comments you claim if you omit the server.router line, you lose access to req.session. Sorry, but this is simply not the case. Here's an entire working express app that shows a middleware immediately before the session middleware having req.session undefined, and another one immediately after the session middleware having it exist.
var express = require('express');
var server = express();
server.use(function (q,r,n) {console.log('Before cookie:', q.session);n();});
server.use(express.cookieParser());
server.use(function (q,r,n) {console.log('after cookie:', q.session);n();});
server.use(express.session({secret: 'SEKRET'}));
server.use(function (q,r,n) {console.log('after session:', q.session);n();});
server.get('/', function (q,r,n) {r.send("you got slashed");});
server.listen(3000);
Run it and you see this on the console.
Before cookie: undefined
after cookie: undefined
after session: { cookie:
{ path: '/',
_expires: null,
originalMaxAge: null,
httpOnly: true } }
However, if you are asking why you can't use the server variable as a function parameter in the same statement in which it is defined, that's just how JavaScript works and has zero to do with express. You can't do this:
var foo = console.log(foo.bar);
Because foo is undefined until that entire statement is complete.
FWIW my opinion is that chainable code like this is dubious. It is unfriendly to debuggers and breakpoints, not supported as a first-class language feature, and isn't really saving you any characters compared to each line being unindented and app.use(app.router), but so be it.

javascript objects confusion [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
What is the purpose of NodeJS module.exports and how do you use it?
I have the following code:
var express = require('express');
var app = module.exports= express();
require('./config/environment.js')(app, express, __dirname);
require('./routes/default.js')(app, __dirname);
module.exports = function (app, express, dirname) {
....
};
module.exports = function (app, dirname) {
....
};
what happened in this code. Second string says, that module.exports and app are the same object, right?
but in function(...) parts app pass as parameter and that code likes on "to object 'module' add method 'exports' and do it 2 times" I want to add some functions, which want to use inside each function (...), but can't because don't understand what happens in that constructions.
Thanks
Why are you assigning module.exports three times? In your code module.exports will first become equal to what ever is returned by calling express. Then module.exports will become equal to your function (NOT what it returns) and will take 3 arguments. Then module.exports will be equal to your final function (again NOT what it returns) taking 2 arguments. Therefore by the end of your code module.exports will be equal to that final function. So I don't see what the need is for the first two assignments. App will be equal to module.exports at the end because app is pointing to module.exports the whole time. It doesn't matter that you want app to be passed as an argument to it because no where in the code above do you actually pass app into the function, after assigning the functions to module.exports. All you have done here is name a parameter "app".
I think you have either missed code out here or got very confused by other languages you may have used in the past.
Lookup Douglas Crockford if the language isn't clear to you.
I hope that helps.

Categories

Resources