how can add a new view / route into express? - node.js

I'm new at this, I'm trying to absorb as much as possible.
I am using this template https://github.com/primaryobjects/Node.js-Bootstrap-Starter-Template
Okay, all right till here, but when I try to add a new page, it returns me the following error:
C:\server\node_modules\express\lib\router\route.js:196
throw new Error(msg);
^
Error: Route.get() requires callback functions but got a [object Undefined]
at Route.(anonymous function) [as get] (C:\server\node_modules\express\lib\r
outer\route.js:196:15)
at EventEmitter.app.(anonymous function) (C:\server\node_modules\express\lib
\application.js:481:19)
at Object.<anonymous> (C:\server\app.js:31:5)
at Module._compile (module.js:460:26)
at Object.Module._extensions..js (module.js:478:10)
at Module.load (module.js:355:32)
at Function.Module._load (module.js:310:12)
at Function.Module.runMain (module.js:501:10)
at startup (node.js:129:16)
at node.js:814:3
The aim would be to answer me a new page at the following address:
http://localhost:3000/ask?america=
The steps I followed were:
Create a view and a path
/views/ask.jade
extends layout
block content
div.container
h1 ASK
2n
/routes/ask.js
exports.ask= function(req, res){
res.render('ask');
};
3r
app.js
app.get('/ask', routes.ask);
But when I try to start "node app" returns me the error mentioned above.
Where am I mistaken?

Have you tried requiring specifically your routes/ask.js file? I'm pretty certain when using
require('folder')
require looks directly for an index file and uses that index file which I believe may mean that your routes/ask.js file might actually not be getting "required" by the app.
So
var askRoutes = require('./routes/ask')
...
...
app.get('/', routes),
app.get('/ask', askRoutes)
To modularize your code you could utilize your routes/index.js file as a routes module load file, where you load your route modules (like routes/ask.js) into your index file so you won't get bogged down by having a ton of required route modules in your app.js file. Just the index.js file would be required.

Can you try the followings :
use the default route first : app.get('/', routes.index); and then put your code after app.get('/ask', routes.ask);
if it doesn't work, put instead of res.render('ask'); the minimal return res.send('some json');

Related

Expressjs change context where the server executes the app from

I'd like to know if it's possible to change the context from where the Express server is serving from, to avoid issues in the import/require files in the App that is served.
I'm serving from [root]/server.js, this file checks for the process.env.NODE_ENV and then requires a file in let's say ./dist/ENVIRONMENT/server.js
if (['staging', 'production'].indexOf(process.env.NODE_ENV) > -1) {
require('./dist/' + process.env.NODE_ENV + '/server.js')
} else {
require('babel-register')
require('./server.dev.js')
}
The files that are served are triggering an error related with the import/require locations that fails for the reason explained in the previous paragraph
Error: Cannot find module '../../../../xxxxx'
Why am I doing this? I'm transpiling the server source code for non development (that runs with babel) and then copied to the distribution directory. I understand that I can have tasks to rename and move this accordingly during deployment, that also solves the problem, but I'd like to learn or understand if we're able to change the context where the Express server, serves from!
From the top of my head, I guess I'll have to solve it through something like (which I'll be testing):
var dist = path.resolve(__dirname, '../../')
app.use(express.static(dist))
Which I attempted, but failed, same error:
Error: Cannot find module '../../../../config'
at Function.Module._resolveFilename (module.js:485:15)
at Function.Module._load (module.js:437:25)
at Module.require (module.js:513:17)
at require (internal/module.js:11:18)
at Object.<anonymous> (/Users/xxxx/www/projectFoobar/dist/staging/lib/services/foobarService/index.js:13:15)
at Module._compile (module.js:569:30)
at Object.Module._extensions..js (module.js:580:10)
at Module.load (module.js:503:32)
at tryModuleLoad (module.js:466:12)
at Function.Module._load (module.js:458:3)
The config file happens to be in the [root] directory.
** OK just realised that using import/export is a bad practice
https://nodesource.com/blog/es-modules-and-node-js-hard-choices/

How can I fix this node.js path issue?

I'm in the process of refactoring my server.js file and trying to incorporate MVC pattern. I'm running into a problem trying to access my controller from my routes.js. I've tried just about every variation of absolute and relative path that I can think but I must be missing something.
Here is my directory structure:
And from my routes.js, here is my code:
module.exports = function ( app, passport, auth ) {
var Clients = require('controllers/clients');
app.get('/clients', Clients.list);
}
I don't think this is relevant, but here is my clients controller:
var mongoose = require('mongoose')
, Client = mongoose.model('Client');
exports.list = function( req, res ) {
Client.find( function( err, clients ) {
res.renderPjax('clients/list', { clients: clients, user: req.user });
});
}
Here is the error that I'm getting when trying to access my controller from routes:
module.js:340
throw err;
^
Error: Cannot find module 'controllers/clients'
at Function.Module._resolveFilename (module.js:338:15)
at Function.Module._load (module.js:280:25)
at Module.require (module.js:364:17)
at require (module.js:380:17)
at module.exports (/Users/sm/Desktop/express3-mongoose-rememberme/app/routes.js:5:16)
at Object.<anonymous> (/Users/sm/Desktop/express3-mongoose-rememberme/server.js:334:24)
at Module._compile (module.js:456:26)
at Object.Module._extensions..js (module.js:474:10)
at Module.load (module.js:356:32)
at Function.Module._load (module.js:312:12)
I'm sure it's something simple that I'm over looking. How can I access my controller from
my routes?
To require something that isn't a separate package (isn't in node_modules), you need to use an explicitly relative path:
require('./controllers/clients')
For more information, see the documentation.
Local Modules
require(...) takes a relative path for local modules
require('./controllers/clients')
Installaed modules
For modules installed via npm install -S foo, use the syntax
require('foo')

Node.js TypeError: object is not a function

I'm trying to run Mike Wilson's book sample app, but receiving the following error:
pcassiano#...:~/socialnet$ sudo node app.js
/home/pcassiano/socialnet/app.js:60
require('./routes/' + routeName)(app, models);
^
TypeError: object is not a function
at /home/pcassiano/socialnet/app.js:60:35
at Array.forEach (native)
at Object.<anonymous> (/home/pcassiano/socialnet/app.js:57:26)
at Module._compile (module.js:449:26)
at Object.Module._extensions..js (module.js:467:10)
at Module.load (module.js:356:32)
at Function.Module._load (module.js:312:12)
at Module.runMain (module.js:492:10)
at process.startup.processNextTick.process._tickCallback (node.js:244:9)
i'm running the latest code from the book's repo.
what should i do in order to run this sample app properly?
thanks in advance.
You likely have .js files in the routes directory that do not export a function.
app.js is calling require on all files in the routes directory and then calling them as a function. So if any of those files do not follow the general pattern below you'll get the error you're seeing:
module.exports = function(app, models) {
// Add this file's routes using app.get, etc. calls.
...
};
The error reports that the value of require('./routes/' + routeName) is not a function. So you have only one real possible source of the problem.
If './routes/'+routeName doesn't exist, node should throw an error (in v0.8.16 at least), so that isn't it. So the most obvious one is that the module being loaded doesn't export a function (as the error suggests).
You should run console.log('routeName: ', routeName) right before the require statement that is on line 60 of app.js and try running it again. Then, after finding the value of routeName, look in the file it's trying to open. Odds are either module.exports is either exporting an object (or an array, string etc), or is not set at all.
If you're adding routes in the routes folder, take care to follow the same exporting style as the author, namely module.exports = function(app, models) {...}

Dynamically generate Express routes fails in production environment

I've seen a lot of folks dynaimcally generating all their routes in the thier routes/index.js like so:
require("fs").readdirSync("./routes", 'utf8').forEach(function(file) {
if (file != 'index.js' && file != '.DS_Store') {
require("./"+file);
}
});
This works fine in development but not in production. If I remove this and add the routes manually it works fine. Any Ideas?
Here's my error if you think that would help:
node.js:134
throw e; // process.nextTick error, or 'error' event on first tick
Error: ENOENT, No such file or directory './routes'
at Object.readdirSync (fs.js:376:18)
at Object.<anonymous> (/app/routes/index.js:4:15)
at Module._compile (module.js:402:26)
at Object..js (module.js:408:10)
at Module.load (module.js:334:31)
at Function._load (module.js:293:12)
at require (module.js:346:19)
at Object.<anonymous> (/app/server.js:50:14)
at Module._compile (module.js:402:26)
at Object..js (module.js:408:10)
Process died with exit code 1. Restarting...
As Mark Bessey says in his answer, you are resolving the routes directory from your current directory -- not relative to where your main script lives. You should probably use __dirname. From the docs:
The name of the directory that the currently executing script resides in.
fs.readdirSync(path.join(__dirname, "routes"))
Also, you don't need to pass 'utf8'. Also, be very careful using any Sync functions in your code -- generally, it's ok in the top level scope, before the server starts accepting requests, so it should be ok in this case.
It seems likely that in production, the current directory is not getting set to the parent of your "routes" directory. How are you launching your app in production? What output do you get from
console.log(process.cwd());

flatironjs and Cloud9; window is undefined error?

Anyone else having luck using flatironjs with the Cloud9 ide?
In my server.js file I have:
require("coffee-script");
var app = require("./app");
app.listen(process.env.PORT);
Then in my app.coffee file I have:
flatiron = require "flatiron"
director = require "director"
app = flatiron.app
app.use flatiron.plugins.http
module.exports = app.router.get "/", ->
res.writeHead 200, { "Content-Type": "text/plain" }
res.end "Hello world!\n"
When I attempt to run this in the Cloud9 IDE I get the following:
node.js:134
throw e; // process.nextTick error, or 'error' event on first tick
**^ ReferenceError: window is not defined**
at Object. (/node_modules/flatiron/node_modules/broadway/node_modules/eventemitter2/lib/eventemitter2.js:547:63)
at Module._compile (module.js:411:26)
at Object..js (module.js:417:10)
at Module.load (module.js:343:31)
at Function._load (module.js:302:12)
at require (module.js:355:19)
at Object. (/node_modules/flatiron/node_modules/broadway/lib/broadway/app.js:11:14)
at Module._compile (module.js:411:26)
at Object..js (module.js:417:10)
at Module.load (module.js:343:31)
If I create a standard http server without using flatiron everything runs great:
http = require "http"
module.exports = http.createServer (req, res) ->
res.writeHead 200, {'Content-Type': 'text/plain'}
res.end "Hello World\n"
Thoughts?
This is a bug in EventEmitter running on Solaris. You can see it as well if you just run an app on the latest version of Solaris, will crash with the same error message. You can use the patched EventEmitter2 that removes the check for the browser.
I created an issue for you.
So there's some code at the bottom of that eventemitter2.js file that basically tries to be "isomorphic" and work in both node.js and a browser. It tries to guess which environment by testing for the following global variables being defined:
process
process.title
exports
If all of those are defined, eventemitter2 will attach it's exported properties to the exports object for use in node.js. Otherwise, it will attach them to the window object for use in a browser.
For some reason inside cloud9, 1 or more of those 3 global variables is not defined, and it's branching to "browser" mode assuming window is there and failing. I don't know enough about the cloud9 ide hosting environment to understand exactly which one (or 2 or 3) of them it is and why it's missing.
Your vanilla http code works because it doesn`t load eventemitter2, which IS loaded when you use flatiron, which depends on broadway, which depends on eventemitter2.

Resources