Multiple Errors serving HTML pages with Express - express

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'));

Related

How can I link my express server to generated 'dist' directory?

I am getting this error, "TypeError: path must be absolute or specify root to res.sendFile"
root
-dist
|--index.html
|--index_bundle.js
-src
|-server
|-server.js
//server.js
var path = require('path')
const express = require('express')
const bodyParser = require('body-parser')
const cors = require('cors')
const app = express()
let dataStorage = {};
app.use(cors())
app.use(bodyParser.json())
app.use(bodyParser.urlencoded({
extended: true
}))
app.use(express.static('dist'))
app.listen(8081, function(){
console.log('Server running on port 8081!')
})
app.get('/', function (req, res) {
res.sendFile('../dist/index.html') //need help setting this up
})
app.post('/formHandler', function(req, res){
//post to dataStorage here
})
I am trying to run an express server while also using webpack-dev-server for hot reloading.
I am having trouble with setting up the path to generated 'dist' file.
I am able to just run the webpack-dev-server without express and the file is working then.
Thank you
You can have access to it by serving It's content as express static.
const path = require('path');
app.use(express.static(path.resolve(__dirname, '../../dist'));
You can also define the path at which statics assets can be accessible like this
app.use('/', express.static(path.resolve(__dirname, '../../dist'));
As in your dist folder there are already an index.html file it will be rendered by default when visiting the / path in your browser. No need to specify the index.html file in you request URL

Set content-type to XHTML in static files

I want to have a route for my static files:
// server.js
app.use('/', require('./routes/ui/templates'));
The thing is that I cannot change the content-type from html->xhtml. Here's my route:
const express = require('express');
const router = express.Router();
// Path configs
const pathRoot = __dirname
const pathPublic = pathRoot + "/../../public/"
router.use('/', express.static(pathPublic));
router.get('/', (req, res) => {
console.log(pathPublic)
res.sendFile('index.html', {root: pathRoot});
})
router.use((req, res, next) => {
res.type('application/xhtml+xml');
next();
})
module.exports = router;
Note that for some reason, if I don't add the router.use(...)
my index file is not served at all. From what I understand, the middleware I've
written should be last as I am trying to capture the response and modify it.
Please correct me if I am wrong.
If you want to manage the Content-Type for specific types of files sent by express.static(), you can use the setHeaders option like this:
app.use(express.static(path.join(__dirname, "public"), {
setHeaders: function(res, path, stat) {
// if file is a .xml file, then set content-type
if (path.endsWith(".xml")) {
res.setHeader("Content-Type", "application/xhtml+xml");
}
}
}));
Some other things you may also be asking about:
Once your express.static() route matches a file, no further routing is done. The response is sent and none of the route handlers that follow will be called. So, you can't impact the content-type elsewhere with later routes.
If the request route path is /, then express.static() will look for an index.html file in the pathPublic you're passing it. If it finds it, it will send that and no further routing will happen.
res.type() does not do what you seem to be trying to use it for. You pass it a file extension and it sets the content-type according to a mime lookup for that file extension. As you can see in my code example above, you can set the content type yourself with res.setHeader("Content-Type", "application/xhtml+xml").
Try res.setHeader('content-type', 'application/xhtml+xml');

Express: serve static files on subroute

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

Express: use separate route file for multiple kinds of http requests on same path

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);
//..

Setting up default view path in Express.js

Source Code
app.js
var express = require('express');
var app = express();
var path = require('path');
var viewPath = path.join(__dirname, 'app/views');
app.set('views', viewPath);
app.set('view engine', 'jade');
app.get('/', function(req, res) {
res.render('index', { title: 'Home Page' } );
});
app.listen(3000);
Folder Structure
app
└───views
│ └───index.jade
└───app.js
Error in Browser
Error: Failed to lookup view index in views directory d:\Users\Admin\Documents\...\project\views
Question
I would like to structure my app by placing the view files in app/views/*.jade, but I cannot get it working so far, using app.set('views', ...) should work but it doesn't
console.log(viewPath) shows d:\Users\Admin\Documents\...\project\app\views
I also tried e.g. app.set('views', 'xxx') but the error still get stucked on the same path, it seems like app.set() has never been called, what's wrong here ?, please guide.
Thanks
Edit
It doesn't matter what I set using app.set('views', 'xxx') the error will always be Error: Failed to lookup view index in views directory d:\Users\Admin\Documents\...\project\views (always keep saying the same path)
I'm so sorry about router.get('/', ...), My actually project's files are different, so I was making mistake here
Try using
app.set('views', path.join(__dirname, 'views'));
Your app.js is in your app folder so I think
var viewPath = path.join(__dirname, 'app/views');
app.set('views', viewPath);
will look into app/app/views/ instead of app/views/ because of __dirname
__dirname is the directory in which the currently executing script resides.
I know it's too late, but might help someone who has the same problem. If you placed the rendering code in a separate file, then you need to use express.Router instead of app.get. For example,
const express = require('express');
const router = express.Router();
router.get('/', (req, res) => {
res.render('index', {title: 'Hey', message: 'Hello there!'});
});
module.exports = router;
Then in your app.js,
const router = require('./app/routes/routerName');
app.use('/', router);
I actually have separated files in my project, so I have app.get('/', ...) in the separated route file, then require it to use with app.use()
I really have no ideas but after moving only the app.get('/', ...) to the app.js, the problem has been solved
Thanks everyone
As mentioned by Roxinagi, you should be using app.get().
Everything else seems fine
app.get('/', function(req, res) {
res.render('index', { title: 'Home Page' } );
});
const path = require('path')
app.set('views', path.join(__dirname, 'app/views/'))
app.set('view engine','jade');