I'm developing a directory app where content is rendered server-side depending on some parameters. My directory is a subapp of other app that is running on appache. I use the reverse proxy to redirect to node when needed.
So, my node root route is this: http://myapp.com/directory/
I need to have routes in this format: http://maypp.com/directory/location/category
where,
location and category can be anything! (it's user generated content)
My initial thought was that I would be able to do something like this:
app.get('/:location?/:category?', routes.index);
However, I get the following behavior:
In my routes.index after I render the view I have
console.log('location: ' + req.params.location + ', category: ' + req.params.category);
When I navigate to http://maypp.com/directory/ I get the following:
location: css, category: main.css
GET /components/modernizr/modernizr.js 200 69ms - 48.97kb
GET /components/requirejs/require.js 200 69ms - 80.75kb
And browser output is broken with the following error:
Uncaught SyntaxError: Unexpected token < main.js:1
And the weirdest thing is that main.js contains rendered HTML page instead of my browser-side js modules.
Another test case:
When I navigate to http://maypp.com/directory/loc/cat I get the following:
location: loc, category: cat
location: css, category: main.css
GET /components/modernizr/modernizr.js 200 6ms - 48.97kb
GET /components/requirejs/require.js 200 6ms - 80.75kb
location: js, category: main.js
and same stuff as above on the browser's side.
In my layout.jade I have the following:
script(type="text/javascript", src="/directory/components/requirejs/require.js" data-main="/directory/js/main")
If I have my route defined without second identifier (like this app.get('/:location?', routes.index);), it works fine, but it's not what I need!
====== Answer =========
Moved all of the route handling below static asset handling middleware.
var app = express();
app.set('port', process.env.PORT || 3000);
app.set('view engine', 'jade');
app.set('views', __dirname + '/views');
app.set('view options', {layout: true});
app.use(express.favicon());
app.use(express.logger('dev'));
app.use(express.bodyParser());
app.use(express.methodOverride());
app.use(express.responseTime());
app.use(express.errorHandler());
app.use(express.responseTime());
app.use(require('prerender-node'));
app.use(express.static(path.join(__dirname, '../../public')));
app.use(app.router);
var routes = require('./routes')(app);
location: css, category: main.css
This and some of your errors are because your handlers for static content, css, and js are not set up to execute BEFORE app.router. Ordering of middleware in express must be carefully thought through and precise. So first get your middleware order correct so all your static CSs, JS, images, etc are handled before the app.router.
Related
I'm trying to learn ExpressJS and I came across this piece of code. I just can't seem to understand the app.use function and the documentation is unclear to me. What exactly is happening to the /public directory in this particular example code when app.use is called?
// Require dependencies
var express = require('express');
var app = express();
// Set server port
app.set('port', (process.env.PORT || 3000));
// Set static page directory, /public
app.use(express.static(__dirname + '/public'));
app.use('/public', express.static('public'));
// Set template file directory, /views. Set view engine to EJS
app.set('views', __dirname + '/views');
app.set('view engine', 'ejs');
// Route root request to pages/index
app.get('/', function(request, response) {
response.render('pages/index');
});
// Route favicon request to public/favicons
app.get('/favicon.ico', function(request, response) {
response.render('./public/favicons');
});
// Begin listening at specified port
app.listen(app.get('port'), function() {
console.log('Node app is running on port', app.get('port'));
});
It's simple - you are setting up the public directory to be accessible over HTTP.
So, something like http://localhost:3000/public/abc.jpg will give you the abc.jpg from the public folder.
The
app.use('/public', express.static('public'))
line simply means - match any path that starts with /public like:
http://localhost/public/*.jpg
or any other extension - will choose that file from your public (the argument in express.static('public')) folder and serve it.
The line
app.use(express.static(__dirname + '/public'))
means - match any path and if file found in public directory, serve it over HTTP.
You can just use of the these two lines - difference being the /public part in the URL.
The docs are quite clear about this: https://expressjs.com/en/starter/static-files.html
I have multiple directories for my convenience for my static files.
Some of my static files are in client directory and some dashboard related files are in src directory so now my directory structure is as follows
/
|
client //static files and other stuff
server //server side express, app, controller, models etc
src //other static files
I have two angular apps one in client folder and another in src folder and my server side routes are as follows -
app.route('/app/dashboard-v1').get(function(req,res){
res.sendFile(path.join(__dirname, '../src', 'index.html'));
});
// All undefined asset or api routes should return a 404
app.route('/:url(api|img|src|auth|components|app|bower_components|assets)/*')
.get(errors[404]);
// All other routes should redirect to the index.html
app.route('/*')
.get(function (req, res) {
res.sendFile(path.resolve(app.get('appPath') + '/index.html'));
});
So my first angular app is in app/dashboard-v1 and all other urls are redirected to app2
I am getting all the files in my app2 correctly but I am getting 404 for all other files in my second app.
now If I comment out the
// app.route('/:url(api|img|src|auth|components|app|bower_components|assets)/*')
.get(errors[404]);
I am getting my index.html from second app in all files in first app instead of the 404 error
My express configuration is as follows -
if ('production' === env) {
app.use(favicon(path.join(config.root, 'public', 'favicon.ico')));
app.use(express.static(path.join(config.root, 'public')));
app.set('appPath', path.join(config.root, 'public'));
app.use(morgan('dev'));
} else {
app.use(require('connect-livereload')());
app.use(express.static(path.join(config.root, '.tmp')));
app.use(express.static(path.join(config.root, 'client')));
app.use(express.static(path.join(config.root, 'src')));
app.set('appPath', path.join(config.root, 'client'));
app.use(morgan('dev'));
app.use(errorHandler()); // Error handler - has to be last
}
I am assuming something is wrong with my routes. How do I fix this ?
In my index.html in first app(app/dashboard-v1) I have added the
<base href="/src/" />
and all the links inside my index.html are relative like the following is a block from src/index.html (app/dashboard-v1 url app)-
<script src="vendor/angular/angular-animate/angular-animate.js"></script>
<script src="vendor/angular/angular-cookies/angular-cookies.js"></script>
and when I open the network console in my browser the request that is made to the server is like this -
Request URL:http://localhost:9000/src/vendor/angular/angular-animate/angular-animate.js
to which I am getting a 404 status code in browser console
Do you run the app on the / direcotry of your example?
I think that you ahve to set __dirname as the static folder
app.use('/',express.static(__dirname));
or if you want you can set specific folders likt this:
app.use("/public", express.static(__dirname + "/public"));
app.use("/public2", express.static(__dirname + "/public2"));
I've been struggling with this for weeks now - for some reason, Express works fine for few hours after launching, then it starts ignoring the requests for static files.
It looks something like this:
GET / 304 153ms
GET /js/bootstrap.min.js 200 120000ms
GET /img/guide/0.png 200 120000ms
GET /img/guide/1.png 200 120000ms
GET /img/guide/2.png 200 120000ms
As I look into Chrome's resource browser, the page at /, handled by a normal app.get() function, is working normally and sent to the client - static files aren't.
From the side of a client, the page loads for 2 minutes showing blank white nothingness, then shows the content without any CSS styling or scripts (predictable).
I have no idea what I'm doing wrong, even simplest examples of Express I've found have this problem, and I didn't see it posted anywhere. Maybe it's the order of middleware, I seriously don't even know anymore...
I hope it's something trivial, and I'm just stupid/blind; here's a part of the code:
app = express()
app.set('views', __dirname + '/views')
app.set('view engine', 'jade')
app.use(express.logger('dev'))
app.use(express.cookieParser())
app.use(express.bodyParser())
app.use(express.session({
key: 'express.sid',
secret: 'wewillchangethislater',
store: sessionStore
}))
app.use(passport.initialize())
app.use(passport.session())
app.use(function(req, res, next) {
res.locals.isAjax = false
res.locals.user = req.user
next()
})
app.use(app.router)
app.use(express.static(__dirname + '/public'))
I've seen it happening with much simpler code tho too:
var express = require('express')
var app = express()
app.set('views', __dirname + '/views')
app.set('view engine', 'jade')
app.use(express.logger('dev'))
app.use(function(req, res, next) {
res.locals.isAjax = false
next()
})
app.use(express.static(__dirname + '/public'))
*some routes here*
app.listen(9999)
The rest of the code is in this utterly broken repo: https://github.com/Maxorq/Mikuia/blob/master/www.js
The only thing I found to help in those cases is restarting, which isn't too fun :/
I've seen this behavior with resin server due to configuration
Maybe not the same but might point you in the right direction
see https://stackoverflow.com/questions/22325309/css-and-js-files-hold-the-http-connection-until-timeout-on-resin-4
I have issues with serving .png image from my express app. I think there is something wrong with the router setup, because it tries to render page rather than serve a static file. The setup is as follows:
// app.js
// Module dependencies
var express = require('express'),
http = require('http'),
path = require('path'),
session = require('./middlewares/session');
// Create server
var app = module.exports = app ? app : express();
app.set('port', process.env.PORT || 3000);
app.set('view engine', 'jade');
app.set('views', __dirname + '/views');
app.set('view options', { layout: true });
app.use(express.static(path.join(__dirname, '../../public')));
app.use(express.favicon());
app.use(express.logger('dev'));
app.use(express.bodyParser());
app.use(express.methodOverride());
app.use(express.errorHandler());
app.use(express.responseTime());
app.use(express.cookieParser());
app.use(app.router);
var routes = require('./routes')(app);
if ('development' == app.get('env')) {
app.use(express.errorHandler());
}
// Start server
http.createServer(app).listen(app.get('port'), function() {
console.log('Express server listening on port ' + app.get('port'));
console.log(__dirname);
});
Then my routes file looks like this:
// routes.js
module.exports = function(app) {
//Routes
// app.get('/', routes.index);
app.get('/api/places', places);
app.get('/add-review', review);
app.get('/logout', logout);
app.get('/:location?/:category?', session(app), routes.index);
}
The jade view where I'm trying to load an image
# view
img(src="/nodeapp/img/logo-white.png")
I'm using reverse proxy for node app which root is this http://app.com/nodeapp
The folder structure:
public
components
css
img
js
server
srs
views
app.js
test
The error that I'm getting is this:
TypeError: Cannot read property 'logo-white.png' of undefined
at Object.get_listings (/app/server/src/models/vendors.js:354:16)
at exports.index (/app/server/src/handlers/index.js:6:31)
at callbacks (/app/node_modules/express/lib/router/index.js:161:37)
at /app/server/src/middlewares/session.js:13:5
at /app/bbe/server/src/api.js:18:3
at _fulfilled (/app/node_modules/requestify/node_modules/q/q.js:798:54)
at self.promiseDispatch.done (/app/requestify/node_modules/q/q.js:827:30)
at Promise.promise.promiseDispatch (/app/node_modules/requestify/node_modules/q/q.js:760:13)
at /app/node_modules/requestify/node_modules/q/q.js:574:44
at flush (/app/node_modules/requestify/node_modules/q/q.js:108:17)
GET /img/logo-white.png 500 857ms
So, here it's trying to actually render my jade views rather than serving from a static folder. Other static files such as js and css are served fine. Why is this happening?
Thanks!
=== Edit (added function that renders views) ===
exports.index = function(req, res) {
res.locals.location = data().get_location(req.params);
res.locals.categories = data().get_categories(res.locals.location);
res.locals.listings = data().get_listings(res.locals.location, req.params.category);
var meta = {
title: "My app",
module: "/nodeapp/js/core/index/main.js"
};
res.render('nodeapp/index', meta);
};
I had trouble myself with setting the 'views' path, so maybe the issue is the same.
I would try to set different view paths for the different sites I had like so (per app)
// site1.js
app.set('views', __dirname + '/views/site1');
// site2.js
app.set('views', __dirname + '/views/site2');
For some reason, it just wouldn't find the views to render. So, I had to set them all back to just '/views' directory, and when I rendered them, I included the extra directory there, and that worked.
I'm thinking if you restructured your directories so this
app.use(express.static(path.join(__dirname, '../../public')));
becomes
app.use(express.static(path.join(__dirname, '/public')));
that it might start working for you. I'm assuming all the other things in your public directories aren't being handled right either. If it's just that png file...check the name, rename it, fiddle with it.
This is driving me insane.
I have a node app with express. It serves up a file called index.ejs.
All I wanna do is import a javascript file on this page (something like jquery). But it won't pull it up, and I'm going nuts (as this should be simple).
On the server side I have this code in a file called app.js:
var express = require('express');
var app = express.createServer();
var hostName = (process.env.VCAP_APP_HOST || 'localhost');
app.listen( process.env.VCAP_APP_PORT || 8000);
app.use(express.static(__dirname + '/public/javascript/'));
//Create the view
app.set('views', __dirname + '/views');
app.set('view engine', 'ejs');
app.set('view options', { layout: false });
app.get('/', function(req, res){
res.render('index.ejs', {
item : "document.write('Hello World');"
});
});
In the ejs file, I have this:
<html>
<script>
<%= item %>
</script>
Link
<script type="text/javascript" src="/javascript/jquery.js"></script>
</html>
I can see in the console that the script is not loaded (it shows an error). But for the life of me I can't figure out why.
You need to add a static server to serve the other files you have under '/'. Currently your server is just responding to requests sent to '/' (and views).
Add this line to your express setup before app.get:
// DOCUMENT_ROOT should point to the directory that contains your javascript directory.
app.use(express.static(DOCUMENT_ROOT));
When your client asks for /javascript/jquery.js, your server is going to be looking for /public/javascript/javascript/jquery.js, and I rather doubt it will find it. Setting express.static()'s pathname to __dirname + '/public' should work, assuming that jquery.js is actually located in your_app/public/javascript.