Serving css files with nodejs - javascript

I am new to node js and trying to simply serve a site containing both an html and css file. I have the below code written
var http = require('http');
var fs = require('fs');
http.createServer((req, res) => {
res.writeHead(200, {'Content-Type': 'text/html'});
res.write(fs.readFileSync('./style.css', {encoding: "utf8"}));
res.write(fs.readFileSync('./index.html', {encoding: "utf8"}));
res.end();
}).listen(3000);
console.log('server running # 3000');
This 'works' when I fire up the server meaning that I can see the site rendering while considering the css, but the css text gets written out at the bottom of my site like its embedded text inside a div tag. Can anyone explain why I am seeing this? Also since I am new to nodejs, any recommendations on serving css or JS files on my server would be greatly appreciated.

I have modified your code (which is working). Have a look at it:
var http = require('http');
var fs = require('fs');
http.createServer((req, res) => {
console.log(req.url)
if (req.url === "/") {
fs.readFile('index.html', (err, html) => {
if (err) {
throw err;
}
res.setHeader('Content-type', 'text/html');
res.write(html);
res.statusCode = 200;
res.end();
});
}
else if (req.url == '/style.css') {
res.setHeader('Content-type', 'text/css');
res.write(fs.readFileSync('style.css'));
res.end();
} else {
res.write("invalid request")
res.end();
}
}).listen(3000);
console.log('server running # 3000');
Here is the HTML file:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
<link rel="stylesheet" href="/style.css" />
</head>
<body>
Hello
</body>
</html>
and style.css
body {
color: red;
}
You need to return your files based on your request. For example, in this scenario, the HTML file is requesting the server for /style.css, the server looks at the code and finds the block which deals with that request
else if (req.url == '/style.css') {
res.setHeader('Content-type', 'text/css');
res.write(fs.readFileSync('style.css'));
res.end();
}
And finally returns the file. I hope that helps.
Recommendation:
Use express.js (https://expressjs.com/).
It is really fast minimal and easy to use NodeJS routing framework which follows the MVC pattern. There are lots of resources on youtube and google for this framework.

Related

Having an issue while running html file using Nodejs

I watched a tutorial to run node.js server for the very first time on your computer. Luckly I've created the server but got stck as I tried to show the html content on the exact same server.
This is my index.js file code -
const http = require("http");
const fs = require("fs");
const port = 8020;
const server = http.createServer((req, res) => {
res.writeHead(200, { "Contet-type": "text/html" });
fs.readFile("index.html", (err, data) => {
if (err) {
res.writeHead(404);
res.write("Error file not found");
} else {
res.writeHead(data);
}
res.end();
});
});
server.listen(port, function (err) {
if (err) {
console.log("Something went wrong");
} else {
console.log("server listening on port " + port);
}
});
And this is what I'm getting in the terminal -
PS C:\Users\Dell\OneDrive\Desktop\New folder> node index.js
server listening on port 8020
node:_http_server:343
throw new ERR_HTTP_INVALID_STATUS_CODE(originalStatusCode);
^
RangeError [ERR_HTTP_INVALID_STATUS_CODE]: Invalid status code: <!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<h1>This is my first nodeJs project</h1>
</body>
</html>
at new NodeError (node:internal/errors:393:5)
at ServerResponse.writeHead (node:_http_server:343:11)
at C:\Users\Dell\OneDrive\Desktop\New folder\index.js:12:11
at FSReqCallback.readFileAfterClose [as oncomplete] (node:internal/fs/read_file_context:68:3) {
code: 'ERR_HTTP_INVALID_STATUS_CODE'
}
Node.js v18.12.1
PS C:\Users\Dell\OneDrive\Desktop\New folder>
And not even the localhost, which is 8020 in this case, is not running on the browser.
I just want to know the mistakes here that I'm totally unaware with or something that I need to do in order to have my desired output.
You're writing the HTML to the header of the response:
res.writeHead(data);
you want:
res.end(data);
or
res.write(data);
res.end();

Importing .js or .mjs files using Node webserver

I installed Node.js and wanted to run a webserver that would show an html+javascript page that imports javascript functions from other .js files.
Installing Node.js, running the webserver, and hosting a file locally all went very smoothly. But I keep having issues accessing the other .js files that I would like to import from test_functions.html.
I have been following various online tutorials, and looking around on stack overflow, trying it in several different ways, but can't get it to work. I am thinking I might need to adjust something in the server.js file to allow my browser to acces the other files I want to import?
Using .mjs extensions (instead of .js) I got my browser to recognise the functions I want to import, but it still doesn't manage to import the functions that I define in these .mjs files.
Here is the code for server.js
// use the http library to start the node server
const { read } = require('fs')
const http = require('http')
// additional library for file handling
const fs = require('fs')
// port we want to use
const port = 3000
// filename of the html page we want to show when accessing the server
const file_name = 'test_functions.html'
// create the server
const server = http.createServer(function(req, res){
// tell the brower we will be writing HTML
res.writeHead(200, {'Content-Type':'text/html'})
fs.readFile(file_name, function(error, data){
if(error){
res.writeHead(404)
read.write('Error: File ' + file_name + ' not found')
} else{
res.write(data)
}
res.end()
})
})
server.listen(port, function(error){
if (error){
console.log('Something went wrong', error)
}
else {
console.log('Server is istenng on port ' + port)
}
})
My main page, test_functions.html looks as follows
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="test.mjs" type="module">
</script>
</head>
<body>
<p>Hey, click on the button below to invoke the function</p>
<input type = "button" onclick = "showAlert()" value = "Click Me">
</body>
</html>
while the function that I placed in test.mjs looks as follows
export default function showAlert()
{
alert("welcome");
}
console.log('hello')
After trying it in various ways, the browser keeps giving me the following two errors:
Failed to load module script: Expected a JavaScript module script but the server responded with a MIME type of "text/html". Strict MIME type checking is enforced for module scripts per HTML spec.
Uncaught ReferenceError: showAlert is not defined
at HTMLInputElement.onclick
To allow the Node server to search through a public folder for all files that are requested by the browser I followed the following tutorial: https://youtube.com/watch?v=gvbVjJnv-b8
I got it all to work in the end by updating the server.js file as follows:
// use the http library to start the node server
const { read } = require('fs')
const http = require('http')
// additional libraries for file handling
const url = require("url");
const fs = require('fs')
const lookup = require("mime-types").lookup;
// server settings
const PORT = 3000
const DEFAULT_PAGE = index.html
// create the server
const server = http.createServer((req, res) => {
// handle the request and send back a static file from a local folder called 'public'
let parsedURL = url.parse(req.url, true);
// remove the leading and trailing slashes
let path = parsedURL.path.replace(/^\/+|\/+$/g, '');
if (path == ""){
path = DEFAULT_PAGE;
}
console.log(`Requested path ${path} `);
let file = __dirname + "/public/" + path;
// async read file function uses callback
fs.readFile(file, function(err, content){
if(err){
console.log(`File Not Found ${file}`);
res.writeHead(404);
res.end();
} else {
//specify the content type in the response
console.log(`Returning ${path}`);
res.setHeader("X-Content-Type-Options", "nosniff");
let mime = lookup(path);
res.writeHead(200, { "Content-type": mime });
res.end(content);
}
});
})
server.listen(PORT, function(error){
if (error){
console.log('Something went wrong', error)
}
else {
console.log('Server is istenng on port ' + PORT)
}
})

Why does my script file turn into an exact copy of my index file?

I'm trying to run my site on localhost with Node.js. It downloads, but the script specified in my index file does not work. Looking at the page sources it seems that my script file has turned into an exact copy of my index file. What could cause that?
Here's my code:
const http = require('http')
const fs = require('fs')
const port = 3000
const server = http.createServer(function(req, res) {
res.writeHead(200, { 'Content-Type': 'text/html'})
fs.readFile('index.html', function(error, data) {
if (error) {
res.writeHead(404)
res.write('Error: File not found')
} else {
res.write(data)
}
res.end()
})
})
server.listen(port, function(error) {
if (error) {
console.log('Something went wrong', error)
} else {
console.log('Server is listening on port ' + port)
}
})
index.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
</head>
<body>
<h1>Hi</h1>
<div id="words">*</div>
<script src="script.js"></script>
</body>
</html>
script.js
words.innerHTML += "1";
You don't have any logic to return different responses (e.g. based on the requested URL), so your server always responds with the index.html document, even when other resources are requested (like your script).
You can implement the logic yourself, or you can use existing software to do it. A very commonly used one is called express.

How do I link a js file to index.html in a Node.js web server?

I'm new to Node.js and I'm just trying to create simple web server that can serve HTML, JS, and CSS files.
The server works and I can view index.html in localhost. But I can't seem to link the request.js to index.html. Here's my project structure:
--public
----js
------request.js
----index.html
--app.js
app.js
const http = require("http");
const fs = require('fs').promises;
const host = 'localhost';
const port = 8000;
const requestListener = function (req, res) {
fs.readFile(__dirname + "/public/index.html")
.then(contents => {
res.setHeader("Content-Type", "text/html");
res.writeHead(200); // success status code
res.end(contents);
})
.catch(err => {
res.writeHead(500);
res.end(err);
return;
});
};
const server = http.createServer(requestListener);
server.listen(port, host, function(error) {
if (error) {
console.log('Something went wrong', error)
}
else {
console.log(`Server is running on http://${host}:${port}`);
}
});
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<!-- Required meta tags -->
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<script src="/js/request.js" defer></script>
<title>Water Web Dev</title>
<body>
</body>
</html>
</head>
request.js
const axios = require('axios');
const getBtn = document.getElementById('get-btn');
const getData = () => {
axios.get('https://reqres.in/api/unknown')
.then(function (response) {
// success
console.log(response);
})
.catch(function (error) {
// error
console.log(error);
})
.then(function () {
// always executed
});
}
getBtn.addEventListener('click', getData)
You should server your css & js files as static files.

.js file detected as type:html when called by HTML script. "was loaded even though its MIME type (“text/html”) is not a valid JavaScript MIME type."

I have seen this MIME type error before but no solutions that I have seen here are helping.
I have been trying to get an API post to work for a bit now, and this is the final key to my puzzle I think.
I have 3 files:
Node JS file: server.js which is run by running 'node server.js' in the root directory of the site.
HTML file: index.html
Javascript file: script.js which is brought in by the HTML and is actively listening for a button to be pressed
When running this from the HTML file directly, it runs fine but im getting a CORS error that is caused by not running it through a backend.
When I run it from my Node.js server file, it has these errors at first load of the HTML page:
The script from “http://localhost:8000/script.js” was loaded even though its MIME type (“text/html”) is not a valid JavaScript MIME type.
Uncaught SyntaxError: expected expression, got '<' script.js 1:1
I am unsure what I am doing wrong. The network tab in dev tools also calls the script.js an HTML file.
index.html:
<!DOCTYPE html>
<html lang="en">
<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>REST API POST</title>
<!-- <link href="styles.css" rel="stylesheet"> -->
<script defer src="script.js"></script>
</head>
<body>
<button target="#post">POST to API</button>
</body>
</html>
server.js:
const express = require('express')
const app = express()
const fetch = require("node-fetch")
const cors = require('cors')
let http = require('http');
let fs = require('fs');
app.use(express.static('public'));
let handleRequest = (request, response) => {
response.writeHead(200, {
'Content-Type': 'text/html'
});
fs.readFile('./index.html', null, function (error, data) {
if (error) {
response.writeHead(404);
respone.write('Whoops! File not found!');
} else {
response.write(data);
}
response.end();
});
};
http.createServer(handleRequest).listen(8000);
script.js:
const triggerAPI = document.querySelectorAll('[target]')
triggerAPI.forEach(button => {
button.addEventListener('click', () => {
// const modal = document.querySelector(button.dataset.modalTarget)
postToAPI()
})
})
function postToAPI() {
console.log("this is bleep!")
fetch('https://api.clickup.com/api/v2/list/67541785/task', {
method: 'post',
body: JSON.stringify(body),
headers: { 'Authorization': 'pk_9326_5JD2PZO42X1XLZI2NCOZL08HIB3YY6DM', 'Content-Type': 'application/json' },
})
.then(res => res.json())
.then(json => console.log(json));
}
const body = {
"name": "Test from HTML code :)",
"description": "New Task Description"
};
Update 1:
app.use(express.static(''));
app.get('/', (request, response) => {
response.sendFile('index.html')
})
app.listen(8000)
Update 2:
Folder setup:
website (folder)
public
index.html
package-lock.json
package.json
script.js
server.js
What am I doing?
cd website
node server.js
What error is happening?
The resource from “http://localhost:8000/server.js” was blocked due to MIME type (“text/html”) mismatch (X-Content-Type-Options: nosniff).
update 2 server.js file:
const express = require('express')
const app = express()
const fetch = require("node-fetch")
const cors = require('cors')
app.use(express.static('public'));
app.get('/', (request, response) => {
response.sendFile('/index.html')
})
app.listen(8000)
Update 3:
Right now, its working except its hitting:
Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at https://api.clickup.com/api/v2/list/6/task. (Reason: CORS header ‘Access-Control-Allow-Origin’ missing).
Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at https://api.clickup.com/api/v2/list/6/task. (Reason: CORS request did not succeed).
script.js:
const openModalButtons = document.querySelectorAll('[target]')
openModalButtons.forEach(button => {
button.addEventListener('click', () => {
const modal = document.querySelector(button.dataset.modalTarget)
postToAPI()
})
})
function postToAPI() {
console.log("this is bleep!")
fetch('https://api.clickup.com/api/v2/list/67541785/task', {
method: 'post',
body: JSON.stringify(body),
headers: { 'Authorization': 'pk_10219326_5JD2PZO42X1XLZI2NCOZL08HIB3YY6DM', 'Content-Type': 'application/json' },
})
.then(res => res.json())
.then(json => console.log(json));
}
const body = {
"name": "Test from HTML code :)",
"description": "New Task Description"
};
Server.js:
const express = require('express')
const app = express()
const fetch = require("node-fetch")
const cors = require('cors')
app.use(express.static('public'));
app.get('/', (request, response) => {
response.sendFile('/index.html')
})
app.listen(8000)
index.html:
<!DOCTYPE html>
<html lang="en">
<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>REST API POST</title>
<!-- <link href="styles.css" rel="stylesheet"> -->
<!-- <script defer src="script.js"></script> -->
<script defer src="script.js"></script>
</head>
<body>
<button target="#post">POST to API</button>
</body>
</html>
You're not using express correctly, don't try and run your own server if you're using express, do one or the other.
app.use(express.static('public'));
Here you've told express to serve your static files for you so just put .js and .html in /public and it's done, it'll all work automagically. Static files are .html, .js, .css and similar files, express routes should serve logic while static files like .html can be directly served on server request. By using the above line you're telling express to serve all static files from the /public directory so if you just put your .js and .html files in there you won't even need routes.
http.createServer(handleRequest)
That line is also handling every single request ever made to the server, so when your .html file hits the client's browser and it requests the .js file it will force it to serve the .html file that you've manually read off disk and never serve the .js file. This will be avoided if you just put .js in /public.
app.get('/example', (request, response) => {
response.sendFile('./index.html')
})
...
app.listen(4000)
That's an example of how you want to listen for routes and how you can manually send a file using express. Even though that will also never execute (I think) since .html will look for html in /public because of the static declaration.

Categories

Resources