Linking external javascript file into html

Hello,

i have written a html file which works perfectly including some javascript functions.
Now i wrote an external javascript and moved those function in to it.
AS next i have tried to link this javascript file in my html file.
Both files are stored in the flash of my ESP32S3.
When i click on button on the webpage which calls a function from the javascript file i get the following error in Devtools console:

Failed to load resource: the server responded with a status of 404 (Not Found)

Under sources in DevTools i see only the html file and there is no javascript file.
So i do include the javascript in html:

<script src="java_function.js"></script>

Both files are in the same derictory.
javascript file: java_function.js



	function checknetwork() {
		fetch("/checkusers")
			.then(response => response.text())
			.then(data => {
				if (data === " "){
					alert("You are logged out. Try to log in first!");
					window.location.href = "/login";
				} else {
					window.location.href = "/network";
				}
			})
			.catch(error => {
			    console.error('Error checking users: ', error);
			});
	}

	function checksysteminfo() {
	    fetch("/checkusers")
		    .then(response => response.text())
		    .then(data => {
		        if (data === " "){
			        alert("You are logged out. Try to log in first!");
			        window.location.href = "/login";
		        } else {
			        window.location.href = "/sysinfos";
		       }
		    })
		    .catch(error => {
		        console.error('Error checking users: ', error);
		    });
	}

	function checkmyprofile() {
	    fetch("/checkusers")
		    .then(response => response.text())
		    .then(data => {
		        if (data === " "){
			        alert("You are logged out. Try to log in first!");
			        window.location.href = "/login";
		        } else {
			        window.location.href = "/meinprofil";
		        }
		    })
		    .catch(error => {
		           console.error('Error checking users: ', error);
		    });
	}

	function checkAdminBeforeSoftware() {
	    fetch("/checkusers")
		    .then(response => response.text())
		    .then(data => {
		        if (data === "admin") {
			       // User is an admin, redirect to aktualisiere.html
			       window.location.href = "aktualisiere";
		        } else if (data === " "){
			       alert("You are logged out. Try to log in first!");
			       window.location.href = "/login";
		        } else {
			       // User is not an admin, display an alert
			       alert("You are not admin, you are not allowed!");
		        }
		    })
		    .catch(error => {
		        console.error('Error checking admin status: ', error);
		    });
	}

    function checkAdminBeforeService() {
	    fetch("/checkusers")
		    .then(response => response.text())
		    .then(data => {
		        if (data === "admin") {
			        // User is an admin, redirect to test.html
			        window.location.href = "sensordata";
		        } else if (data === " "){
			        alert("You are logged out. Try to log in first!");
			        window.location.href = "/login";
		        } else {
			        // User is not an admin, display an alert
			        alert("You are not admin, you are not allowed!");
		        }
		    })
		    .catch(error => {
		        console.error('Error checking admin status: ', error);
		    });
    }

    function move() {
        var elem = document.getElementById("myBar");   
        var width = 1;
        var id = setInterval(frame, 1235);
        function frame() {
            if (width >= 100) {
                clearInterval(id);
            } else {
                width++; 
                elem.style.width = width + '%'; 
                elem.innerHTML = width * 1  + '%';
           }
        }
    }

    function logout() {
        // Perform any necessary logout actions here
        // For example, clearing session storage or cookies
        localStorage.removeItem('authToken'); // Remove authentication token
        setTimeout(function(){ window.open("/login", "_self");}, 0);
        window.sessionStorage.clear();
        var xhr = new XMLHttpRequest();
        xhr.open("GET", "/logout", true);
        xhr.send();
    }

And html file: aktualisiere.html

<!DOCTYPE html>
<html>
	<head>
	<meta name="viewport" content="width=device-width, initial-scale=1.0">
	<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css">
	<link rel="stylesheet" href="https://www.w3schools.com/w3css/4/w3.css">

		<style>
			* {
			  box-sizing: border-box;
			}

			.navbar {
			  width: 100%;
			  overflow: hidden;
			  background-color: white;
			  border-bottom: 1px solid #BBBBBB;
			}
			.navbar a {
			  float: left;
			  font-size: 1.25vw;
			  color: black;
			  text-align: center;
			  padding: 15px;
			  text-decoration: none;
			}
			.dropdown {
			  overflow: hidden;
			}

			.dropdown .dropbtn {
			  font-size: 1.25vw;;  
			  border: none;
			  outline: none;
			  color: black;
			  padding: 14px 16px;
			  background-color: inherit;
			  font-family: inherit;
			  margin: 0;
			}
			.dropdown-content {
			  display: none;
			  position: absolute;
			  background-color: white;
			  width: 12%;
			  box-shadow: 0px 8px 16px 0px rgba(0,0,0,0.2);
			  z-index: 1;
			}

			.dropdown-content a {
			  float: none;
			  color: black;
			  padding: 12px 16px;
			  text-decoration: none;
			  display: block;
			  text-align: center;
			}

			.dropdown-content a:hover {
			  background-color: white;
			}

			.dropdown:hover .dropdown-content {
			  display: block;
			}

			.navbar a:hover, .dropdown:hover .dropbtn {
			  color: blue;
			}

			.sidenav {
			  width: 23%;
			  float: left;
			  border-right: 1px solid #BBBBBB;
			}

			.sidenav a {
			  background-color: white;
			  padding: 8px;
			  margin-top: 7px;
			  font-size: 1.25vw;
			  text-decoration: none;
			  color: black;
			  width: 100%;
			  display: block;
			  border-bottom: 1px solid #BBBBBB;
			}
			.sidenav a:hover {
			  color: blue;
			}

			label {
			  padding: 8px 8px 8px 8px;
			  display: inline-block;
			}
			.container {
			  border-radius: 5px;
			  background-color: white;
			  font-size: 1vw;
			  padding: 10px;
			  width: 50%;
			  position: absolute;
			  top: 20%;
			  left: 50%;
			  transform: translateX(-34%);
			}

			input[type=file] {
			  background-color: white;
			  font-size: 1vw;
			  width: 80%;
			  margin: 0 -2%;
			  padding: 22px 20px;
			}

			input[type=submit] {
			  background-color: green; 
			  font-size: 1vw;
			  padding: 10px;
			  border: none;
			  width: 15%;
			  margin: 0 14%;
			}


			input[type=submit]:hover {
			  background-color: #45a049; 
			}

			input[type=reset] {
			  background-color: #ff0000;
			  font-size: 1vw;
			  padding: 10px 10px 10px 10px; 
			  border: none;
			  width: 15%;
			  margin: 0 -5%;
			}

			input[type=reset]:hover {
			  background-color: #ee4466; 
			}
			.footer {
			  background-color: #ffffff;
			  color: #111111;
			  text-align: center;
			  font-size: 1vw;
			  padding: 10px;
			  position: absolute;
			  bottom: 1%;
			  left: 50%;
			  transform: translateX(-50%);
			  border-top: 1px solid #BBBBBB;
			}

			@media only screen and (max-width: 450px) {
			  /* For mobile phones: */
			  .navbar, .sidenav{
				width: 30%;
			  }
			}
		</style>
	</head>
	<body style="font-family:Verdana;color:#aaaaaa;">
		<div class="w3-main" style="display: flex; justify-content: center; margin-top: 20px;">

			 
			<div class="w3-container">

				<div class="navbar">
				    <img src='https://wiki.amberg.deprag.de/allgemein/images/thumb/d/de/Logo-DEPRAG-machinesunlimited.svg/120px-Logo-DEPRAG-machinesunlimited.svg.png' style='margin-right: 20px; float: left;'  id='deprag-logo' width= '12%'>
					<a href="#" onclick="checkdash()">Dashboard</a>
					<a href="#" onclick="checkAdminBeforeSoftware()">Software</a>
					<a href="#" onclick="checknetwork()">Einstellungen</a>
					<a href="#" onclick="checksysteminfo()">Systeminfo</a>
					<a href="#" onclick="checkAdminBeforeService()">Service</a>
					<div class="dropdown">
					    <button class="dropbtn"><i class="fa fa-fw fa-user"></i>Admin<i class="fa fa-caret-down"></i></button>
					    <div class="dropdown-content">
					        <a class="fa fa-user" href="#" onclick="checkmyprofile()">Mein Profil</a>
					        <a class="fa fa-times "href="#" onclick="logout()">Abmelden</a>
					    </div>
					</div> 
				</div>
			<div class="sidenav">
			    <a href="#" onclick="checkAdminBeforeSoftware()">Aktualisierung</a>
			</div>
			  
			    <div class="container">
					<form method="post" action= "/update" enctype="multipart/form-data">

						<div class="w3-light-grey" style="width: 67%">
							<div id="myBar" class="w3-container w3-green w3-center" style="width:0%">0%</div>
						</div>
					    <label for="fname">Firmware File:</label>

					    <input type="file" name="update"><br><br>

					    <input type="submit" value="Update" onclick="move()">
					    <input type="reset" value="Reset">

					</form>
			    </div>
			  
			</div>
		</div> 

		<div class="footer">
		    <p>&copy; 2024 - DEPRAG SCHULZ GMBH u. CO.</p>
		    <span>Softwareversion - 2024.06</span>
		</div>
		
	    <script src="java_function.js"></script>

	</body>
</html>


Any help please.

Please take a close look at line 42 in your code.

Thanks for reply.

Which code?
javascript? html? or Arduino

It looks like the esp does not know where the js file is. You did not post your esp code but maybe you have to use a filesystem to store the js code in a file. I have only included it inside the html file in the past.

This works for me

<script type="text/javascript" src="something.js"></script>

Thanks for the reply.

Here is how i read the js from the flash:

void handleaktualisierung(){

  String response, response1;
  if(globalUsername.equals("admin")){

  // Send the response to the client
    Serial.println("Inside handleaktualisierung");

    File file2 = LittleFS.open("/aktualisiere.html", "r");
    if (file2) {
      response += file2.readString();
      file2.close();
    } 

    File file1 = LittleFS.open("/java_function.js", "r");
    if(file1){
      response1 += file1.readString();
      file1.close();
    }
  }
  else {
    String response = "<h1>You are not admin, you are not allowed!!!</h1>";
    response += "<META http-equiv='refresh' content='5;URL=/dash'>Back to homepage...\n";
    ethernetServer.send(200, "text/html", response);
  }

  // Send the modified HTML as the HTTP response
  ethernetServer.send(200, "text/html", response);
  ethernetServer.send(200, "text/javascript", response1);
}

And i debbugged, it reads the js file correctlly.

This link may help. ESP32 HTTP web server: Serving external JavaScript file

I am wondering if your script src should go in the header of your html file instead of the bottom.

I have tried that and put it in the header, that didn't help.
I have opebed the DevTools and under Sources we should see all the resources and i do see the html file but there is no javascript file

The other code. The one you don't show us. The national secret.

BTW, one request, 3 answers from the server ... there might be something wrong.

I could not load external html, css or javascript files using the built-in webserver library. I switched to using espAsyncWebserver library and modified my code. Only then could I load the external files from spiffs. I took a look at the Webserver library examples and without spending a lot of time did not see any simple examples of loading external files.

First of all, thank you all for the reply.
Second, i am using "EthernetWebServer" library because i am using ethernet.
I could already load all my external html files without any issue.
I tried the same way with js file but it didn't worked.
I don't have national secret code.
The Arduino code which i didn't posted here is too long.
I have posted only the function which reads the files from the flash and send them as response to the client.

@zwieblum

One response is only if the user is not admin so only one response.
I added second response which is javafile but it does not help so i will remove it.
All in all the server sends only one response to the request from the client.

As mentioned, this part at the bottom is definitely wrong

Only the first one matters.

  • If they are not an admin, they get the http-equiv='refresh' HTML, and then two other HTTP responses that don't matter. There is no return
  • If they are an admin, they get the main HTML, and a JavaScript response that does not matter

The JavaScript -- and any other referenced content, like a stylesheet or image -- must be sent only when requested. Here's a bare bones server that sends payloads as requested by the browser, which is how HTML works.

#include <WebServer.h>
#include "arduino_secrets.h"

WebServer server(80);

const char index_html[] = R"(
<html>
<head>
<script src="some.js"></script>
</head>
<body>
<h1>Heading</h1>
</body>
</html>
)";

const char some_js[] = R"(
console.log("loaded", new Date());
)";

void setup() {
  Serial.begin(115200);
  server.on("/", []() {
    Serial.println("serving /");
    server.send(200, "text/html", index_html);
  });
  server.on("/some.js", []() {
    Serial.println("serving /some.js");
    server.send(200, "text/javascript", some_js);
  });

  WiFi.begin(SECRET_SSID, SECRET_PASSWORD);
  Serial.println();
  while (WiFi.status() != WL_CONNECTED) {
    Serial.print(".");
    delay(150);
  }
  Serial.println();
  Serial.println(WiFi.localIP());

  server.begin();
}

void loop() {
  server.handleClient();
  delay(1);
}

It uses the arduino-esp32-standard WebServer.

@kenb4 thank you, that was helpful.
@noweare probably your provided link was helpful too but i didn't get the idea yesterday.
The solution is writing new separate handler for javascript files.
Thank you all who relpied.
Credit for the solution to both @kenb4 and @noweare

... which is quite obvious, but as you did not provide the full code ... well ...

@zwieblum
thank you too for your efforts.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.