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
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 am having trouble with local includes on the client side using Node.js and Socket.io. This may be to my PHP/Apache mindset I have had for file requests for most of my life.
On my server, I load the page likewise:
var express = require("express");
var app = express();
var path = require("path");
var server = require("http").createServer(app);
var io = require("socket.io")(server);
var mysql = require("mysql");
var port = process.env.PORT;
var ip = process.env.IP;
app.use(express.static(__dirname + "/client"));
//start opening socket connection handlers ...
And my files are organized likewise:
games
libraries
bigInt
threejs
etc...
version_1
client
index.html
index.js
index.css
server.js
database.sql
version_2
version_3
etc...
Depending which version I want to run, I open that version's directory and run its server.js file. The line redirects the client to /client/index.html with the line app.use(express.static(__dirname + "/client")). But now only files that are in the client folder are reachable by <script></script> or <link> tags but not those libraries in the libraries folder that I use across versions.
How do I change my code to be able to access files inside the libraries folder from /version_x/client/index.html while still directing the client to proper html file?
Note: Due to this issue, I have been forced to use only libraries with supported CDNs for the past couple weeks I have been learning Node.js.
Add the following line right after var ip = process.env.IP;:
app.use('/libraries', express.static(path.join(__dirname, '..', 'libraries'));
What this does is adding a new route to your application server. All your files inside your /games/libraries folder are now accessible via /libraries.
How does it work? Your express router uses different middlewares based on the provided paths. This line tells the router, to use the static middleware and serve files from ../libraries when a HTTP Request for anything under /libraries comes in.
You can serve more folders with express.static
//Serve Client Folder
app.use(express.static(__dirname + "/client"));
//Server External Libraries Folder
app.use('/libs', express.static(__dirname + "/../libraries"));
//Ex: <script src="libs/threejs/threejs.js">
//Will load libraries/threejs/threejs.js
I made an html5 game (using GameMaker), which is constituted of an index.html and a folder "html5game" that contains the dependencies of the game - the javascript code and the resources. The problem is the resources are quite numerous and diverse (sounds, sprites, etc.) and The client needs them all to play.
I am looking for a way to send them all without naming them specifically.
I tried the glob module :
var glob = require( 'glob' );
var files = glob.sync( './html5game/**' ).forEach( function( file ) {
require( path.resolve( file ) );
});
but I can't figure a way to send the files using res.sendFile() once I did that.
I tried
var express = require('express');
var app = express();
[...]
app.get('/aeronavale/jeu', function(req, res){
res.sendFile(__dirname + '/aeronavale/index.html');
res.sendFile(files)
});
[...]
app.listen(3000, function(){
console.log('app started on port 3000, yeah !')
})
but it gives me the error :
TypeError: path argument is required to res.sendFile
If you have an other solution, I a also interested. Thanks for your answers !
You will not be able to send multiple file like that with res.sendFile. The most straightforward thing that you can do here would be this:
Put your index.html file and your html5game directory into some common directory, e.g. called html and put it where you have your Node.js program. An example directory layout would be:
/home/you/yourapp:
- app.js (your node program)
- package.json (your package.json etc)
- html (a new directory)
- index.html (your main html to serve)
- html5game (the directory with other files)
- (other files)
Now, in your Node program you can use something like this:
var path = require('path');
var express = require('express');
var app = express();
var htmlPath = path.join(__dirname, 'html');
app.use(express.static(htmlPath));
var server = app.listen(3000, function () {
var host = 'localhost';
var port = server.address().port;
console.log('listening on http://'+host+':'+port+'/');
});
This will serve all of your files (including index.html) on addresses like:
http://localhost:3000/ (your index.html)
http://localhost:3000/html5game/xxx.js (your assets)
Of course you still need to make sure that you refer to your assets in your index.html file correctly, for example with:
<script src="/html5game/xxx.js"></script>
in the case of the example layout above.
The top level directory with your static assets (where you have your index.html) is usually called static, public or html but you can call it whatever you like, as long as you use the correct path in your call to express.static().
If you want to have your game available in some path other than the root path then you can specify it to app.use. For example if you change this:
app.use(express.static(htmlPath));
to this:
app.use('/game', express.static(htmlPath));
Then instead of those URLs:
http://localhost:3000/ (your index.html)
http://localhost:3000/html5game/xxx.js (your assets)
those URLs will be available instead:
http://localhost:3000/game/ (your index.html)
http://localhost:3000/game/html5game/xxx.js (your assets)
A lot of questions here are related to serving static files with Express so I made a working example and posted it on GitHub so that people could have a working starting point and go from there:
https://github.com/rsp/node-express-static-example
See also some other answers where I talk about it in more detail:
How to serve an image using nodejs
Failed to load resource from same directory when redirecting Javascript
onload js call not working with node
Loading partials fails on the server JS
Node JS not serving the static image
The workaround for this is to compress the directory using the archiver library and uncompress it on the front end.
I am writing a "todolist" application. In my node.js code I make use of express and give it access to my folder called Client:
var app = express();
app.use(express.static(__dirname + "/Client"));
In my Client folder is the following:
codeJS.js
homepage.html
Todolistpage.html
style.css
logo.jpg
How can I prevent a user to not be able to view my Todolistpage.html file when they type in localhost:3000/Todolistpage.html (without removing Todolistpage.html from my Client folder)?
(Ideally later on I try to only allow users logged in to view it)
It's probably easier if you don't serve the file statically and handle it as part of the view logic. So you would just remove it from the public directory and handle it separately with app.get() or router.get() middleware. Is there a reason why you need to serve it statically?
You could do something like this:
var app = express();
app.get('/Todolistpage.html, function(req, res) {
return res.status(401).end();
});
app.use(express.static(__dirname + '/Client');
This isn't ideal as you'll have to change it anytime the file name changes, and have to do it individually for each file.
You could also have a different directory /secure and some middleware for user auth like:
app.use('/secure', someAuth, express.static(__dirname + '/secure'));
or even...
app.use('/secure', someAuth, express.static(__dirname + '/Client/secure'));
but that seems confusing to me.
I'm trying to build a simple chat app using node and socket.io. I am following the tutorial listed here: http://socket.io/get-started/chat/
My issues is that the tutorial has some javascript that is placed in a script tag directly in the html. I would like to move this code into it's own js file.
I made a file called chat.js, that is in the same directory as my index.html and index.js. In my html I put the following code in the header (I also tried right before the ending body tag too)
<script type="text/javascript" src="chat.js"></script>
However, when I run node index.js in terminal and go to localhost, I get a 400 for chat.js. I've tried placing "/chat.js" as well as "./chat.js" with no luck. All three files are in the same directory.
Any clues to what I am doing wrong will be appreciated.
My index.js
var app = require('express')();
var http = require('http').Server(app);
var io = require('socket.io')(http);
app.get('/', function(req, res){
res.sendFile(__dirname + '/index.html');
});
io.on('connection', function(socket){
socket.on('chat message', function(msg){
io.emit('chat message', msg);
});
});
http.listen(3000, function(){
console.log('listening on *:3000');
});
node.js does not automatically serve any files like other web servers do. If you want it to send chat.js when the browser requests it, you will have to create a route for it in your node.js code so that the web server will send it.
If you use something like the Express framework, this can be done in perhaps one line of code with app.use(express.static(...)).
Notice how in the demo you linked to, there's a specific route for the / path. You need a similar route for /chat.js or you could use app.use(express.static(...)) to configure the automatic serving of a whole directory of files.
In the future, if you show your actual server code, then we could help more specifically with actual code that fits into your server.
Now that you've shown your code, you could add a specific route for /chat.js:
app.get('/chat.js', function(req, res){
res.sendFile(__dirname + '/chat.js');
});
Or, if you move chat.js to be in a public sub-directory under your app code, then you could serve all files in that directory automatically with this:
app.use(express.static('public'));
When Express gets a request for a route that doesn't have a specific handler, it will check the public sub-directory to see if a file matches the request name. If so, it will automatically serve that file.