I'm trying out a simple one page render and I'm obviously doing it wrong:
var express = require('express');
var app = express();
app.get('/', function(req, res){
res.render('home.html');
});
app.listen(3000);
console.log('Listening on port 3000');
Error:
Error: Cannot find module 'html'
I want to load a page with CSS/images and wanted to know where to store the CSS/images/scripts/HTML and how to load it. I have yet to find many example express apps.
When using res.render, you are rendering a defined view. The documentation state:
Render a view with a callback responding with the rendered string.
When an error occurs next(err) is invoked internally.
For specific HTML, you either have to load the file with fs.readFile, or have Express use a rendering engine, such as Jade or EJS. For example, this code sample would apply the EJS render engine to all files with the extension .html.
app.engine('html', require('ejs').renderFile);
Then you can render a file like this. This is an example of passing variables to the HTML file, because that's what embedded JavaScript is used for.
app.get('/', function (req, res) {
res.render('/file', {
pass: 'arguments',
to: 'the file here'
});
});
That is more convenient than having to read the file on each load like so:
app.get('/', function (req, res) {
fs.readFile('/index.html', 'utf8', function (err, data) {
res.send(data);
});
});
Although this is aside from your question, this is how passing variables to EJS works. It even works with if statements and loops, since it accepts all JavaScript. Putting console.log in the file would log each time the file was rendered.
<span><%= pass %></span>
<!-- after rendering -->
<span>arguments</span>
If you need to serve other resources, such as CSS, JavaScript, or other html files, you could use Express' directory function.
app.use(express.static('/'));
Then you wouldn't need to render your HTML at all. It would be statically served.
I want to load a html with css/images and wanted to know what is the layout of where to store the css/img/js and the html and load it? I am yet to find many example express js apps.
Assuming that you have installed express, within your express project you will find public folder. within public folder you will find three folder - images, javascripts, and stylesheets . As the names suggest place your css/img/js in their respective folders.
You place static HTML files not using any templates in the in the express project public folder and invoke it using:
app.get('/', function(req, res) {
res.redirect('/home.html');
});
Related
I'm learning Node.js with Express to get a little server running for studying. I'm getting response code 404 for all requests to files linked in my index.html file (e.g. the .css, .js, and image files).
The code I used to send index.html:
routes.get('/', (req, res) => {
res.sendFile(path.join(__dirname, "/clientSide/index.html"));
})
If I change the path to the whole folder instead:
routes.get('/', (req, res) => {
res.sendFile(path.join(__dirname, "/clientSide"));
})
I get in my browser the path from my hard drive to the folder, but I still can't view the files that way.
The clientSide folder contains index.html, app.js, style.css, and 2 or 3 images, all in the same folder. I can't view any of them.
I changed the filenames and folder name, and checked for capitalization to no avail.
SOLVED
I was using app.use(express.static(path.join(__dirname, "static/")));
With app = express();
That does not work, but using routes.use instead of app.use, while routes = express.Router();, is what solves that
The end
In your first code snippet, when you write:
routes.get('/', (req, res) => {
res.sendFile(path.join(__dirname, "/clientSide/index.html"));
})
You defined a new middleware function for requests to route /; that's what routes.get('/', ...) does. Assuming your server is running on port 3000, route / maps to http://127.0.0.1:3000/. For exactly that URL, and no other, Express executes your provided function, which replies with the the file clientSide/index.html. Thus, when your browser requests http://127.0.0.1:3000/, Express responds correctly.
But you've said nothing about the other files, such as http://127.0.0.1:3000/style.css, which would be route /style.css. You haven't defined any middleware for that route. So Express, not knowing what to do, by default responds with 404 and an error message. Thus, when your browser tries to load http://127.0.0.1:3000/style.css while fetching the resources referenced in index.html, the stylesheet fails to load.
Your second code snippet doesn't fix anything. It really makes things worse, because res.sendFile() can't send folders (how would that even work?) and that generates errors. You still haven't defined routes other than /, and now all your files are inaccessible.
To actually solve the problem, you could, theoretically, tediously define a route for every file, or more cleverly define one route with a route parameter. But serving a static folder with Express is a solved problem. You can simply offload the work to express.static by replacing all your code with:
routes.use(express.static(path.join(__dirname, "clientSide/")));
To go even further, you don't need Express or Node.js for a static file server. Try nginx. And for simple webpages, you don't need a server at all; just double-click index.html and let your browser open it.
I would like to show a custom 404 page (containing html, css, img, and ico). I know my 404 folder works when I replace the first public static homepage. However, I believe I am either not using routes the right way or it is not possible to set up two static folders.
I do not want to use template view engines at all. I want everything to be rendered on the frontend.
My project looks as follows:
404
--index.html
--error.css
--404.jpg
bin
--server.js
public
--index.html
routes
--index.js
package.json
app.js
app.js
...
var index = require(./routes/index); //works
...
app.use(favicon(__dirname + '/public/content/images/logo.ico'));
app.use(logger('dev'));
app.use(jsonParser);
app.use(urlencodedParser);
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public'))); //love it
app.use('/', index); //this is fine
...
index.js
var express = require('express');
const path = require('path');
var router = express.Router();
router.use(function timeLog(req, res, next) {
console.log('Time: ', Date.now());
next();
});
router.use('/', express.static(path.join(__dirname, './404'))); // HALP!
module.exports = router;
I've played around with the directory (trying to use '404' vs './404'). I am testing this by entering "localhost:3000/error". So if my path is '/error', it should still use the parent path: '/'. The documentation states that as long as my route is placed last, it should still work. I tested it without express.static and used an anon function that prints error on console.
Is it impossible to use express.static() twice?
Moving some of my comments into an answer since this led to your solution.
For Express.js 4.x, is it possible to use express.static twice?
Yes, you can use express.static() as many times as you want. It is middleware and, if it does not find a file matching the request, it just calls next() and allows the middleware chain to continue. So, you can have as many of them as you want and they will each get to search for a matching file in the order you register them.
I would like to show a custom 404 page (containing html, css, img, and ico). I know my 404 folder works when I replace the first public static homepage. However, I believe I am either not using routes the right way or it is not possible to set up two static folders.
You are mistakenly trying to use express.static() to implement a custom 404 page. That is not what it does. The usual way to implement a custom 404 page is with the last middleware handler in the chain. When that gets hit, nothing else has found a match for the current request, therefore you send your custom 404 page.
That typically looks like this:
app.use(function(req, res, next) {
res.status(404).sendFile(localPathToYour404Page);
});
See the "How do I handle 404 responses" section of this Express starter FAQ.
And, here's an article on custom error pages that shows some other examples.
https://github.com/jekku/users/blob/master/server.js#L41
Here's how I route my static files on an ExpressJS app. I usually don't do it in the routes, but I consider it as an 'initialization' process. It is possible to use ANY middleware twice or even more - as much as you want, keep that in mind.
I am starting to learn node.js, for now I am just trying to execute my old none node app with node. In this app, I have a html page with a body calling an onload js function. It's working just fine.
Now I have a a node app: app.js, simple as that:
var express = require ('express');
var app = express ();
app.use(express.static(__dirname + '/images'));
app.use(express.static(__dirname + '/CSS'));
app.use(express.static(__dirname + '/font'));
app.use(express.static(__dirname ));
app.use(express.static(__dirname +'/ketcher'));
app.use(express.static(__dirname +'/ChemAlive_JS'));
app.get('/', function(req, res) {
res.sendFile('/home/laetitia/Project/ChemAlive_Interface_Node/ChemAlive_Interface.html');
});
app.listen(8080);
And in the .html I still have:
<body onload="ketcher.init();">
but the function I want to load is not load at all anymore.
Any clue?
Thanks
You have not provided a lot of info in the question but from what you provide I can have few suggestions:
Suggestions
Instead of adding a lot of express.static uses:
app.use(express.static(__dirname + '/images'));
app.use(express.static(__dirname + '/CSS'));
app.use(express.static(__dirname + '/font'));
app.use(express.static(__dirname ));
app.use(express.static(__dirname +'/ketcher'));
app.use(express.static(__dirname +'/ChemAlive_JS'));
put those files (and directories) that you want to be served into one directory, e.g. called static, and use express.static once:
app.use(express.static(__dirname + '/static'));
or better yet, using the path module:
app.use(express.static(path.join(__dirname, 'static')));
you need to require the path module first with:
var path = require('path');
Now, instead of serving the single file for the '/' route with:
app.get('/', function(req, res) {
res.sendFile('/home/laetitia/Project/ChemAlive_Interface_Node/ChemAlive_Interface.html');
});
just put that file into the static directory as index.html so it will be served by the express.static middleware automatically.
Rationale
The way you have it configured currently, is that e.g. everyone can download your Node application - app.js with all of its configuration and even submodules etc.
Also, by using the express.static middleware many times I suspect that you are not sure how the files in those directories will be mapped to URLs.
Having a one place for static files makes it easy to verify whether any script tags have correct paths etc.
My guess
You don't provide enough info to be sure but my guess is that the JavaScript files for the main HTML file are not loaded correctly but you provide not enough info to be sure.
You can open the developer tools console in the browser and reload the page while the console is open and see for errors.
I suspect that the ketcher.init() method is being run but either the method, or the ketcher object is undefined, because some <script> tags failed to be loaded.
Example
The full example after following my suggestions would be much simpler:
var path = require('path');
var express = require ('express');
var app = express();
app.use(express.static(path.join(__dirname, 'static')));
app.listen(8080);
Maybe I would add some output to see what's going on:
var path = require('path');
var express = require ('express');
console.log('starting app.js');
var app = express();
app.use(express.static(path.join(__dirname, 'static')));
app.listen(8080, function () {
console.log('listening on http://localhost:8080/');
});
And now you will have all files that can be served to the browser in one place: in the static directory in this example.
Working app
You can see my example of a working Express application serving static files on GitHub:
https://github.com/rsp/node-express-static-example
In this example the directory for static files is called html but you can call it how you want, as long as it's consistent with how you use the express.static middleware.
You can start from this example project and just put your own files into the directory where express.static is told to look for files to serve.
You can also change the port number to match your needs.
More examples to do the same with and without Express, plus better explanation:
https://github.com/rsp/node-static-http-servers
More hints
The onload callback may not be fired if the page is waiting for some resources to load.
To see if your onload callback is firing you can change it to:
<body onload="alert('onload callback fired');">
Also the ketcher object may be not initialized or it may not have the init() method. After the page is loaded you can open the JavaScript Console and try running the method manually to see if it would work if it was fired:
ketcher.init();
You can also try commands like:
console.dir(ketcher.init);
console.dir(ketcher);
console.log(typeof ketcher.init);
console.log(typeof ketcher);
to see if the ketcher object contains what it should.
Even if the GET localhost:8080/ketcher.js gives a 200 OK status, it can still load some other resources that are not available or, as is very common with code that serve files with res.sendFile() (though unlikely in this case), it can serve HTML instead of JavaScript and result in a cryptic parse error on the < character - see this question for example:
Uncaught (in promise) SyntaxError: Unexpected token < in JSON at position 0 while acess static files in node server
Other related answers:
How to serve an image using nodejs
Failed to load resource from same directory when redirecting Javascript
Sending whole folder content to client with express
Loading partials fails on the server JS
Node JS not serving the static image
I can setup Angular in my web app using ASP/Visual Studio rather easily, but I want to get into the Node world, more specifically Express. I'm not truly understanding a basic route handler for Express, that will support the paradigms that Angular has.
For example, when setting up an Express file, there's a million examples, but almost all of them use Jade for templating, and I'm against Jade's syntax and have no desire to utilize it.
So far, I have this for my Express server (I have commented out some questions regarding my decisions made so far):
var express = require('express'),
path = require('path');
var app = express();
var env = process.env.NODE_ENV || 'development';
// 1) Is this really necessary if I'm going to utilize Angular routing for views?
app.set('views', path.join(__dirname, '/app/views'));
app.use(express.static(__dirname + '/public'));
// 2) I'm assuming this is the desired pattern for utilizing Angular.
// A catch-all handler that serves up an html file, which will then
// hand off the rest of the routing to Angular?
app.get('*', function(req, res) {
res.sendFile(path.join(__dirname + '/public/index.html'));
});
const PORT = 3000;
app.listen(PORT);
console.log('Listening on port: ' + PORT);
The questions I have are:
Is app.set('views', ...) necessary in an Angular app through Express or is it really intended for a Jade/EJS templating workflow? If it's useful to Angular, what path should I point it to? My Angular views? Or just the static html file that will serve as the container to all angular views?
I'm assuming app.use(express.static(...)) is still needed for ensuring Express can serve up public static resources, like css/javascript.
Is an app.get('*', ...) { res.sendFile('path/to/index.html') } route handler the accepted pattern for serving up one html file, which will contain all necessary Angular usage?
For Angular, is it normal to only have one html file for the entire of your application, and then just use Angular's routing and controllers/views to handle the rest?
Is app.set('views', ...) necessary in an Angular app through Express or is it really intended for a Jade/EJS templating workflow? If it's useful to Angular, what path should I point it to? My Angular views? Or just the static html file that will serve as the container to all angular views?
If you need to render a view on the server side and then send it to the client, you need this. Otherwise (in your case) no. You can just send the file to the user or generate a user-specific output based on the parameters that user has sent to the server. It could be anything, HTML file, json or just simple text.
I'm assuming app.use(express.static(...)) is still needed for ensuring Express can serve up public static resources, like css/javascript.
You are right. If you need to serve the static content as well, the best way is to use express.static, however you can catch the requests and serve the content by yourself.
Is an app.get('*', ...) { res.sendFile('path/to/index.html') } route handler the accepted pattern for serving up one html file, which will contain all necessary Angular usage?
If for each and every other requests that the previous routes didn't catch, you need to send the exact same file, yes it is fine.
Remember if you need to serve other HTML files as templates and they are not in the same directory as you pointed in express.static to, the client could not have access to html files. I'll discuss it in a bit.
However, I believe it is a good practice to define all the routes and not just put a * to catch them all. It is better to define a pattern at least, it would be easier to maintain the code later on.
For Angular, is it normal to only have one html file for the entirety of your application, and then just use Angular's routing and controllers/views to handle the rest?
Depends on your application. In most of the cases yes.
I've done several big angular projects, I only have one route that actually serves the main html file, and one that serves static files (pictures, js, css). I also have a route that points to the templates directory which should be served as static contents. Those are the templates that AngularJS need to work with.
For the communication between your angular app and the server, you'll probably need other routes as well. You could create RESTful API end-points to create a communication layer for the client and the server.
I usually have these two lines in the server code to keep the all the templates in the same folder. It makes it easier to manage and define work flows:
app.use(express.static(path.join(__dirname, 'public')));
app.use('/templates', express.static(path.join(__dirname, 'templates')));
For communication between the server and the client:
app.post('/login', function (req, res) {
// deal with login information ...
res.send({
done: true,
errors: []
});
});
app.post('/search', function (req, res) {
// do the search ...
res.send({
done: true,
results: []
});
});
Remember if you use * at some point in your app, the other routes that you defined after that, will never catch the request.
And
I'm against Jade's syntax and have no desire to utilize it.
Yes, me too! But there are other options as well, I personally prefer ejs. If you are using express-generator you can just pass -e switch and it'll create everything compatible with ejs.
$ express -e
Also, take a look at here.
I'm a PHP developer attempting node.js using express.js libraries for the first time. I've gotten a simple node.js static server running using express.staticand am now trying to move on to routing.
I have this routing rule:
app.get('/', function (req, res){
res.sendFile('index.html', {root: path.join(__dirname, '/finished')});
});
which returns index.html (url:localhost:port) fine, my problems are when I attempt to import from other directories in index.html's folder. I always get a 404 error.
Do I have to write rules for every file requested? Is there anyway to make a folder, or group of folders public?
Example (this works):
app.get('/components/webcomponentsjs/webcomponents.js', function (req, res){
res.sendFile('./components/webcomponentsjs/webcomponents.js');
});
There must be a way better way to do this. Any assistance and documentation appreciated, can't seem to connect the dots.
EDIT
express.static usage:
app.use(express.static(__dirname + '/root'));