Cannot load css file in ejs file - node.js

I am using an ejs file which is supposed to include a css file for styling, but the css file wouldn't load. Can someone help me resolve the issue. The server only loads the html view, but not css, despite using express.static() to serve the static files.
signup.ejs:
<!DOCTYPE html>
<html>
<head>
<title>Hostel</title>
<link rel="stylesheet" type="text/css" href="../assets/css/signup.css">
<link href="https://fonts.googleapis.com/css2?family=Jost:wght#500&display=swap" rel="stylesheet">
</head>
<body>
<div class="main">
<input type="checkbox" id="chk" aria-hidden="true">
<div class="signup">
<form>
<label for="chk" aria-hidden="true">Sign up</label>
<input type="text" name="txt" placeholder="User name" required="">
<input type="email" name="email" placeholder="Email" required="">
<input type="password" name="pswd" placeholder="Password" required="">
<button>Sign up</button>
</form>
</div>
<div class="login">
<form>
<label for="chk" aria-hidden="true">Login</label>
<input type="email" name="email" placeholder="Email" required="">
<input type="password" name="pswd" placeholder="Password" required="">
<button>Login</button>
</form>
</div>
</div>
</body>
</html>
app.js:
const express=require("express");
const connectDB = require("./db");
const app=express();
const path=require("path");
const userRouter=require("./routes/users");
app.use(express.json());
const port=process.env.PORT || 3000;
connectDB();
app.set('views', path.join(__dirname, '/views'));
app.set("view engine", "ejs");
app.use('/css', express.static(path.resolve(__dirname, "assets/css")));
app.use('/js', express.static(path.resolve(__dirname, "assets/js")));
app.use("/",(req,res,next)=>{
res.render("signup");
});
app.use("/users",userRouter);
app.listen(port,()=>{
console.log(`Server running on port ${port}`);
});
Folder Structure:
server
|
|->assets/css/signup.css
|->views/signup.ejs
|->app.js
Thank you in advance

Problem
The URLs in your HTML page don't match the express.static() middleware you have.
So, for example, when you have this:
<link rel="stylesheet" type="text/css" href="../assets/css/signup.css">
That's going to combine the path and domain of of the page URL to formulate a request to your server for something like:
/assets/css/signup.css
But, you don't have a route that matches that. You have this:
app.use('/css', express.static(path.resolve(__dirname, "assets/css")));
But, that requires a path that starts with /css and you have no route that starts with /assets.
Solution
So, drop the reference in the HTML page to /assets. That's an internal (to your server) location that the HTML page doesn't need to know anything about. In fact, you can technically change that on your server without breaking or changing the web page.
So, change your HTML tag to this:
<link rel="stylesheet" type="text/css" href="/css/signup.css">
This is an absolute path URL and will send a request for:
/css/signup.css
That will match your route here:
app.use('/css', express.static(path.resolve(__dirname, "assets/css")));
The /css part of the URL will match the app.use('/css', ...) route and after removing the /css part from the path, it will then look for the remaining page of the URL signup.css in the path.resolve(__dirname, "assets/css") directory.

Related

What is the issue here in serving static files

const express = require('express');
const path = require('path');
const app = express();
// Use static folder middleware
app.use(express.static(path.join(__dirname , "public")));
// Get
app.get("/" , (req , res)=>{
res.sendFile(`${__dirname}/index.html`);
});
// Listen
app.listen(3000 , ()=>{
console.log('server running on port 3000');
});
Folder structure
Root
-index.html
-app.js
public
-css
-index.css
-images
-image.png
In the index.html page The index.css file and the image.png are linked.
However, Those two are not being server as static files in app.js. But I have included the middle for serving static folders.
can some one explain what is the issue
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="description" content="">
<meta name="author" content="Mark Otto, Jacob Thornton, and Bootstrap
contributors">
<meta name="generator" content="Hugo 0.82.0">
<title>Sign up</title>
<link rel="canonical"
href="https://getbootstrap.com/docs/5.0/examples/sign-in/">
<!-- Bootstrap core CSS -->
<link href="https://cdn.jsdelivr.net/npm/bootstrap#5.0.0-
beta3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-
eOJMYsd53ii+scO/bJGFsiCZc+5NDVN2yr8+0RDqr0Ql0h+rP48ckxlpbzKgwra6"
crossorigin="anonymous">
<!-- Favicons -->
<link rel="apple-touch-icon" href="/docs/5.0/assets/img/favicons/apple-
touch-icon.png" sizes="180x180">
<link rel="icon" href="/docs/5.0/assets/img/favicons/favicon-32x32.png"
sizes="32x32" type="image/png">
<link rel="icon" href="/docs/5.0/assets/img/favicons/favicon-16x16.png"
sizes="16x16" type="image/png">
<link rel="manifest" href="/docs/5.0/assets/img/favicons/manifest.json">
<link rel="mask-icon" href="/docs/5.0/assets/img/favicons/safari-pinned-
tab.svg" color="#7952b3">
<link rel="icon" href="/docs/5.0/assets/img/favicons/favicon.ico">
<meta name="theme-color" content="#7952b3">
<style>
.bd-placeholder-img {
font-size: 1.125rem;
text-anchor: middle;
-webkit-user-select: none;
-moz-user-select: none;
user-select: none;
}
#media (min-width: 768px) {
.bd-placeholder-img-lg {
font-size: 3.5rem;
}
}
</style>
<!-- Custom styles for this template -->
<link href="./public/css/index.css" rel="stylesheet">
</head>
<body class="text-center">
<main class="form-signin">
<form action="/" , method="POST">
<img class="mb-4" src="./public/images/image.png" alt="" width="72"
height="57">
<h1 class="h3 mb-3 fw-normal">Sign Up</h1>
<div class="form-floating">
<input type="text" name="fname" class="form-control top"
id="firstName" placeholder="first name">
<label for="firstName">First Name</label>
</div>
<div class="form-floating">
<input type="text" name="lname" class="form-control middle" id="lastName" placeholder="last name">
<label for="firstName">Last name</label>
</div>
<div class="form-floating">
<input type="email" name="email" class="form-control bottom" id="email" placeholder="inkey#email.com">
<label for="email">Email ID</label>
</div>
<button class="w-100 btn btn-lg btn-primary" type="submit">Sign in</button>
<p class="mt-5 mb-3 text-muted">© 2020–2021</p>
</form>
</main>
</body>
</html>
This is the html page taken from bootstrap
The css file under the comment custom styles for this template
and the png is below the form tag.
The files are added correct as when the html page is seen in the browser independently then the image and css is showing up
However when it is served using node and express the image and css arent showing up
OK, So I am answering my own question here.
After refering to #jdmayfield 's answer and searching about MIME type errors I reached link to this link.
I realised that when you set the pubic folder as static in node, Then that public folder should not be added in the path to css or images in html
Meaning that
In the folder structure given above if we want to link css in html the code we use is
<link href="./public/css/index.css" rel="stylesheet">
And this gave me a MIME type error.
So I changed the above code to
<link href="css/index.css" rel="stylesheet">
This worked.
However if You independently open the HTML file by going live in vscode, the css and images wont load. But when served with node they will be served.
UPDATED POST:
In light of the recent comment by #Nav giving the error regarding mime-type, here is a snippet I found at Express: Setting content-type based on path/file?
"The Express documentation shows that it can do this if you pass in the
file name."
var filePath = 'path/to/image.png';
res.contentType(path.basename(filePath));
// Content-Type is now "image/png"
Try this example first. If that does not work, reload and check Dev console for different errors. It is possible there is more than one cause of your issue.
ORIGINAL POST:
Based on the code you have submitted, I think your problem is the default CORS policy. You need to incorporate a method of allowing Cross-Origin Resource Sharing between the domains, ports, and protocols you are using. I found a good document detailing CORS explicitly, but succinctly, with a solution that appears specifically suited to your needs. You might open the Dev console in your browser and look for similar error messages as outlined in the document to confirm.
Here's the link:
https://flaviocopes.com/express-cors/

Node.js (express framework): Post method not working

I am able to run the Get method and HTML form also visible on browser using Get method but when I am clicking on submit button nothing is happening, no error nothing. it shows the same HTML form page.
HTML code:
<!DOCTYPE html>enter code here
<html lang="en" dir="ltr">
<head>
<meta charset="utf-8">
<title>Calculator</title>
</head>
<body>
<form action="/" method="post">
<h1>Calculator</h1>
<input type="text" name="num1" placeholder="Number 1">
<input type="text" name="num2" placeholder="Number 2">
<button action="/" type="button" name="button">Submit</button>
</form>
</body>
</html>
Node Js code:
//jshint esversion:6
const express=require("express");
const app=express();
app.get("/", function(req,res){
res.sendFile( __dirname+"/index.html");
});
app.post("/", function(req,res){
res.send("Thanks for post");
});
app.listen(3000, function(){
console.log("Server Started On Port 3000");
});
Your button type should be Submit
<button type="submit" value="Submit">Calculator</button>

GET method form with ExpressJS - multiple app.get

I want to make a simple login form.
This is the relevant code:
app.get('/login' , (req,res)=>{
app.use(express.static('login'));
res.render(__dirname + '/login/index.ejs');
/*This is load the login page*/
});
index.ejs:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>login</title>
</head>
<body>
<h1>Login</h1>
<form action="/" method="GET">
<input type="text" name="email" placeholder="email">
<input type="password" name="password" placeholder="password">
<input type="submit" value="login">
</form>
</body>
</html>
You can see the form is GET method because I don't create/update anything. If I used app.post for detecting the parameters I've used app.post and it was working fine.
But how I handle two app.get ? one for load the page, the second for handle the html form ?
For example:
app.get('/login' , (req,res)=>{
console.log(req.query);
}
Thanks !
I recommend that instead of using the GET method for both the login and the displaying of your website you make your form method POST instead of GET. Then use multer in your express app as a way to parse the received form data.
<form action="/" method="POST">
const multer = require('multer');
const upload = multer();
app.use(upload.array());
app.post('/login', function(req, res){
console.log(req.body);
res.send("recieved your request!");
});

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.

react onSubmit not working using react + express

My onSubmit function is not working with a website I made using a bootstrap template, specifically this one https://wrapbootstrap.com/theme/unify-responsive-website-template-WB0412697. It just refreshes the page, deleting whatever is in there. I have tried all combinations of the following:
Replacing onSubmit with onSuccess.
Moving my function inside the render before the return statement.
Adding parentheses to the handleSubmit function within the
Replacing e.preventDefault() with e.stopPropagation()
I am using nodejs, express and react, and am new to all 3.
I find it worth mentioning that I do not require('react-dom') nor use ReactDOM anywhere, which is weird to me because I always used it when I did the tutorials to learn react.
I believe I have read every similar problem on stack overflow, but nothing seems to be working. Here are my files in the order in which they are executed
app.js
var routes = require('./routes/index');
app.use('/', routes);
routes/index.js file
var express = require('express');
var router = express.Router();
router.get('/', function(req, res, next) {
res.render('index');
});
module.exports = router;
views/index.fsx jsx
var React = require('react');
var LoginForm = React.createClass({
getInitialState: function() {
return {username: '', password: ''};
},
handleUsernameChange: function(e) {
this.setState({username: e.target.value});
},
handlePasswordChange: function(e) {
this.setState({password: e.target.value});
},
handleSubmit: function(e) {
e.preventDefault();
},
success : function () {
alert('Success');
},
fail : function () {
alert('Fail');
},
render: function() {
return (
<form onSubmit={this.handleSubmit} className="loginForm">
<div className="input-group">
<input type="text" className="form-control" placeholder="Username" value={this.state.username} onChange={this.handleUsernameChange} required autofocus />
<input type="password" className="form-control" placeholder="Password" value={this.state.password} onChange={this.handlePasswordChange} required />
<button type="submit" className="btn-u btn-u-lg col-xs-12 col-sm-offset-5 col-md-offset-1 col-lg-offset-2">
Sign in <i className="fa fa-sign-in" />
</button>
</div>
</form>
);
}
});
var Welcome = React.createClass({
render: function() {
return (
<html>
<head>
<link rel='stylesheet' type='text/css' href='//fonts.googleapis.com/css?family=Open+Sans:400,300,600&subset=cyrillic,latin' />
<link rel="stylesheet" href="assets/plugins/bootstrap/css/bootstrap.min.css" />
<link rel="stylesheet" href="assets/css/style.css" />
<link rel="stylesheet" href="assets/css/headers/header-default.css" />
<link rel="stylesheet" href="assets/css/footers/footer-v1.css" />
<link rel="stylesheet" href="assets/plugins/line-icons/line-icons.css" />
<link rel="stylesheet" href="assets/plugins/font-awesome/css/font-awesome.min.css" />
<link rel="stylesheet" href="assets/plugins/sky-forms-pro/skyforms/css/sky-forms.css" />
<link rel="stylesheet" href="assets/plugins/sky-forms-pro/skyforms/custom/custom-sky-forms.css" />
<link rel="stylesheet" href="assets/css/pages/page_search.css" />
<link rel="stylesheet" href="assets/css/theme-colors/teal.css" id="style_color" />
<link rel="stylesheet" href="assets/css/theme-skins/dark.css" />
<link rel="stylesheet" href="assets/css/custom.css" />
<link rel="stylesheet" href="assets/css/homepage-style.css" />
</head>
<body>
<div>
<LoginForm />
</div>
<script type="text/javascript" src="assets/plugins/jquery/jquery.min.js" />
<script type="text/javascript" src="assets/plugins/jquery/jquery-migrate.min.js" />
<script type="text/javascript" src="assets/plugins/bootstrap/js/bootstrap.min.js" />
<script type="text/javascript" src="assets/plugins/back-to-top.js" />
</body>
</html>
);
}
});
module.exports = WelcomePage; // I'm not entirely sure what module.exports does
You need to change e.stopPropagation(); with e.preventDefault(); This will stop the page refresh.
Also,
stopPropagation stops the event from bubbling up the event chain.
preventDefault prevents the default action the browser makes on that event.
Move your html code in a separate file and render your app like the jsfiddle example that I created for you. https://jsfiddle.net/antony_z/7jLqxm2p/
Maybe try adding .bind(this) to this.handleSubmit, to have this.handleSubmit.bind(this)
Keep :
onSubmit
e.preventDefault()
I am attempting to answer my own question here because it was too long for a comment. But regarding your suggestion to put my HTML in it's own file...
My view engine is setup for jsx files. I am going to try what you did by doing this:
npm install consolidate
npm install swig
In app.js I will put:
var cons = require('consolidate');
at the top. Then for my view engine setup I will configure it like:
app.engine('html', cons.swig);
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'html');
So now how do I setup my routes/index.js file? I'm guessing it should be something like:
var express = require('express');
var router = express.Router();
router.get('/', function(req, res) {
res.render('index');
});
So now I will have to create views/index.html (rather than views/index.jsx like before). I inserted the HTML from your JSfiddle into the index.html file, but where do I put the code containing the LoginForm and ReactDOM stuff? I think I would be able to create a file in public/js/welcome-page.jsx and then include it at the bottom, but then other people can see my react code and onSubmit function, which is insecure right?

Resources