Importing .js or .mjs files using Node webserver - javascript

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)
}
})

Related

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.

.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.

Connect node app and server + post image to server

I have a very basic question about a node application, and a question about HTTP requests. It's the first time I create a node app with server, and I just can't seem to get the different components to work together.
This is my server.js
var express = require('express');
var multer = require('multer');
const request = require('request');
const upload = multer({dest: __dirname + '/uploads/images'});
const app = express();
const PORT = 3000;
app.use(express.static('public'));
app.post('/upload', upload.single('photo'), (req, res) => {
if(req.file) {
res.json(req.file);
}
else throw 'error';
});
app.listen(PORT, () => {
console.log('Listening at ' + PORT );
});
Then I have a file app.js with a motion-detection system. Every time motion is detected, a picture is taken. This all works fine.
Then the picture should be sent to the server. This is what I can't figure out.
I created a function toServer() that should post the detected data to the server
const request = require('request');
function toServer(data) {
const formData = {
// Pass data via Buffers
my_buffer: data,
// Pass optional meta-data with an 'options' object with style: {value: DATA, options: OPTIONS}
// Use case: for some types of streams, you'll need to provide "file"-related information manually.
// See the `form-data` README for more information about options: https://github.com/form-data/form-data
};
request.post({url:'http://localhost:3000/upload', formData: formData}, function optionalCallback(err, httpResponse, body) {
if (err) {
return console.error('Upload failed:', err);
}
console.log('Upload successful! Server responded with:', body);
});
};
Problem 1: when running the server.js on localhost:3000, it doesn't find any of the scripts loaded in index.html nor my app.js.
Problem 2: when running the index.html on live-server, all scripts are found, but i get the error "request is not defined".
I am pretty sure there is some basic node setup thing I'm missing.
The solution for toServer() might be more complicated.
Thanks for your time,
Mustard Shaper
Problem 1:
this could happen because you have not specified to render your index.html.
for example:
res.render('index')
if it's not because of the single quotes in upload.single('photo') try double quotes.
Another possible error could be that you are missing a default display engine setting.
an example: https://www.npmjs.com/package/hbs
Problem 2:
it may be because you are missing the header
var request = require('request');
request.post({
headers: {'content-type' : 'application/x-www-form-urlencoded'},
url: 'http://localhost',
body: "example"
}, function(error, response, body){
console.log(body);
});
See more at https://expressjs.com/

D3.json Unexpected token with Node.js Server

trying to learn D3 I wrote the following local server:
const http = require('http');
const fs = require('fs');
function onRequest(request, response) {
response.writeHead(200, {'Content-Type': 'text/html'});
fs.readFile('./index.html', null, function(error, data) {
if (error) {
response.writeHead(404);
// response.write('file not found');
} else {
response.write(data);
}
response.end();
});
}
http.createServer(onRequest).listen(8000, '127.0.0.1');
I then go to http://127.0.0.1:8000/ to render this index.html:
<html>
<body>
<script src="https://d3js.org/d3.v5.min.js"></script>
<script>
var stringit = `[{"coin_val": 4999999,"coin_lab": "#PAX"},{"coin_val": 1100000,"coin_lab": "#USDC"}]`;
console.log('working.')
d3.json('./data.json', function(err, data) {
console.log(err)
console.log(data)
});
</script>
</body>
</html>
but I receive the following error in Chrome console:
Uncaught (in promise) SyntaxError: Unexpected token < in JSON at
position 1
at Go (d3.v5.min.js:2) Go # d3.v5.min.js:2
What am I doing wrong? is it i the 3D code or I just don't get the server right? how can I get D3 to read a JSON file in a Node.js server?
I suspect the JSON is not the issue, something goes wrong on the server side and reads the HTML in a wrong way?
I wrote the following local server
Which serves up the contents of index.html in response to any request it gets.
d3.json('./data.json',
So your JavaScript asks for data.json and it gets the contents of index.html.
Since the contents of index.html are not JSON, and start with a <, it throws the error message. A JSON file cannot start with a <.
You need to fix your server so it gives the browser what it asks for instead of blindly sending index.html.
your problem seems to be that your code doesn't know how to serve anything but index.html. It is really frustrating working with a pure node server because most resources on the internet assume that users are going to employ express or another framework.
Below I have a server that can serve static websites and handle requests for a few common types of media. You can add other types by modifying the code in the getContentType function by looking up the mime type for that file format.
I hope this helps
'use strict'
// Step 1: Declare Constants and Require External Resources
const port = "8888", landing = 'index.html', hostname = "127.0.0.1";
const path = require('path');
const http = require('http');
const fs = require('fs');
const qs = require('querystring');
// Step 2: Create getContentType Function that Returns the Requested MimeType for the browser
/**
* getContentType :: str -> str
*
* Function returns the content type that matches the resource being
* requested by the server controller
*/
function getContentType(url){
const mimeTypes = {
'.html' : 'text/html' , '.js' : 'text/javascript' ,
'.css' : 'text/css' , '.json' : 'application/json' ,
'.png' : 'image/png' , '.jpg' : 'image/jpg' ,
'.gif' : 'image/gif' , '.svg' : 'image/svg+xml' ,
'.wav' : 'audio/wav' , '.mp4' : 'video/mp4' ,
'.woff' : 'application/font-woff' , '.ttf' : 'application/font-ttf' ,
'.otf' : 'application/font-otf' , '.eot' : 'application/vnd.ms-fontobject' ,
'.wasm' : 'application/wasm'
};
// If requested url extension is a mime type, the dict object will return that url's value,
// otherwise octet-stream will be returned instead
return mimeTypes[path.extname(url).toLowerCase()] || 'application/octet-stream';
}
// Step 3: Create sendFile Function that Delivers Requested files to the Response stream
/**
* sendFile :: (str, str, str, stream) -> void
*
* function delivers any requested resources to the stream
*/
function sendFile(file, url, contentType, request, response){
fs.readFile(file, (error, content) => {
if(error) {
response.writeHead(404)
.write(`404 Error: '${url}' Was Not Found!`);
response.end();
// include file path for easy debugging, tabs added to make distinct
console.log(`\t${request.method} Response: 404 Error, '${file}' Was Not Found!`);
} else {
response.writeHead(200, {'Content-Type': contentType})
.write(content);
response.end();
console.log(`\t${request.method} Response: 200, ${url} Served`);
};
});
};
// Step 4: Create serverController Function to initialize the server and run the request loop
/**
* serverController :: str -> void
*
* Function creates a server and accesses sendFile and getContentType to serve
* requested resources
*/
function serverController(hostname) {
const server = http.createServer((request, response) => {
// Creates space around .html requests so that they stand out more in the console
if (path.extname(request.url) == '.html' || request.url == '/') {
console.log(`\nPage Requested: ${request.url}\n`);
} else {
if (request.method == "GET") {
console.log(`${request.method} Request: ${request.url}`);
} else {
console.log(`Request came: ${request.url}`);
}
}
// Sends the requested resources to the response stream
if (request.url == '/') {
var file = path.join(__dirname, landing); // delivers index.html by default
sendFile(file, landing, 'text/html', request, response);
} else {
var file = path.join(__dirname, request.url); // delivers requested resource
sendFile(file, request.url, getContentType(request.url), request, response);
};
});
// Gives server a port to listen to and gives an IP address to find it
server.listen(port, hostname, () => {
console.log(`Server running at ${hostname}:${port}\n`);
});
}
// Step 6: Create launch IIFE Function that Starts the server upon Instantiation
(function launch() {
serverController(hostname);
})();

Retrieving data from webpage using script and then accessing it with node js server

I have a html file index.html with a local script script.js running in localhost:8080 using a script NodeServer.js in Node.js.
I want that, whenever I enter data in input boxes, it should get
fetched by the local script and then the script.js export it to
the NodeServer.js application, which would further log the data on the
console.
I am using Chrome browser - 65.0.3325.181
Here is my index.html:
<!DOCTYPE html>
<html>
<head>
<title>Website</title>
<!-- My local script -->
<script src='file:///F:/RahulVerma/NodeJS/LoginPage/script.js'></script>
</head>
<body>
<input type='text' placeholder='Enter username' id='username'/><br/>
<input type='password' placeholder='Enter password' id='password'/><hr/>
<!-- getData() is present in local script -->
<button onclick='getData();'>Submit</button>
</body>
</html>
Here is my script.js:
let getData = () => {
let username = document.getElementById('username').value;
let password = document.getElementById('password').value;
module.exports = { username, password }; // exporting username and password to server running through node.js
}
And my NodeServer.js:
const http = require('http'); // to create server
const fs = require('fs'); // to read index.html
const script = require('F:/RahulVerma/NodeJS/LoginPage/script'); // to fetch data from script.js
// My Server
let server = (request, response) => {
fs.readFile('F:/RahulVerma/NodeJS/LoginPage/index.html', 'utf8', (error, result) => {
if(error) {
response.writeHead(404, {'Content-Type': 'text/plain'});
response.write(`Error: ${error}`);
} else {
response.writeHead(200, {'Content-Type': 'text/html'});
response.write(result);
}
response.end();
});
}
// Creating server
http.createServer(server).listen(8080);
console.log(script.username, script.password); // logging data onto the console
When I type node NodeServer.js in Node.js 9.3.0 (ia32) and npm, the index.html starts working on localhost:8080 but the script.js fails to render in the browser due to the following error: Not allowed to load local resource: file:///F:/RahulVerma/NodeJS/LoginPage/script.js
What am I doing wrong ?
cors error:a mechanism that uses additional HTTP headers to let a user agent gain permission to access selected resources from a server on a different origin
// Create our server
var server;
server = http.createServer(function(req,res){
// Set CORS headers
response.setHeader("Access-Control-Allow-Origin", "*");
response.setHeader("Access-Control-Allow-Credentials", "true");
response.setHeader("Access-Control-Allow-Methods", "GET,HEAD,OPTIONS,POST,PUT");
response.setHeader("Access-Control-Allow-Headers", "Access-Control-Allow-Headers, Origin,Accept, X-Requested-With, Content-Type, Access-Control-Request-Method, Access-Control-Request-Headers");;
if ( req.method === 'OPTIONS' ) {
res.writeHead(200);
res.end();
return;
}
});
further clarification visit stack overflow cors
Best awnser link

Categories

Resources