I have a test directory C:\node_samples\hello_express set up:
I have a package.json file in the test directory:
{
"name": "hello_express",
"version": "0.0.0",
"description": "A simple web site",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "Pieter Geerkens",
"license": "MIT",
"private": true,
"dependencies": {
"express": "4.13.4",
"formidable": "1.x"
}
}
I have node.js, express and formidable properly installed in a ../node_modules subdirectory (at least, success reported from the install.) by running this command from the test directory:
npm install
I have an app.js file located in the test directory:
var express = require('express');
var app = express();
var formidable = require('formidable');
app.use('/forms', express.static(__dirname + '/public'));
app.post('/SubmitHelloPost', function (request, response) {
if (request.method.toLowerCase() == 'post') {
// parse form data
var form = new formidable.IncomingForm();
form.parse(request, function (err, fields) {
response.writeHead(200, { 'Content-Type': 'text/html' });
response.write('Hello ' + fields.userName + '!<br />');
response.end('Have a POST great day!');
console.log('Handled POST request from ' + fields.userName);
});
}
});
app.get('/SubmitHello', function (request, response) {
response.writeHead(200, { 'Content-Type': 'text/html' });
response.write('Hello ' + request.query.userName + '!<br />');
response.end('Have a great day!');
console.log('Handled GET request from ' + request.query.userName);
});
var port = 8081;
app.listen(port);
console.log('Listening on port: ' + port);
I open a command prompt and run node app as follows:
However when I attempt to run the test by navigating to either of:
http://localhost:8081/HelloForm.html
http://localhost:8081/HelloPost.html
I get an Error 404.
The html files are (HelloForm.html):
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title></title>
<meta charset="utf-8" />
</head>
<body>
<form method="get" action="/SubmitHello">
Enter Name: <input type="text" name="userName" autofocus />
<input type="submit" value="Submit" />
</form>
</body>
</html>
and (HelloPost.html*):
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title></title>
<meta charset="utf-8" />
</head>
<body>
<form method="post" action="/SubmitHelloPost">
Enter Name: <input type="text" name="userName" autofocus />
<input type="submit" value="Submit" />
</form>
</body>
</html>
I have no idea what is wrong. everything worked briefly after I first set it up, then stopped working.
I think your problem is caused by the following line:
app.use('/forms', express.static(__dirname + '/public'));
This tells Express that when it receives requests starting with /forms, it should map those to static files in the /public folder. From your directory structure, I think this is what you're trying to do:
app.use('/', express.static(__dirname));
(It's still a good idea to move your static files to a separate directory though. Right now, navigating to http://localhost:8081/app.js would return the raw server-side code, which you probably don't want to be readable from your client-side code.)
You should make a directory for those files (I'll use 'public' for this example). Then move the files you want to serve to it, and then change
app.use('/forms', express.static(__dirname + '/public'));
to
app.use('/', express.static(__dirname + '/public'));
The first argument is the server directory where clients access the files, which you want to be the root directory (i.e. '/'), and the second argument is where the files are stored. Usually you don't want to mix your public content (like html), with private content, like server logic, so you put it in a separate folder and only serve that content.
It looks like there are at least 2 problems.
Problem #1
You've mounted your static asset directory at the /forms path, meaning any static assets you want to retrieve will be found at http://localhost:8081/forms/SomeFileName. You are trying to locate them directly at http://localhost:8081/HelloForm.html, which won't work. If you want to get rid of the /forms part of the path entirely, then you can remove the path argument entirely from your static asset declaration:
app.use(express.static(__dirname + '/public'));
Problem #2
You don't have these files inside the public directory anyway. They're just sitting out in your root directory. Instead you want them to be inside a folder called public, so that your static asset declaration can find them. That's why it has the word public in it, like so:
app.use('/forms', express.static(__dirname + '/public'));
So instead, create a folder in the root directory called public and move both those files (HelloForm.html and HelloPost.html) into there.
Here are the Express docs on static file serving, which show you how it works in more detail.
However, I'm guessing that even though this will work to display those 2 files, this is probably not what you ultimately want to do. My guess is that you want to use the 2 routes you've defined to show these 2 pages. My recommendation would be to read up on using a View Engine like EJS to render dynamic views, and also read up on RESTful routing to determine how to name your routes.
Related
I am a newbie, experimenting with JS. I was trying to build a small Node.js app, with a JS script embedded in the index.html, but when I run nodemon, it returns 404 for the script and cant find it. The same html page with embedded script works fine with parcel. What am I doing wrong?
My app.js :
const express = require('express')
app = express()
app.get('/', (req, res, next)=>{
res.sendFile('D:/Node.js Folder/My first project/views/index.html')
})
app.get('/add-user', (req, res, next)=>{
res.sendFile('D:/Node.js Folder/My first project/views/add-user.html')
})
app.get('/show-user', (req, res, next)=>{
res.sendFile('D:/Node.js Folder/My first project/views/show-users.html')
})
app.listen(3000)
HTML File :
<!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 class = "text-gray-400">
<div>
<div class = "text-3xl">
<nav>
<h1>
Hello! Welcome to the first page!
</h1>
<h1 class = "chat-notification-title">
Hello! Welcome to the first page!
</h1>
<form>
<label for="cname">Company Name</label><br>
<input type="text" id="cname" name="cname"><br>
<label for="ccode">Company Code</label><br>
<input type="text" id="ccode" name="ccode">
</form>
<button class ='btn-submit' type = "submit">Add Record</button>
</nav>
</div>
</div><script src="../controller/controller-1.js"></script>
</body>
</html>
Embedded Script :
'use strict'
console.log(document)
const button = document.querySelector('.btn-submit')
console.log(button)
button.addEventListener('click', function () {
console.log('BUTTON PRESSED')
alert("Pressed")
})
One thing you need to do is stop using absolute paths
for eg. 'D:/Node.js Folder/My first project/views/index.html'
should be ./views/index.html
assuming that the app.js file is in the same folder as the views folder.
The server on which you might deploy this code is not going to have the same path as your pc.
You also might wanna make a static folder and move your html, script (controller) folder inside that
and add the following line to the app.js
app.use('/', express.static('static'))
// or
app.use('/', express.static('./static'))
this way you won't have to serve the individual files like you are doing right now.
if you have the src for the embedded file set to ./controller/controller-1.js it will work fine.
I solved it by adding this to my app.js :
app.get('/controller/controller-1.js', (req, res, next)=>{
res.sendFile('D:/Node.js Folder/My first project/controller/controller-1.js')
})
Help from this thread : How to include javascript on client side of node.js?
Is there a better way to do this?
Nodemon are supposed to be used on the server side, often running an express or similar server.
parcel serve is what you are supposed to use on the client side (without server), to serve the html files directly.
You should also not use paths to your own disk. Luckily when the project is running it creates a dist folder with the same files. You are meant to link those to paths in code. Ie on res.sendFile you should write res.sendFile(path.resolve("../client/dist/index.html")) or res.sendFile(path.resolve("../dist/views/index.html))
You import path as import * as path from "path"
If you want to use it with a server, then you should do this:
Client json "dev" should parcel watch index.html, and server "dev" should nodemon server.js.
Both these scripts are supposed to be run in the root package.json file, with concurrently, allowing them to run simultaneously
"dev": "concurrently npm:server:dev npm:client:dev",
"server:dev": "cd server && npm run dev",
"client:dev": "cd client && npm run dev",
In the server file, you should then do something like this:
import express from "express"; //import express
const app = express(); // use express
app.use(express.static("../client/dist/")); // allows express to server static files
app.use((req, res, next) => {
if (req.method === "GET" && !req.path.startsWith("/api")) {
return res.sendFile(path.resolve("../client/dist/index.html"));
} else {
next();
}
}); // checks if url is trying to reach an api, if not it returns the file you are looking for
const server = app.listen(process.env.PORT || 3000, () => {
console.log("Server started on http://localhost:" + server.address().port);
}); // starts server and logs the localhost url
You are then meant to access your site from the server side, and every time you change the server, nodemon will restart the server for you, and every time you change the client, parcel will do the same
Let's say i have a simple project, index.html and one .js file with a method:
<!DOCTYPE html>
<html lang="pl">
<HEAD>
<script src="controller.js"></script>
<meta charset="utf-8"/>
<title>Project</title>
</HEAD>
<body>
<textarea id ="someID" name = "textFieldName"></textarea>
<button onclick="showNewData()">Button</button>
<p id="score"></p>
</body>
</html>
function getText(){
value = document.getElementById('someID').value;
}
function showNewData(){
getText();
document.getElementById('score').innerHTML = "Current data: "+value;
}
I tried to do the same on localhost:3000. So i've done npm project with express and hbs dependencies. It start from server.js file:
const express = require('express');
const port = 3000;
const app = express();
app.set('view engine', 'hbs');
app.get('/', (req, res) => {
res.render('index')
})
app.listen(port);
In "views" folder i have hbs file looked the same like former index.html file but it can't use javascript method from external file. Does anyone know how to do that?
in hbs file
As far as the browser knows, it is HTML. Clients do not care, and cannot know, if an HTTP response is generated by reading a static file or dynamically with some form of server side processing.
src="controller.js"
The value of the src attribute has to resolve to a URL containing the JavaScript
app.get('/', (req, res) => {
res.render('index')
})
The only URL your web server knows about (and so will provide anything other than a 404 error for) is /.
If you want /controller.js to provide a JS file then you need to write code to make that happen.
How to handle static files is covered in the Express Getting Started Guide.
I'm trying to render my HTML file with some a local CSS file, local JS file and two remote files as links
but all I got is a plain HTML in the browser
here is the top of my HTML file (index.html):
<script src="src/drawflow.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.4.1/js/bootstrap.min.js"></script>
<link rel="stylesheet" type="text/css" href="src/index.css" />
<link
rel="stylesheet"
href="https://maxcdn.bootstrapcdn.com/bootstrap/3.4.1/css/bootstrap.min.css"
/>
This is my server code (app.js):
"use strict";
const express = require("express");
const path = require("path");
const app = express();
app.use(express.static(__dirname + "/src"));
app.get("/", (req, res) => {
res.sendFile(path.join(__dirname + "/index.html"));
});
app.listen(process.env.port || 4000, () => {
console.log("listening to port 4000...");
});
and here is my file structure:
file structure
The index.html file is working just fine when opened in the browser but it can't be fetched properly from the server.
Any ideas ?
Thanks to the comment by Chris Short
I replaced
app.use(express.static(__dirname + "/src"));
to
app.use('/src', express.static(path.join(__dirname + '/src')));
and it worked perfectly.
Thanks a lot.
If I'm understanding correctly. The assets for your HTML file are not being fetched properly, so your HTML is showing as bare when you access through the browser. With this understanding, the reason your assets are not loading properly is due to the way your app.js is set up.
Currently you are trying to access href="src/index.css" in your header, however all of your assets are going to be found from your website root. Expressjs handles all app.use statements as middleware and by default are attached to the root of your website. If you would like to have this accessible from "src" then you will need to set up your express.static a bit differently like so.
app.use("/src", express.static(path.join(__dirname, "/src"));
See the below for more info
https://expressjs.com/en/starter/static-files.html
https://expressjs.com/en/guide/using-middleware.html
I'm working on a personal project in order to learn web dev, and I've run into a strange (and hopefully easily solved) problem. In my index.html file I've included a reference to a main.js file, and that's been working just fine for a while now. However, I've recently rewritten the project in Typescript and I've decided to rearrange the folder structure. The problem is that when I move my index.html file (and some other files) down one directory and append a '../' to the script's 'src' tag, I get a 404 error when the html attempts to load the script.
This works just fine:
.
|-scripts
|-Main.ts
|-Main.js
|-SlideShowView.ts
|-SlideShowView.js
|-Server.ts
|-Server.js
|-index.html -> <script src="scripts/Main.js" type="module"></script>
This does not:
.
|-scripts
|-Main.ts
|-Main.js
|-SlideShowView.ts
|-SlideShowView.js
|-services
|-Server.ts
|-Server.js
|-index.html -> <script src="../scripts/Main.js" type="module"></script>
Connecting to the site when using the second scheme gives this error:
GET http://localhost:8000/scripts/Main.js net::ERR_ABORTED 404 (Not Found)
Is index.html not allowed to look above it's own directory? Is there a permissions issue or something? It's such a simple thing that's failing to work I figure there must be something small I'm missing.
Thanks in advance for the help!
Found the answer!
After I moved index.html back to root, the problem wasn't in my html or main.js, but in the express server I was using:
import path from "path";
import express from "express";
const serverPortNum = 8000;
const htmlFile = path.join(__dirname + '/../index.html'); //Added an escape here...
// Create html server
var app = express();
app.use(express.static(__dirname));// ...but not here.
app.get('/', function(req: any, res: any)
{
res.sendFile(htmlFile);
});
app.listen(serverPortNum, function()
{
console.log("Listening! (port " + serverPortNum + ")");
});
Basically, I had changed the path to the html file correctly but I forgot to make the change in app.use() as well. Changing that line to app.use(express.static(__dirname + "/..")); corrected the problem.
This should be simple as moving the index.html file outside of both file structures
|-scripts
|-Main.ts
|-Main.js
|-SlideShowView.ts
|-SlideShowView.js
|-services
|-Server.ts
|-Server.js
|-index.html -> <script src="scripts/Main.js" type="module"></script>
I want a file like index.html to be loaded when the server is created. When I execute the server.js using node, I send a response as text like this res.end("text"). But I want the index.html to load.
I tried to load it using sendFile() in app.get('/getFile') but when I type in the address bar, I get the text for all the urls..even for localhost:3000/getFile.
This is my server.js:
(function(){
var http = require("http");
var express = require('express');
var app = express();
var bodyParser = require('body-parser');
var path = require('path');
// app.use(express.static(__dirname));
app.use(bodyParser.json());
app.use(express.static(__dirname+'/views'));
var server = http.createServer(function(request, response) {
response.end("text");
});
server.listen('3000');
console.log("Server is listening");
app.get('/getFile',function(request,response){
// response.end('shi');
response.sendFile(path.join('/index.html'));
})
})();
Change the following in your code:
var server = http.createServer(function(request, response) {
response.end("text");
});
to this:
var server = http.createServer(app);
Now, you can serve your static index.html file with this code:
app.get('/', function(req, res, next){
// Serve the index.html file in the root directory of the website.
res.sendFile(path.join('/index.html'));
});
I hope this helps. If you have any questions, let me know.
EDITED
I just made a folder and wrote the following code and I have checked that this is working.
var express = require('express');
var app = express();
app.use(express.static(__dirname + '/public'));
app.get('/', function(req, res) {
res.sendFile(__dirname + '/public/indexz.html');
});
app.listen(1339);
console.log('Open this link http://localhost:1337');
Steps
1 Copy the code given above in a new folder and name it whatever you want, name the file server.js
2 go to your cmd and propagate to location of your code and now npm install express
3 now type node server on console
4 open the link that is there on the console.
Note : Make sure there is folder name public and there is a file named
indexz.html in there.
Edited
Regarding proper client side files arrangement
You will have to keep all your files in public folder, first of all and attach them accordingly in your html document.
Example
<!-- Owl Carousel Assets -->
<link href="css/owl.carousel.css" rel="stylesheet">
<link href="css/owl.theme.css" rel="stylesheet">
<script src="js/jquery.min.js"></script>
<script src="angular.js"></script>
<script src="controller.js"></script>
and then within public folder you'll have folders named js and css and in root of the public folder your html files.
Looks your issue is with all the static assets.
In application server like express you have 3 different kind of elements to serve:
static content: this is all html, client side js, css, images and so on
server side templates or views, are documents you assemble with some sort of templating library like handlebars or jade to produce html
api that provide data in xml or more common json format
Your issue is how to serve a static part.
You should add to the static folder of your express app the folder where you build your angular app.
Not just the index.html you need the client side .js, .css and all images the page require.
UPDATE:
Here you could find the express documentation about static content.
UPDATE:
When you add a static folder to the express middleware, you should be able to access your file directly.
For example, if you have 2 files: $project/static/main.js and $project/static/js/my-lib.js, you should use the following urls:
http://127.0.0.1:3000/main.js
http://127.0.0.1:3000/js/my-lib.js
Considering you're executing the node http server on localhost on port 3000.
If you provide a specific path to access the static content, then you have to rewrite your url so.
If you use a line like:
app.use('/staticFolder', express.static('staticFolder'));
Than the urls to the mentioned files will be:
http://127.0.0.1:3000/staticFolder/main.js
http://127.0.0.1:3000/staticFolder/js/my-lib.js
Also pay attention to the path you provide to express.
You should give a proper path, and it's always safer to use absolute paths:
app.use(express.static(__dirname + 'staticFolder'));
or
app.use('/staticFolder', express.static(__dirname + 'staticFolder'));