J
You have several problems related to how you are accessing the data in your application.PROBLEMAYou want to serve a (or some) JavaScript files from the folder public on a server https://expressjs.com/ using https://nodejs.org/es/ and https://ejs.co/ .SOLUTIONTo achieve what you propose, you must first understand the concept of root folder (root) from which your application is served or executed.When you create a server using Express with NodeJS, the directory root the server will contain the entry point. As we know, an Express.js application has an entry point that is usually a file called index.js, but this can vary according to the preferences of each programmer.A very basic structure of an application could be as follows:project-folder
|
-/public
| |
| --\css
| | |
| | -styles.css
| |
| --\js
| | |
| | -myScript.js
| |
| -favicon.ico
|
-/routes
| |
| -routes.js
|
-/views
| |
| - header.ejs
| - index.ejs
| - footer.ejs
|
-index.js
Being the entry point of our application is index.js, root directory (\) will be the directory project-folder. Access to the other components of our application will be made relative to that directory.Now, it happens that sometimes we have projects that separate the source files from the distribution files:project-folder
|
--\src
| |
| - // archivos fuente
|
--\dist
|
- // archivos de distribución
Now the root directory of our application will be project-folder\src, (always the entry point is in src) therefore access to the other components of our application will be made relative to that directory.Taking into account these considerations, we can already understand a little more how Node handles the routes regarding the entry point of the application.Express.static()The method static() ExpressJS is used to tell the Node server, the location (with respect to the root directory) of the static files that will be served to the customer.However, that route will be the route raíz on the client side. It sounds like something confusing, but it's simple once we understand it.Turns out that from the client side, the files we want to access will be served from a root route that in this case will be the URI of our application.For example, normally developing URI of our application is http://localhost:3000, therefore this will be the root directory from the client side, all the resources you want to access will be related to this URI.Now, what we did to the method. static() on the server side is the name of the directory where the files will be hosted that will be served on the root route (http://localhost:3000) of our application on the client side.So, if we have our static files on the server inside the folder public is to keep them separated from the rest of our files and thus create a protection barrier. Each file or directory within our folder public can be accessed from the root route (URI) of our application.For example, if in our folder public on the server side we have a file called: recurso.htmlthe same can be accessed from the client side in the following direction: http://localhost:3000/recurso.htmlThe same will happen with the resources we declare as a source in our documents html. If a label script reference to a file .js of our server, the same will be located in relation to the URI of our application.According to what you ask in your question, you have a template in EJS, in which you have a label script as follows:<script src="../public/confirm.js"></script><!-- Esto está mal -->
If we analyze the route you're going to attribute src we see that you are telling the browser to try to access or ask the server for a file that is in the parent directory of our root (http://localhost:3000) in a folder called public.The first problem here is that the root directory has no parent directory (../), therefore the request will be rejected.The second problem is that you're using the folder name public, which is the name of our static file repository on the server side, but on the client side there is no such folder (unless within our folder public on the server there is another sub folder called public).Then the label should rewrite it as follows:<script src="confirm.js"></script>
This way our Express server, when you receive the request to serve the file confirm.js it will from the folder called public in our application.A good practice is to separate files (according to their type) in folders within the folder public. For example, files from Javascript can have them all within a folder called js in public, style files can be put into a folder called css in public.So, we could put the label script as follows:<script src="js/confirm.js"></script>
Or our style tag:<link rel="stylesheet" href="css/styles.css">
Now both attributes point to sub folders that must exist within the folder public on our server.Express ResponseThe second problem in your application is as follows:res.render('identification.ejs');
res.sendFile('./public/confirm.js');
If we read the object documentation https://expressjs.com/en/4x/api.html#res of Express, specifically documentation of methods https://expressjs.com/en/4x/api.html#res.render and https://expressjs.com/en/4x/api.html#res.sendFile , we can notice something important:
both methods send a customer response.Being HTTP a protocol of the type request/response, it is to be hoped that for each request made by the client, a single answer is sent from the server. Therefore, you can already glimpse the error by trying to send 2 answers to the same request http. That's why you get the message Can't set headers after they are sent, indicating that a customer response has already been sent for the.On the other hand, when you do:res.sendFile('./public/confirm.js');
you are effectively sending a file called confirm.js the customer, but the same will not be part of a label html within a document, therefore the browser will not execute it, on the contrary it will render it as received.In addition, the documentation of that method indicates that you must pass the absolute route of the file you wish to send (./public is a relative route), or configure the root directory to use relative routes.Over these obstacles you can rewrite your code as follows:identification.ejs:<% include header.ejs%>
<body>
<p>Complete the folowing input bars acordinly</p>
<input id="name" type="text" name="name" placeholder="First and last name"/>
<input id="id" type="number" name="id" placeholder="Id number"/>
<input id="homeAd" type="text" name="homeAd" placeholder="Home address"/>
<input id="posCod" type="number" name="posCod" placeholder="Postal Code"/>
<input id="phone" type="number" name="phone" placeholder="Phone"/>
<input id="homePhone" type="number" name="homePhone" placeholder="Home phone number"/>
<input id="email" type="text" name="email" placeholder="Email"/>
<br>
<button id="ideconfi" onclick="hola()">Sumbit</button>
</script src="js/confirm.js">
<!-- Puedes notar que tu archivo 'confirm.js' está dentro de una carpeta llamada 'js' -->
index.js// Usando ES5 (en aplicaciones Node es preferible siempre usar let y const en vez de var)
const express = require('express');
const app = express();
app.use(express.static('public')); //<- la carpeta 'public' debe estar en el directorio raíz de la aplicación (el directorio que contiene a index.js)
app.get('/ide', (req, res, next) => { //como buena práctica siempre incluye el objeto 'next'
console.log(req.url);
res.render('identification.ejs'); // <- como no se especifica el 'engine' se debe colocar la extensión del archivo que se envía para renderizar en el navegador
});
app.listen(3000, () => {
console.log('Servidor escuchando en puerto 3000');
});
I hope this clears your doubts.You can see this https://github.com/virtualkur2/express-ejs-example that I created in Github where there is a small example of using EJS with Express and how it would apply to your case of use. In it you will find that you can access 2 routes: http://localhost:3000 for you to see how explained here about the use of the folder public to serve static files with Express, and route http://localhost:3000/getfileto see how the browser processes a file sent with the method sendFile() de Express.