Serve assets before other routes - node.js

I am developing a web app using Node.js, Express and AngularJS.
I am serving my front-end JavaScript from the public folder, so e.g. that HTTP GET /lib/angular/angular.min.js would presumably return the AngularJS JavaScript.
However, as I want all requests to get handled by the Angular router in the browser, I have a catch-all route defined as follows:
app.get('/*', function(req, res) { res.send('template.jade'); });
The problem is that this route overrides the static asset routing, in which case it always run, even when a static asset is requested.
Is there a way to tell Express to process static assets before the custom routes propagate? Are there perhaps any other clever ways of avoiding this issue?
The Express configuration is as follows:
// Generated by CoffeeScript 1.7.1
(function() {
var ExpressConfig, crypto, express, path, pkg;
crypto = require('crypto');
express = require('express');
path = require('path');
pkg = require('../package');
ExpressConfig = (function() {
function ExpressConfig() {}
ExpressConfig.prototype.configure = function(ENV) {
var APP_ROOT, app;
APP_ROOT = path.join(__dirname, '../');
app = express();
app.set('port', pkg.config.port);
app.set('views', APP_ROOT + 'webapp');
app.set('view engine', 'jade');
app.use(express.favicon());
app.use(express.logger('dev'));
app.use(express.json());
app.use(express.urlencoded());
app.use(express.methodOverride());
app.use(express.cookieParser(crypto.randomBytes(20).toString('hex')));
app.use(express.session());
app.use(app.router);
app.use(require('stylus').middleware(APP_ROOT + 'public'));
app.use(express["static"](APP_ROOT + 'public'));
if (ENV === 'development') {
app.use(express.errorHandler());
}
return app;
};
return ExpressConfig;
})();
module.exports = ExpressConfig;
}).call(this);
//# sourceMappingURL=express-config.map
I can verify that the configuration is run before the catch-all route definition, as I have checked it by logging in each place to check the order.
I can also verify that the assets configuration works when the catch-all route is removed.

The static middleware should appear before app.router and the specific route.
// first
app.use(express["static"](APP_ROOT + 'public'));
// second
app.use(app.router);
// last
app.get('/*',whatever);

Related

Express not interpreting URL path correctly for static files

I am building a Node.JS app with Express and Handlebars to serve the public content. The app is running in pm2.
The app is working fine, but I want to serve static files. I added 2 static routes which are loaded fine when I check the Express log.
But when I try to access the files, I get a 404. I noticed the message on the 404 states "Cannot GET /js" where I would expect "Cannot GET /scripts/scripts.min.js".
The URL should be on /scripts/scripts.min.js, internally it's located inside a public folder:
app.js
public
scripts
scripts.min.js
images
styles
Here is my app.js:
const express = require('express');
const { engine } = require('express-handlebars');
require('dotenv').config();
const bodyParser = require('body-parser');
const path = require('path');
const app = express();
const {
NODE_ENV,
PORT,
HOST,
} = process.env;
// Use body-parser middleware
app.use(bodyParser.json());
// Use express-handlebars as the view engine
app.engine('handlebars', engine({
defaultLayout: 'main',
layoutsDir: __dirname + '/views/layouts',
partialsDir: __dirname + '/views/partials',
}));
app.set('view engine', 'handlebars');
app.set('views', __dirname + '/views');
app.use(express.static(path.join(__dirname, 'public')))
app.use('/scripts/monaco/', express.static(path.join(__dirname, 'node_modules','monaco-editor','min','vs')));
// Define routes
app.get('/', (req, res) => {
res.render('home', { title: 'Home' });
});
app.get('/debug', (req, res) => {
res.send(__dirname + '/public')
})
app.post('/', (req, res) => {
console.log(req.body);
res.send('Success');
});
// Load external routes (also tried the staticFiles by using res.sendFile)
require('./routes/processing')(app);
// require('./routes/staticFiles')(app);
// Start the server
app.listen(PORT, () => {
app.currentServer = {
host: HOST ? HOST : "127.0.0.1",
port: PORT,
};
console.log(`Server init on: http://:${PORT}`);
});
I tried serving the files using express.static, I also tried sending them trough specific routes by using res.sendFile.
It looks like Express (or something else) is interpreting the URL path incorrectly. /scripts/scripts.min.js is downgraded to /js so it seems.
I hope anybody has a clue!

How to use route for html file already served as static

I use passport.js to authenticate user after he enters login page. To keep user logged in when he returns to home page i'm going to use something like:
app.use(express.static(__dirname + '/public'));
app.get('/', function(req,res){
if(req.user){
// connect to database ....
} else{
res.sendFile(__dirname +'/index.html');
}
});
Note that index.html file is inside "public" folder. Recently i realized that having a code like above, node.js doesn't use app.get('/'....) route but it serves index.html directly. So i'm unable to check if req.user exists. Any suggestion?
As You might understand express.static handles index.html before Your router.
But You cannot avoid express.static also (otherwise You have to use nginx or write own static file output).
So You've to re-think Your folder structure or have to develop 2 separate apps: api (backend) and frontend (that will request to api for data)
In context of Your question I wrote an example app where I organize assets, html files and app routes:
1) Have such folder structure:
2) and example app.js :
'use strict';
const express = require('express');
const app = express();
const cookieParser = require('cookie-parser');
const bodyParser = require('body-parser');
app.set('trust proxy', 1);
// attaching renderer
app.engine('.html', require('ejs').renderFile); // ejs renderer will render .html files as ejs files
app.set('view engine', 'html'); // views has .html extension
app.set('views', __dirname + '/public'); // views live in public folder
// attaching common middlewares
app.use('/assets', express.static('public/assets')); // our static assets will live in public/assets folder
app.use(cookieParser());
app.use(bodyParser());
// implement and attach passport auth somewhere (:
// remove it after passport has been attached:
const authorizeUser = (req, res, next) => {
req.user = {id: 1, username: 'test'};
next();
};
app.get('/', authorizeUser, (req, res) => {
res.render('index', {user: req.user}); // render get index.html from views folder (see above)
});
app.listen(8080, () => {
console.log('App listening');
});
p.s. download example app from here (don't forget to call npm i inside extracted folder (; )
p.s. implement passport.js Yourself

Including API routes in Express 4.x

I'm learning MEAN stack with 'Getting MEAN with...' book, and problem is older Express version in books than i use.
The first step is to tell our application that we’re adding more routes to look out for,
and when it should use them. We already have a line in app.js to require the server
application routes, which we can simply duplicate and set the path to the API routes
as follows:
var routes = require('./app_server/routes/index');
var routesApi = require('./app_api/routes/index');
Next we need to tell the application when to use the routes. We currently have the following line in app.js telling the application to check the server application routes for
all incoming requests:
app.use('/', routes);
Notice the '/' as the first parameter. This enables us to specify a subset of URL s for
which the routes will apply. For example, we’ll define all of our API routes starting
with /api/ . By adding the line shown in the following code snippet we can tell the application to use the API routes only when the route starts with /api :
app.use('/', routes);
app.use('/api', routesApi);
And there's listing of my app.js file:
var express = require('express')
, others = require('./app_server/routes/others')
, locations = require('./app_server/routes/locations')
, routesApi = require('/app_api/routes/index')
, ;
require('./app_server/models/db')
var app = module.exports = express.createServer();
// Configuration
app.configure(function(){
app.set('views', __dirname + '/app_server/views');
app.set('view engine', 'jade');
app.use(express.bodyParser());
app.use(express.methodOverride());
app.use(app.router);
app.use(express.static(__dirname + '/public'));
});
app.configure('development', function(){
app.use(express.errorHandler({ dumpExceptions: true, showStack: true }));
});
app.configure('production', function(){
app.use(express.errorHandler());
});
// Routes
// LOCATION PAGES
app.get('/', locations.homeList);
app.get('/location', locations.locInfo);
app.get('/location/review/new', locations.addReview);
// OTHER PAGES
app.get('/about', others.about);
app.listen(3000, function(){
console.log("Express server listening on port %d in %s mode", app.address().port, app.settings.env);
});
Can someone explain me how to do the same in my Express version ?
In Express 4, this is done using Router Middleware. More info is available on Express Routing here.
A Router is simply a mini express app that you can define middleware and routes on that should all be packaged together, ie /api should all use apiRouter. Here is what apiRouter could look like
apiRouter.js
var express = require('express')
var router = express.Router(); // Create our Router Middleware
// GET / route
router.get('/', function(req, res) {
return res.status(200).send('GET /api received!');
});
// export our router middleware
module.exports = router;
Your main Express app would stay the same, so you would add your router using a require() to import the actual file, and then inject the router with use()
Express Server File
var express = require('express');
var app = express();
var apiRouter = require('../apiRouter');
var port = process.env.PORT || 3000;
app.use('/', apiRouter);
app.listen(port, function() {
console.log('listening on ' + port);
});

Node.js Express not rendering html view

so I was trying to follow a tutorial to use node.js as the front end of a wordpress site
This one http://www.1001.io/improve-wordpress-with-nodejs/
Here is the code from server.js
var frnt = require('frnt');
var fs = require("fs");
var path = require("path");
var express = require('express');
var app = express();
var doT = require('express-dot');
// Define where the public files are, in this example ./public
app.use(express.static(path.join(__dirname, 'public')));
// Make sure this is set before the frnt middleware, otherwise you won't
// be able to create custom routes.
app.use(app.router);
// Setup the frnt middleware with the link to the internal server
app.use(frnt.init({
proxyUrl: "http://localhost:8888/frnt-example/wordpress", // The link to your wordpress site
layout: false // We simplify this example by not using layouts
}));
// define rendering engine
app.set('views', path.join(__dirname, "views"));
app.set('view engine', 'html' );
app.engine('html', doT.__express );
// respond with "Hello World!" on the homepage
app.get('/', function (req, res) {
res.send('./views/index.html');
});
app.listen(8080); // listen to port 8080
It keeps outputting the following
./views/index.html
Rather than rendering the html?
I've never used frnt, but res.send sends a string so that's no big surprise.
Look at res.sendfile which sends the contents of a file.
I prefer to use ejs , it's sems like html just edit index.html to index.ejs
1- install ejs module npm install ejs
2- add this in app.js
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'ejs');
and render the index.ejs by using
app.get('/', function (req, res) {
res.render('index'); // or res.render('index.ejs');
});
res.send() // it send just a string not file
Hope it usefull !

Nodejs & express can't find public folder

My node.js app can't find the public folder. I've tried using connect static and express static from this answer: static files with express.js and also this answer: File not found in Node.js
But I still can't get it working. I get the content of the page I try to display, but not any of the links to css and js files.
Any ideas?
This is my app.js file.
var express = require('express'),
post = require('./routes/posts'),
web = require('./routes/web'),
http = require('http'),
stylus = require('stylus'),
nib = require('nib'),
path = require('path');
var app = express();
function compile(str, path) {
return stylus(str).set('filename', path).use(nib());
}
app.configure(function () {
app.set('views', __dirname + '/views');
app.set('view engine', 'jade');
app.use(express.logger('dev'));
app.use(express.json());
app.use(express.urlencoded());
app.use(express.multipart());
app.use(app.router);
app.use(stylus.middleware({src: __dirname + '/public', compile: compile}));
app.use(express.static(path.join(__dirname, 'public')));
app.use(express.bodyParser({ keepExtensions: true, uploadDir: __dirname + '/upload/photos' }));
});
//app.use(app.router);
//Web
app.get('/', web.frontPage);
app.post('/posts', post.findAllPosts);
app.post('/posts/:id', post.findPostById);
app.post('/postAdd', post.addPost);
app.put('/posts/:id', post.updatePost);
app.delete('/posts/:id', post.deletePost);
app.get('*', function(req, res){
res.render('404');
});
http.createServer(app).listen(80);
console.log('Listening on port 80...');
Your problem is caused by this:
app.get('*', function(req, res){
res.render('404');
});
Because you're declaring the app.router middleware (which handles that catch-all route) before the static middleware, the router gets all the requests for static files too, and if they aren't handled by any of your other routes, it will generate a 404.
The solution would be to move the static middleware to before the router. The same also needs to be applied to the Stylus middleware and the bodyParser middleware, to make sure they are called before your routes:
app.use(stylus.middleware({src: __dirname + '/public', compile: compile}));
app.use(express.static(path.join(__dirname, 'public')));
app.use(express.bodyParser({ keepExtensions: true, uploadDir: __dirname + '/upload/photos' }));
app.use(app.router);
(although it seems that you can skip the bodyParser middleware, since you're using the json, urlencoded and multipart middlewares already; the bodyParser middleware is just a very thin wrapper around those three)

Resources