Referencing external files with a node.js server? - resources

I have an Ubuntu 10.04 hosting server which allows me to run node.js off of it. I'm making an test homepage and I have a few files as follows:
index.html:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>iSuperMario</title>
<link rel="stylesheet" href="css/reset.css">
<link rel="stylesheet" href="css/style.css">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.5.2/jquery.min.js"></script>
<script src="/nowjs/now.js"></script>
<script src="js/chat.js"></script>
</head>
<body>
<div id="wrapper">
<div id="header">
<img src="images/green_pipe_960.png">
<img src="images/orange_pipe_960.png">
</div>
<div id="chat">
<input type="text" id="text-input">
<input type="button" value="Send" id="send-button">
</div>
<div id="content">
</div>
<div id="rooms">
</div>
</div>
</body>
</html>
reset.css and style.css (which both just contain styling for the index.html page
chat.js (which contains some scripting to implement the barebones chat function for the index.html page)
server.js which is a node.js server utilizing nowjs to serve the index.html page on port 8080 of the Ubuntu server and to implement the chat function:
var fs = require('fs');
var server = require('http').createServer(function(req, response){
fs.readFile(__dirname+'/index.html', function(err, data){
response.writeHead(200, {'Content-Type':'text/html'});
response.write(data);
response.end();
});
});
server.listen(8080);
var everyone = require("now").initialize(server);
everyone.connected(function(){
console.log("Someone has joined!");
});
everyone.disconnected(function(){
console.log("Someone has left...");
});
everyone.now.distributeMessage = function(message){everyone.now.receiveMessage(message);};
So, when I view the page from the server in a browser, none of the external resources (reset.css, style.css, chat.js, green_pipe_960.png and orange_pipe_960.png) are connected properly.
How should I enable these? I mean, if I had to, and it simplified the process a great deal, I could always include the external styles and scripts in index.html. But, the images could never be embedded (at least I think xD).
Thanks!

You need to set your file structure as follows
= main
= index.html
= css
= reset.css
= style.css
= js
= chat.js
= images
= green_pipe..
= orange_pipe..
Alternatively you can change your urls to match your real file structure.
I would like to recommend you use express or something else if you want to server something beyond a very basic prototype.

This webpage might help. Serving Static Files from Node.js.

Related

Node is serving my html file in place of my bootstrap css and js files

I'm trying to serve bootstrap locally via npm-installed package.
However, Node is serving my html file in place of my bootstrap CSS and JS files. This is perplexing to me.
I'm specifying both folders to express.static to ensure they are accessible publicly:
app.use(express.static(path.join(__dirname,"public")));
app.use(express.static(path.join(__dirname, "node_modules")));
Here is my directory tree structure:
.
├── Assets
│   ├── 11-express-homework-demo-01.png
│   └── 11-express-homework-demo-02.png
├── Develop
│   ├── db
│   ├── node_modules
│   ├── package-lock.json
│   ├── package.json
│   ├── public
│ ├── notes.ejs
│ ├── index.html
│   ├── server.js
│   └── views
├── README.md
└── result.txt
wherein
server.js is where I'm running express from,
node_modules is where bootstrap lives (default npm installation can be assumed)
and in both notes.ejs and index.html, I have the following resources included:
<link type="text/css" rel="stylesheet" href="/node_modules/bootstrap/dist/css/bootstrap.min.css" >
<script type="script" src="/node_modules/bootstrap/dist/js/bootstrap.bundle.min.js"></script>
index.html is simply a static landing page and notes.ejs is the app's main user-interactive screen.
index.html is as follows:
<!DOCTYPE html>
<html lang="en-US">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Note Taker</title>
<link type="text/css" rel="stylesheet" href="/node_modules/bootstrap/dist/css/bootstrap.min.css" >
</head>
<body>
<nav class="navbar bg-info">
<a class="navbar-brand text-light p-3" href="/">Note Taker
</a>
</nav>
<div class="container">
<div style="margin-top: 80px;" class="text-center p-5 mb-4 bg-light">
<h1 class="display-4">Note Taker <span role="img" aria-label="Memo">📝</span></h1>
<h4 class="mt-4">Take notes with Express</h4>
<a class="btn btn-primary btn-lg mt-4" href="/notes" role="button">Get Started</a>
</div>
</div>
<script type="script" src="/node_modules/bootstrap/dist/js/bootstrap.bundle.min.js"></script>
</body>
</html>
notes.ejs is as follows:
<!DOCTYPE html>
<html lang="en-US">
<head>
<meta charset="UTF-8" >
<meta name="viewport" content="width=device-width, initial-scale=1.0" >
<meta http-equiv="X-UA-Compatible" content="ie=edge" >
<meta http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate">
<meta http-equiv="Pragma" content="no-cache">
<meta http-equiv="Expires" content="0">
<title>Note Taker</title>
<link
rel="stylesheet"
href="https://use.fontawesome.com/releases/v5.3.1/css/all.css"
integrity="sha384-mzrmE5qonljUremFsqc01SB46JvROS7bZs3IO2EmfFsd15uHvIt+Y8vEf7N7fWAU"
crossorigin="anonymous"
>
<link type="text/css" rel="stylesheet" href="/node_modules/bootstrap/dist/css/bootstrap.min.css" >
</head>
<body>
<nav class="navbar bg-info">
<a class="navbar-brand text-light p-3" href="/">Note Taker </a>
<div class="icons">
<i class="fas fa-save text-light save-note"></i>
<i class="fas fa-plus text-light new-note"></i>
</div>
</nav>
<div class="container-fluid">
<div class="row">
<div class="col-4 list-container">
<div class="card">
<ul class="list-group list-group-flush">
<%- titles %>
<!-- https://stackoverflow.com/a/33701518/9095603 -->
</ul>
</div>
</div>
<div class="col-8">
<input
class="note-title form-control form-control-lg"
placeholder="Note Title"
maxlength="28"
type="text"
>
<textarea class="note-textarea" class="form-control" placeholder="Note Text" style="min-width: 100%"></textarea>
</div>
</div>
</div>
<script type="script" src="/node_modules/bootstrap/dist/js/bootstrap.bundle.min.js"></script>
</body>
</html>
Addendum - also in case you needed to see my server.js:
// This application uses the Express.js framework to create a REST API that allows clients to perform CRUD (create, read, update, delete) operations on notes stored in a JSON file. The API has three endpoints:
// - `GET /notes` retrieves a list of all notes stored in the `notes.json` file.
// - `POST /notes` adds a new note to the list of notes stored in the `notes.json` file. The new note data is passed in the request body as JSON.
// - `DELETE /notes/:id` deletes a note from the list of notes stored in the `notes.json` file. The ID of the note to delete is passed in the URL as a path parameter.
const express = require("express");
const path = require("path");
const fs = require("fs");
// const bootstrap = require('bootstrap')
// import 'bootstrap/dist/css/bootstrap.css';
const app = express();
const PORT = 3001;
// EJS (alternatively use Pug for dynamic HTML)
// https://www.youtube.com/watch?v=yXEesONd_54
// register view engine
app.set("view engine", "ejs");
// inform ejs which is your views folder because you don't use the default folder name views, but rather 'public'
app.set("views", path.join(__dirname,"public"));
app.use(express.static(path.join(__dirname,"public")));
app.use(express.static(path.join(__dirname, "node_modules")));
var titles = "";
app.get("/notes", (req, res) => {
fs.readFile("db/db.json", "utf-8", (err, data) => {
if (err) {
res.status(500).send({ error: "Could not read file" });
} else {
data = JSON.parse(data);
// res.send(JSON.parse(data));
if (data) {
console.log(typeof data);
console.log(data);
for (let i = 0; i < data.length; i++) {
titles += `<li class="list-group-item">${data[i].title}</li>`;
}
console.log(titles);
}
}
});
// res.sendFile(path.join(__dirname,'public/notes.html'))
res.render("notes", { titles });
// render: https://youtu.be/yXEesONd_54?t=597
});
app.use((req, res) => {
res.sendFile(path.join(__dirname, "public/index.html"));
});
// app.get('/', (req, res) => {
// res.render('index', { title: 'some title'})
// })
app.listen(PORT, () => console.log(`Server is running on port ${PORT}`));
I have tried the above to no avail. In place of the linked bootstrap CSS file and the bootstrap JS file, it's serving my html file. I don't understand what is happening.
Precisely because you have specified
app.use(express.static(path.join(__dirname, "node_modules")));
Then your link and script tags should not include /node_modules/ at the front of your resource paths.
That is, currently you have:
<link type="text/css" rel="stylesheet" href="/node_modules/bootstrap/dist/css/bootstrap.min.css" >
<script type="script" src="/node_modules/bootstrap/dist/js/bootstrap.bundle.min.js"></script>
Instead try:
<link type="text/css" rel="stylesheet" href="bootstrap/dist/css/bootstrap.min.css" >
<script type="script" src="bootstrap/dist/js/bootstrap.bundle.min.js"></script>
That should solve your problem. As for the logic of why the html file is loaded instead of the css and js files when you do it your original way, someone else can comment on that, because I'm not sure.

EJS include as wrapper

Can I include another .ejs file that will wrap the current content?
I want to have a general layout like this:
layout.js:
<!DOCTYPE html>
<html>
<head>
</head>
<body>
<div id="header"></div>
<div id="content">
<!-- I want to "inject" my code here -->
</div>
</body>
</html>
and I want to use this template from another file, like this:
content.ejs
<% inside(layout) ? { %>
content
<% } %>
Can I do something like this?
I'm currently doing this the other way around, I call layout with a parameter include_name but it's a little inconvenient. I would like to call the relevant content.ejs which includes the generic content itself. Is this possible?
Thanks,
From EJS Documentation:
EJS does not specifically support blocks, but layouts can be
implemented by including headers and footers, like so:
<%- include('header') -%>
<h1>
Title
</h1>
<p>
My page
</p>
<%- include('footer') -%>
Although some frameworks have some facilities to deal with problem. for example Express until version 3.x had layout support and for latest versions you could use it as a stand alone npm package: express-partials
With this package in place you define a <%- body %> region in your skeleton template (layout.ejs) and when you call your desired layout (content.ejs), express will render layout.ejs with content.ejs as <%- body %> ( unless you set {layout:false} which then it only renders content.ejs):
layout.ejs
<!DOCTYPE html>
<html>
<head>
</head>
<body>
<div id="header"></div>
<div id="content">
<%- body %>
</div>
</body>
</html>
content.ejs
content
app.js
var express = require('express')
, partials = require('express-partials')
, app = express();
// load the express-partials middleware
app.use(partials());
app.get('/',function(req,res,next){
res.render('content.ejs')
// -> render layout.ejs with content.ejs as `body`.
})
app.listen(3000);

Localhost test: can't get resource using http://localhost:8888

For test purposes I run Apache local web server and I'm setting up a node.js app listening on port 8888 serving as image preprocessor, but unfortunately I'm experiencing problems as described below.
The node app.js is running in the web root directory:
'use strict';
let express= require('express')
,multer = require('multer')
,upload = multer()
,app = express()
//Import imgProcessor module which we would implement later
,imgProc = require('./imgProcessor');
app.get ('/', (req, res, next)=>{
res.sendFile(__dirname+'/appmain.html');
});
app.post('/uploadImg', upload.array('pics'),
(req, res, next)=>{
//Call the convertImgs method and pass the image files as its argument
imgProc.convertImgs(req.files).then(
(imageStringArray)=>{
//After all image processing finished, send the base64 image string to client
res.json(imageStringArray)})});
app.listen(8888, ()=>{
console.log('Hosted on Port 8888')});
The appmain.html page resides in the same web root directory:
<html>
<head>
<title>Upload Image Demo</title>
<link rel="shortcut icon" href="">
<script src="node_modules/jquery/dist/jquery.min.js"></script>
<script src="node_modules/materialize-css/dist/js/materialize.min.js"></script>
<link rel="stylesheet" href="node_modules/materialize-css/dist/css/materialize.min.css">
</head>
<body class="container">
<div class="row">
<form id="form1" class="col m4 offset-m4" action="/uploadImg" enctype="multipart/form-data" method="post">
<div class="file-field input-field">
<div class="btn">
<span>File</span>
<input type="file" multiple="" accept="image/jpeg,png" name="pics">
</div>
<div class="file-path-wrapper">
<input class="file-path validate" type="text" placeholder="Upload one or more files">
</div>
</div>
<div class="input-field">
<button type="submit" class="waves-effect waves-light btn">Submit</button>
</div>
<div class="progress" style="display:none">
<div class="indeterminate"></div>
</div>
</form>
</div>
<div class="row img-preview"></div>
<script>
$(function(){
$('#form1').on('submit', function(event){
event.preventDefault();
var data = new FormData(this);
$.each(
$('input[name="pics"]')[0].files,
function(i, file){
data.append('file-'+i, file);
});
$('.progress').css({
display:'block'
});
$.ajax({
type:'POST',
url: $(this).attr('action'),
data:data,
cache:false,
contentType: false,
processData: false,
success:function(data){
for(var i=0;i<data.length;i++){
var template =
'<div class="col m4">
<div class="card">
<div class="card-image">
<img src="'
+ data[i]
+ '"></div></div></div>';
$('.img-preview').append(template);
}
$('.progress').css({
display:'none'
});
},
error: function(err){
$('.progress').css({
display:'none'
});
}
});
})
})
</script>
</body>
</html>
When I use the URL http://localhost:8888 in the browser the html page is loaded (i.e. I can see the buttons and input fields of the form) but the resources requested in the <script> (ex.: node_modules/jquery/dist/jquery.min.js or node_modules/materialize-css/dist/js/materialize.min.js) are not loaded. By the same way the page can't benefit from the unloaded CSS stylesheet.
As opposite, if I try to use the URL http://localhost/appmain.html the page is loaded as expected (I mean: with the correct resources and CSS).
It seems that my Apache Web Server can't serve resources when handling the port number inside the URL. How can I resolve this?
EDIT
Just to simplify: let'say the node app2.js is listening on port 8888 and it has just a method (get) that send to the client the 'Hello World!' page app2main.html. No files to serve. The app2main.html page need only to load a couple of Javascript script and a CSS stylesheet.
app2.js
'use strict';
let express= require('express')
,app = express();
app.get ('/', (req, res, next)=>{
res.sendFile(__dirname+'/app2main.html');
});
app.listen(8888, ()=>{
console.log('Hosted on Port 8888')});
app2main.html
<html>
<head>
<title>Upload Image Demo</title>
<link rel="shortcut icon" href="">
<script src="node_modules/jquery/dist/jquery.min.js"></script>
<script
src="node_modules/materialize-css/dist/js/materialize.min.js"></script>
<link rel="stylesheet"
href="node_modules/materialize-css/dist/css/materialize.min.css">
</head>
<body class="container">
<h2> Hello World! </h2>
</body>
</html>
When accessing the URL http://localhost:8888 the 'Hello World!' message appears, but I get the following error (visibile by inspecting the page):
http://localhost:8888/node_modules/jquery/dist/jquery.min.js Failed to load resource: the server responded with a status of 404 (Not Found)
http://localhost:8888/node_modules/materialize-css/dist/js/materialize.min.js Failed to load resource: the server responded with a status of 404 (Not Found)
http://localhost:8888/node_modules/materialize-css/dist/css/materialize.min.css Failed to load resource: the server responded with a status of 404 (Not Found)
http://localhost:8888/node_modules/materialize-css/dist/css/materialize.min.css Failed to load resource: the server responded with a status of 404 (Not Found)
Instead I get no error (and the expected style) when accessing the URL http://localhost/app2main.html
As discussed in comments, you should use express.static to serve static content in node.js app. In your case, your static content lies in node_modules directory itself. You can try the following code to load all resources,
e.g. http://localhost:8888/node_modules/jquery/dist/jquery.min.js
app.use('/node_modules', express.static('node_modules'));
Also, you mentioned that when you access http://localhost/app2main.html, then it worked without express.static, because apache web server to serve static files similar to express.static in node.js. That's why
http://localhost/node_modules/jquery/dist/jquery.min.js was working.
Hope it clears your doubt.

Connection-route of node.js taking wrong parameters informations

I've a problem with my node.js application.
I'm using the packages connection, connection-route, socket.io and ejs.
My application provides informations to the html page (connected via socket.io), these informations are managed by an ejs template.
When I reach a destination with a parameter, like http://localhost:5001/machine/:id2, something strange happens.
The connection route code is the following:
router.get('/machine/:mac_id', function (req, res, next) {
var mac_index = req.params.mac_id.slice(1,req.params.mac_id.length);
console.log(mac_index);
res.writeHead(200, { 'Content-Type': 'text/html' });
var str = mod_fs.readFileSync(mac_route + '/index.html', 'utf8') ;
var ret = mod_ejs.render(str, {
filename: mac_route,
title: "Machine Overview",
/* other informations */
});
res.end(ret);
}
The variable mac_route contains the path to the file index.html, which is loaded correctly.
The problem lies in the mac_index variable. On the console are printed 3 rows:
id2
unctions.js
query-1.9.1.js
The first row is obviously correct, the last 2 rows are obviously not correct, infact these are two javascript files (my file functions.js and the file for jquery jquery-1.9.1.js).
These files are included in the header of the index.html file.
HTML STRUCTURE:
header.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title> <%= title %> </title>
<link rel='stylesheet' href='/style.css' type="text/css"/>
<script src="http://localhost:5001/socket.io/socket.io.js"></script>
<script language="javascript" type="text/javascript" src="functions.js"></script>
<script language="javascript" type="text/javascript" src="jquery-1.9.1.js"></script>
</head>
<body>
<div id="header">
...
</div>
<div id="page">
index.html
<% include /header.html %>
<div id="commands">
...
</div>
<div id="main">
... code of the page, manage informations received ...
</div>
<% include /footer.html %>
footer.html
<div id="footer">
...
</div>
</div> <!-- Close the "page" div opened in the header //-->
</body>
</html>
I can't find where's the mistake.
Why the file's names are taken as parameter of the req object?
The normalized URL for those files is:
http://localhost:5001/machine/functions.js
http://localhost:5001/machine/jquery-1.9.1.js
Those match your route (/machine/:mac_id), so they will be handled by it.
Try including the connect.static middleware before your routes:
app.use(connect.static(__dirname));
(this assumes your Connect app is stored in the app variable and the JS files are in the same directory as your Node script; if not, change __dirname to point to the directory where the JS files are located).

ejs 'partial is not defined'

Okay I have a mostly static homepage but I wanted to have partial views that for navigation, footer ect. I'm using ejs and it looks like this:
my controller: home.js
// Dependencies
var express = require('express');
module.exports = {
get: function(req, res) {
app.set('view engine', 'ejs');
var model = {
layout:'home',
};
res.render('home');
}
};
My views directory has nav, home and footer all .ejs
Then the actual html file stripped of text would look as following.
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" >
<title>Tom Jones</title>
<!-- CSS -->
<link rel="stylesheet" href="/css/home.css" type="text/css" media="screen" >
</head>
<body>
<%- partial('nav') %>
<!--content part -->
<div id="showcontainer">
<section>
</section>
</div>
<div id="maincontainer">
<section>
</section>
</div>
</body>
</html>
The Problem
When ever I test it out I run into the error partial is not defined. I tried requiring ejs but no success.
As #Pickels said, Partial was removed in 3.x. However, the most recent version of EJS provides a mechanism for including "partials", called "include":
https://github.com/visionmedia/ejs#includes
Includes are relative to the template with the include statement, for example if you have "./views/users.ejs" and "./views/user/show.ejs" you would use <% include user/show %>. The included file(s) are literally included into the template, no IO is performed after compilation, thus local variables are available to these included templates.
The following will work as a replacement for your old partial() function. You'll need to make tweaks elsewhere to support Express 3.x completely, but for the most part this seems to work well (better actually - less code and more performant).
<% include nav.ejs %> <!-- replaces your old <%- partial('nav') %> -->
Now in ejs 3.1.x
<% include('relative_filepath'); %>
Must be replaced by
<%- include('relative_filepath'); %>
Partial was removed in 3.x. It's now up to the templating engine to provide partials.

Resources