2

i have a problem opening a js-file on my NodeJS-server, because it will always specify my .js-file with a Content-Type of "text/html".

The goal is to send user-input from a html-form to a JavaScript-file for doing some calculations and later create a Graphic from it.

On my app.js (Node-Server) i have:

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

This will open my html-file correctly. Which is an input-form like follows:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <script type="module" src="./js/index.js"></script> 
    <title>Node-App</title>
</head>
<body>
    Enter Name and Birthdate:<br><br>
    <form action="#" method="post" id="frm">
        <label for="Name">Name:</label><br>
        <input type="text" id="nam"><br>

        <label for="Date">Date:</label><br> 
        <input type="text" id="dat"><br>

        <input type="button" onclick="userInput()" value="Plot">
    </form>

But now i want to open a js-function from here by clicking a button, which gives me the error "userInput is not defnied".
Not a surprise, since loading the page already throw the error "Loading the Module from "www/js/index.js" was blocked by a disabled MIME-Type (text/html)"

My JS-file looks like this, but is not loaded correctly anyways:

function userInput() {
    console.log("Test The Function");
}

I can see in "Network Analysis", in the .js-files's http-header, that its Content-Type is "text/html", so my question is how can i change this?

I tried several things already like setting it in my app.js by typing res.writeHead(200, { 'Content-Type': ['text/html', application/javascript] }) or res.setHeader("Content-Type": "application/javascript"); but it would either not load the html anymore or just do nothing.

Also i tried to set the Content-Type in my index.html as a script-tag like <script type="application/javascript" src="./js/index.js"></script> , but it also changes nothing.

Thanks for your help!

Morizzla
  • 23
  • 6

2 Answers2

2

By default when you serve an html page to the browser, it will analyze your document and if it finds links to css or javascript, it will make an HTTP request to the server that holds these assets.

When you open the browser console via the devTools, you may notice that you either have an error message telling you that it was not possible to GET the requested resource (the name of your javascript file), or your page loads infinitely without returning a response.

So from that we can understand a very simple thing, it's that you have to manage the routes to the resources stored in your server.

For example, the browser will query your server with a GET method and the url http://localhost:3000/script.js, after which your server must serve it this asset.

Here's an example to illustrate this:

Imagine a file structure containing:

  • a public folder, which itself contains an 'assets' folder and an 'html' folder.

  • a server.js file containing your server logic.

This html folder would contain the html file to serve.

The assets folder would contain the 'script.js' and 'styles.css' files.

"use strict";

const http = require("http");
const fs = require("fs");
const os = require("os");
const path = require("path");

const host = "localhost";
const port = 3000;

const server = http.createServer((req, res) => {
    if (req.method === "GET") {
        if (req.url === "/") {
            const readStream = fs.createReadStream(path.join(process.cwd(), "public", "html", "index.html"));
            res.writeHead(200, {
                "Content-Type": "text/html",
            });
            readStream.pipe(res);
        }
        if (req.url === "/styles.css") {
            const readStream = fs.createReadStream(path.join(process.cwd(), "public", "assets", "styles.css"));
            res.writeHead(200, {
                "Content-Type": "text/css",
            });
            readStream.pipe(res);
        }
        if (req.url === "/script.js") {
            const readStream = fs.createReadStream(path.join(process.cwd(), "public", "assets", "script.js"));
            res.writeHead(200, {
                "Content-Type": "text/html",
            });
            readStream.pipe(res);
        }
    }

});

server.on("listening", () => {
    console.log(`Server running on http://${host}:${port}`);
})

server.listen(port);

process.on("SIGINT", () => {
    console.log(`${os.EOL}Server interrupted by 'SIGINT'`);
    process.exit(1);
});
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Node-App</title>
    <link rel="stylesheet" href="styles.css">
</head>
<body>
    Enter Name and Birthdate:<br><br>
    <form action="#" method="post" id="frm">
        <label for="Name">Name:</label><br>
        <input type="text" id="nam"><br>

        <label for="Date">Date:</label><br> 
        <input type="text" id="dat"><br>

        <input type="button" onclick="userInput()" value="Plot">
    </form>
    <script src="script.js"></script>
</body>

In this example I'm using createReadStream() from the 'fs' module for a performance boost, which I strongly advise you to use when serving static files.

Now when the browser will make one or more requests to your server, concerning assets such as 'script.js' or 'styles.css' as in my example, your server will serve it the requested files.

Hope this helps, good luck!

Mrwaks
  • 160
  • 5
  • Thx for the hints, it helped me alot. I can now run the js-file and use its functions by html-button, but i still cannot use `require()` function in it to load the needed module, error is: Uncaught ReferenceError: require is not defined. – Morizzla Sep 15 '22 at 21:09
  • Require does not work on the client side. This is another problem, if you want to use client-side modules, you will need to use a tool like browserify, which is very easy to use: https://browserify.org/ P.s: Don't forget to leave a vote on my answer, to mark the post as solved. – Mrwaks Sep 17 '22 at 20:40
  • Ok thanks for the hint! My last approach was to use all of the `require()` statements in my app.js, but then i realized i cannot process user input anymore, because the app.js is only run at server start, i guess. So probably i need the browserify! I upvoted your answer but i dont have enough reputation yes :P THX for your help! – Morizzla Oct 12 '22 at 10:42
  • I now fixed the Problem by using the "express" library to set up the server. I think it is much more readable, but basically i just needed a post-request to get the data to the server and process it there... – Morizzla Dec 05 '22 at 11:49
0

So with the express module it can be solved like this, app.js:

const path = require("path");
const express = require("express");
const app = express();

app.get("/", function(req, res){    
    res.sendFile(path.join(__dirname, 'html', 'index.html'));
});
app.get("/assets/main.js", function(req, res){
    res.setHeader('Content-Type', 'text/javascript');
    res.sendFile(path.join(__dirname, 'assets', 'main.js'));
});
app.post("/data", function(req, res) {
    res.sendFile(path.join(__dirname, 'html', 'file.html'));    
});
const port = 8080;
app.listen(port, function(){
    console.log("Server is running");
});

index.html:

<form action="/data" method="POST" id="frm">
    some input fields
    <button type="submit" id="btn">Send data to backend</button>
</form>
Morizzla
  • 23
  • 6