Node.js Getting undefined property when using require in other module - javascript

This is how my app.js looks
var app = require('http').createServer(handler),
io = require('socket.io').listen(app),
static = require('node-static'); // for serving files
var game = require('./game.js').createGame();
// This will make all the files in the current folder
// accessible from the web
var fileServer = new static.Server('./');
// This is the port for our web server.
// you will need to go to http://localhost:8080 to see it
app.listen(8080);
// Listen for incoming connections from clients
io.sockets.on('connection', function (socket) {
handle Events ...
});
exports.io = io;
exports.game = game;
when I try to access the created socket.io listner or the game instance I get error saying its undefined.
This how I am trying to access it in trick,js
var game = require('./app.js').game;
var socketio = require('./app.js').io;
var PlayerMove = require('./playerMove.js');
This might be because trick.js is actually executed before app.js (I put debug points and it was confirmed there). How do I avoid this? Is there a better way of exposing object instances in node.js, some pattern that i should probably use ?

declaring a variable does not export it. If you need to export something for your module, you should use exports.myVariable = myValue.
requiring your app.js file for the first time will run it. So everything you export in it will be available once you're out of the require() call

Related

import class from file gives unexpedted string error

I'm trying to make a very simple server script for a game using sockets.
I basically have a server.js that uses express and socket.io to accept a connection and serve whatever is in public folder.
let express = require("express");
let app = express();
app.use(express.static("public"));
let server = app.listen(3000);
let socket = require("socket.io");
let io = socket(server);
io.sockets.on("connection", newConnection);
function newConnection(socket) {
console.log("New connection: " + socket.id);
}
This is a basic script that accepts connections from a client and just prints when a client has connected.
I already did a npm init, installed express and socket.io and I run it using npm start and it works correctly.
Now, I have build a class Game in a file Game.js and when a client connects I just want to instantiate the game.
Something like:
function newConnection(socket) {
console.log("New connection: " + socket.id);
let game = new Game();
}
The problem is that I don't know how to import Game.
I tried using import, but apparently I'm not using the right syntax:
import "game.js"
import "game.js"
^^^^^^^^^
SyntaxError: Unexpected string
I just want inside my server.js to use a class that I implemented in a file that is in the same folder. How can I do this?
When using node, you don't use the "import" keyword but rather "require" (Like you already did with express and socket.io in your server.js).
This would look something like:
let game = require("game.js");
Don't forget to export the needed functions inside your game.js.
exports.newConnection = function(socket) {
console.log("New connection: " + socket.id);
let game = new Game();
}
This way, you can call your newConnection function from inside the server.js by typing:
io.sockets.on("connection", game.newConnection);
If you only need one function from inside a class, you can also just "require" a single function by explicitly stating this function, like:
let gameconnection = require("game.js").newConnection;
and then calling it with:
io.sockets.on("connection", gameconnection);

How do I start js app from another js app?

I have to execute an ansync function before execute an express server, because I'm going to get a aparameter to pass it to the API. So I guess I can call the async funcion and on the promise I will get, call my express server (until now I have exectued it with "node my_server.js")
How can I do that? How can I call my_server.js on my new js ?
Usually the server does not get created while merely running node server.js. It will just execute javascript contained in server.js. The server will be created when your code reaches express() if you are creating server via express or createServer from plain nodejs.
That means you can probably do
var param = await someSync();
// Set the param in global context and then create your server
var app = express();
// or
var app = createHttpServer()
So now before your app starts you will have that param and you can use it in your api
If you are using promise instead of async, just create your server in then part of your promise, this will also make sure that your app will have that param before your server starts
You can fork a new process using the child_process module in node.
const { fork } = require('child_process')
const path = require('path')
const newProcess = fork(path.join(__dirname, 'path/to/jsfile'), [...otherArgs])

Require (the same instance of) socket.io in multiple modules

I am a bit confused, about how to require and use modules in Node.js.
My scenario is the following:
I wrote a complete server in one single file, which uses Socket.io for realtime communication.
Now the index.js became pretty big, and I want to split the code into several modules to make it more managable.
For example I have some functions for serving a Survey to the clients, and getting back their answers. I put all those functions in a seperate module, and require it in the index.js. Works fine so far.
The only thing I am concerned about is, if there is another way to use the SAME socket instance inside the module.
My current coding looks like this:
index.js:
var express = require('express');
var app = express();
var server = require('http').createServer(app);
var io = require('socket.io')(server);
var Survey = require('./survey');
io.on('connection', function (client) {
client.on('getCurrentQuestion', function (data) {
Survey.getCurrentQuestion(parseInt(data.survey_id), client.id);
});
});
server.listen(port, server_url, function () {
Survey.init(io);
});
survey.js:
var io = null;
var Survey = {};
Survey.init = function(socketio) {
io = socketio;
};
Survey.getCurrentQuestion = function(survey_id, socket_id) {
var response = {
status: "unknown",
survey_id: survey_id
};
// [...] some code that processes everything
// then uses Socket.io to push something back to the client
io.sockets.in(socket_id).emit('getCurrentQuestion', response);
};
module.exports = Survey;
This way it works, but I'm not happy passing io inside an init function to the required module.
What would be "the right way" to do this?
If I require('socket.io') inside the survey module, will it be the same instance as in index.js?
How would I even require that, since it needs the server, which needs the app, which is created in index.js?
I am confused and hope that somebody can help me. Thanks!
When you import a node.JS library you can also pass in objects. In your case the index.js file should be changed to the following:
//index.js
var express = require('express');
var app = express();
var server = require('http').createServer(app);
var io = require('socket.io')(server);
var Survey = require('./survey')(io);
Then just change your survey.js code to take the io object:
//survey.js
module.exports = function (io) {
var Survey = {};
Survey.getCurrentQuestion = function(survey_id, socket_id) {
var response = {
status: "unknown",
survey_id: survey_id
};
// [...] some code that processes everything
// then uses Socket.io to push something back to the client
io.sockets.in(socket_id).emit('getCurrentQuestion', response);
};
return Survey;
};
To answer your other question:
If you require('socket.io') inside the survey module, it will be a different instance from index.js.
EDIT
If you want a more modern way of doing it...You could use ES6 format and create a class to do this better:
'ES6 index.js
import SurveyClass from './Survey';
import * as express from 'express';
let app = express();
let server = require('http').createServer(app);
let io = require('socket.io')(server);
let MySurveyClass= SurveyClass(io);
let myInstance = new MySurveyClass();
myInstance.getCurrentQuestion(5, "some-socket-id");
'ES6 survey.js
export default class Survey{
constructor(io){
this.io= io;
};
getCurrentQuestion(survey_id, socket_id) {
var response = {
status: "unknown",
survey_id: survey_id
};
// [...] some code that processes everything
// then uses Socket.io to push something back to the client
this.io.sockets.in(socket_id).emit('getCurrentQuestion', response);
};
}
When you do this in multiple modules:
var socketio = require('socket.io');
then it will be the same object for all requires.
But if you do this:
var io = require('socket.io')(server);
even if you have the same object in server in both places, io would be a different value because it would come from different invocations of the function returned by require('socket.io') even though those functions would be the same.
If you want to make sure that the io is the same then you'd have do e.g. something like this: Make a module that exports a promise of io and some way to initialize it - a function that gets the server and everything needed. Now, in the place where you have the server you can require the module and initialize it with that exported function, and in other places you can import the module and use a promise.
Instead of a promise you could use callbacks or even just a property on the exported object that could be initially undefined and gets defined when the socket.io is initialized but using a promise would probably be most simple solution to make sure that you're not using it while it's not ready yet.
You didn't mention in your question whether or not you use some framework and which one if any, but some of the frameworks like Hapi give you an easy way to share functionality like that. E.g. see:
https://hapijs.com/tutorials/plugins
If you use Hapi then you should use plugins. If other framework then search for a similar feature.

How do you set and retrieve an instance of BookshelfJS using Express?

I'm trying to use Bookshelf along with Express 4.0 and can't seem to get them working together or rather, I can't seem to follow "best practices". The Bookshelf docs mention that one should always reuse the same instance of it throughout the app. It even lists an example:
// When the app starts
var app = express();
var knex = require('knex')(dbConfig);
var bookshelf = require('bookshelf')(knex);
app.set('bookshelf', bookshelf);
// elsewhere, to use the bookshelf client:
var bookshelf = app.get('bookshelf');
var Post = bookshelf.Model.extend({
// ...
});
However, I can't seem to get it working when I have to use app.get() in a separate file. For example, here's my app.js file (the root of my entire app):
var express = require('express');
var app = express();
var db = require('./server/db/db');
app.set('bookshelf', db);
var api = require('./server');
app.use(api);
Here's my db.js file that gets required above:
var express = require('express');
var app = express();
var knex = require('knex')({ //my db settings go here });
var bookshelf = require('bookshelf')(knex);
module.exports = bookshelf;
The above code works if I require it directly. Here's where the issue turns up. Whenever I want to actually use the bookshelf connection, no matter what file I'm in, I follow the same process but it fails and "bookshelf" is always undefined. Here's an example of an index.js file that's required and called "api" in the app.js:
var express = require('express');
var app = express();
var db = app.get('bookshelf');
console.log(db);
DB always comes up as undefined. Whenever I try to make a new Model, I use the same process except I do an db.Model.extend({}) and trying to access the Model property throws an error (because it's undefined).
From what I can use both Bookshelf and Express docs agree that this should work and it doesn't. Any ideas?
This line creates a new app every time you call it:
var myApp = express();
If you want to set or get variables from the same app, you'll have to pass it as an argument.
var api = require('./server')(myApp);
And then in your api module:
module.exports = function(app){
var db = app.get('bookshelf');
//....
};
On a side note: you don't have to worry about singletons in Node.js all you have to do is just require it.
var db = require('./path/to/db/config');
It'll only be instantiated once and cached for later calls.

Node.js module export

How can I export these variables so I can later use them on different js files?
The following example works well with just 1 variable
var app = module.exports = express();
But I want to pass more variables so I did this
var app = express();
var connection = mysql.createConnection({
host : 'localhost',
user : 'root',
password : ''
});
module.exports.app = app;
module.exports.connection = connection;
with no success
This is because on the first, your module is the app. I mean that if you have B like that in the first case:
app = require('A') // = express()
whereas on the second time it is :
app = require('A') // = {app: express(), connection: connection}
The answer is in the Node.js Modules documentation:
You either assign the value that you want to export to the module.exports property, or you assign an object to it.
mymodule.js:
var app = module.exports = express();
Or:
var app = express();
module.exports = {
"app": app,
"otherproperties": "you want to export"
}
To require a module that you made yourself and didn't place node_modules directory, you can either supply an absolute path or a relative path.
Calling module:
var app = require("/home/user/myapp/mymodule.js"); // absolute path
app; // access returned value of express() function, created in *mymodule.js*
Or:
var app = require("./mymodule.js"); // path relative to the calling module
// In this case the calling module is in the same directory as *mymodule.js*
app.app; // access returned value of express() function, created in *mymodule.js*
Addendum: Even though the modules library/module has been locked, I really recommend reading the documentation. It's very much possible to read the entire documentation in two evenings while looking up network terminology that you're not familiar with. It'll save you a lot of time in the short term!

Categories