I'm using express-subdomain 1.0.5 with express 4 to route a subdomain for my site. I have localhosts set up and that's working fine. In my main application.js, I have this:
//views
app.engine('ejs', engine);
app.set('views',__dirname + '/views');
app.set('view engine', 'ejs');
//subdomains
var developerRoutes = require('./developerRoutes');
app.use(subdomain('test-developer', developerRoutes));
// main routes
var routes = require('./routes');
app.use(routes);
The developerRoutes file looks like this:
var developer = require('../src/developer');
var devRouter = require('express').Router();
devRouter.get('/', developer.developerHome);
module.exports = devRouter;
and developer looks like this (I expect to have ~10 routes so I'm using a separate file):
exports.developerHome = function(req, res) {
console.log('hi developer got here') //this fires, so I know this route is being called
res.render('developerHome', {
data: {
testData: 'hi'
}
});
}
When I try test-developer.localhost.dev, it 404s (and developerHome.ejs exists). When I try any other route that exists for the main domain but is not present in the developer routes file (e.g. test-developer.localhost.dev/about), it renders the main view. If I try a plain res.send('hi!'); in developer.js, that renders fine.
Is there some ordering of the middleware that I'm missing? I've tried putting the view engine lines both before and after the main and subdomain lines, with no change. Is there any way to make the subdomain routes fall through to the express errorhandling middleware instead of (as it seems) the main routes?
Editing to add -- If I force status and send HTML as below it works, but why?
exports.developerHome = function(req, res) {
console.log('hi developer got here')
res.render('developer/developerHome',
{data:
{
testData: 'hi'
}
},
function(err, html){
if(err) console.log(err);
res.status(200).send(html);
}
);
}
Related
I'm trying to route pages using Express, but I can't seem to route from my main page. I'm using HTML as the view engine and I feel like everything is set up properly, but I'm seeing the error:
"TypeError: path must be absolute or specify root to res.sendFile"
Here is my file structure:
root
-public
--images
--index.html
--main.css
--sponsors.html
--team.html
app.js
I've tried multiple file routes, res.render versus res.sendFile.
var express = require("express")
var app = express()
const port = 3000
var http = require("http")
const path = require('path')
app.set("view engine", "html")
app.listen(port, () => console.log(`Example app listening on port
${port}!`))
app.use(express.static(__dirname + '/public'));
app.get('/sponsors', function(req, res) {
res.sendFile('sponsors')
})
app.get('/', function(req, res) {
res.sendFile('index')
})
app.get('/team', function(req, res) {
res.sendFile('team')
})
To render from a view engine, use res.render(), not res.sendFile().
And, your view engine will need to be able to find a file with that name and an appropriate file extension in the path for the view engine.
If you want to use res.sendFile() without the view engine, then you must specify an actual filename or include the root option that tells it where to look. You must also use the actual file extension on the filename.
Remove the following route method.
// remove the following code
app.get('/', function(req, res) {
res.sendFile('index')
});
Update the default path to the static method you had already written.
app.use('/', express.static(__dirname + '/public'));
I have created an CRA app and have a couple express routes loading the CRA build files, for example:
app.get('/files', async (req, res, next) => {
...
try {
res.format({
html: function() {
const fileLoc = './public/react_ui/build/index.html';
const stream = fs.createReadStream(path.resolve(fileLoc));
stream.pipe(res);
}
});
} catch (e) {
next(e);
res.redirect(SEE_OTHER.http_status, '/login');
}
});
Prior to added the CRA, the express app exposed the /public folder like this:
// access to express App code files
app.use(express.static(__dirname + '/public'));
Now that I have the CRA app embedded, I wanted to expose the build files like this, otherwise the index.html file created by building the CRA does not know where the /static/js/* are:
// access to React App build files
app.use(express.static(__dirname + '/public/react_ui/build'));
However, it breaks the express routing. For instance, when I logout of the app, it is supposed to send me to the endpoint / and this checks if I am logged in or not, if not, then it is supposed to send me to the login page like this:
app.get('/', function(req, res) {
...
isLoggedIn(req, function(status) {
switch (status.status) {
case 200:
res.redirect(303, '/loader');
break;
default:
res.redirect(303, '/login');
}
});
});
However, this is what is breaking. If I remove the command to expose the /build folder above, then the routing works again and I am sent to the login page, but accessing the CRA pages breaks, because the build files are NOT FOUND.
// access to React App build files - if removed, routing works again
app.use(express.static(__dirname + '/public/react_ui/build'));
Does anyone have any suggestions as to why this is happening? I don't know if this is a react app issue, an express issue, or something else. Any insights would be helpful.
You have conflicting routes.
app.js
app.use('/', express.static(__dirname + 'path/to/static/build'));
// Dont use '/' as it used for static route.
app.use('/auth', (req, res) => {
...
isLoggedIn(req, function(status) {
switch (status.status) {
case 200:
res.redirect(303, '/loader');
break;
default:
res.redirect(303, '/login');
}
});
})
Note you can use whatever route for static build. I have given general convention.
I'm trying to get routing work using Express and create-react-app.
My goal is to address the user to the homepage of the application when the URL is / and to the login page when the URL matches /login.
In my server.js I have two routes defined:
var mainRoutes = require("./routes/mainRoutes");
var apiRoutes = require("./routes/apiRoutes");
[...]
app.use("/", mainRoutes);
app.use("/api", apiRoutes);
While apiRoutes contains all the api routing definitions, mainRoutes is responsible for the main navigation (at least this was the idea):
var express = require("express");
var path = require("path");
let router = express.Router();
router.route("/").get((req, res, next) => {
res.sendFile("index.html", { root: "./client/build/" });
});
router.route("/login").get((req, res, next) => {
res.send("This is the login page");
});
module.exports = router;
Somewhere I read about serving the static asset generated by the building process of create-react-app so I added:
// Priority serve any static files.
app.use(express.static(path.join(__dirname, "client/build")));
// All remaining requests return the React app, so it can handle routing.
app.get("*", function(req, res) {
res.sendFile(path.join(__dirname + "/client/build/index.html"));
});
Adding these lines, I successfully see my index.html but I can't visit both /login and /apisubroutes since it redirect me on the main page (index.html) each time.
It's like I need to serve the static files on my subroute mainRoutes but I don't have an idea on how to do that.
How can I make this work?
app.get('*') would match every single route that you have.
You should do something like this:
var mainRoutes = require("./routes/mainRoutes");
var apiRoutes = require("./routes/apiRoutes");
[...]
app.use(express.static(path.join(__dirname, "client/build")));
app.use("/", mainRoutes);
app.use("/api", apiRoutes);
// If the app reaches this point, it means that
// the path did not match any of the ones above
app.use(function(req, res, next){
// redirect the user to where we serve the index.html
res.redirect('/');
});
create-react-app I believe handles routing different, you cannot hook up the browser's route to the route you want to serve because you're running a single page application", unless you do universal routing with server and the js bundle
Here are my routes:
app.get('/signUp', routes.signUp);
app.post('/signUp' , routes.signUp);
Here is my separate file for routes.
exports.signUp = function(req, res) {
res.render('signUp');
};
The second block of code is behaviour I want in response to a get request.
How do I respond to a post request? I have already tied up the signUp function with behaviour that responds to get. Do I bundle up the post behaviour in the same function and render the sign up page again? Suppose I simply want to render the view, I don't want the post behaviour to execute in that case so it would be strange to bundle those together.
I believe the express router module should resolve this for you.
route file -
var express = require('express');
var router = express.Router();
router.route("/")
.get(function (req, res) {
res.render('signUp');
})
.post(function (req, res) {
//do something else
})
module.exports = router
index.js/app.js/server.js/whatever you call it.
//..
signUp = require("./routes/signup.js"); //or wherever this is
//...
app.use("/signUp", signUp);
//..
Alright, so I am having an issue with express getting my templates to work with the extends/block keywords. I was able to get the index template working just fine; however, when I tried to add a second template, 'extends' does not seem to function. I've pasted the code below, and help would be appreciated! (for reference, I am running express version 2.5.8 and node 0.6.12)
app.js:
var express = require('express')
, routes = require('./routes');
var app = module.exports = express.createServer();
// Configuration
app.configure(function(){
app.set('views', __dirname + '/views');
app.set('view engine', 'jade');
app.use(express.bodyParser());
app.use(express.methodOverride());
app.use(express.cookieParser());
app.use(express.session({ secret: 'your secret here' }));
app.use(app.router);
app.use(express.static(__dirname + '/public'));
app.set('view options', { layout: false, pretty: true });
});
app.configure('development', function(){
app.use(express.errorHandler({ dumpExceptions: true, showStack: true }));
});
app.configure('production', function(){
app.use(express.errorHandler());
});
// Routes
app.get('/', routes.index);
app.get('/login', routes.login);
app.listen(3000, function(){
console.log("Express server listening on port %d in %s mode", app.address().port, app.settings.env);
});
routes/index.js:
exports.index = function(req, res){
res.render('index', { title: 'rm-dash-r' })
};
exports.login = function (req, res) {
res.render('login', { title: 'rm-dash-r' })
};
In the views/ directory, there are 3 files. index.jade, main-layout.jade, and login.jade. For testing, login and index are identical files.
main-layout.jade:
!!!
html
head
title= title
link(rel='stylesheet', href='/stylesheets/style.css')
body(style='margin: 0 22%;')
div.container
div.header
a(href='/')
span rm-dash-r
div.stripes
span
div.nav
a(href='/') Blog
a(href='/') About
a(href='/') Projects
div.clearer
span
div.stripes
span
div.main
div.left
div.content
block content
...
index.jade/login.jade:
extends main-layout
block content
h1 testing
Essentially, the route for '/' works without any problems, but the login route will only render the login.jade markup, except with extends main-layout at the top of the page.
If there is any other information that would be helpful to know, please let me know.
alright, after significant trial and error, I seem to have it working. For some reason, after adding a return to the first line of login.jade (ie. extends main-layout is now line 2) it all seems to work.
I haven't the slightest idea why this is the case, but if anybody can shed some light I'd be interested to hear.