Basic Locally Hosted Web-server Functionality - javascript

I am working on an addition to a project to create dynamic HTML reports from data that is stored in a SQLite database. Initially, I tried to do everything client-side using things like browserify and sql.js, but I ran into a lot of issues trying to read from the .db file locally.
For that reason, I have now decided to spin up a very basic web server that will be locally hosted. Essentially, I want the user to be able to navigate to http://localhost:3000 and hit a landing page which is the home page of the report.
I have set up a very basic HTTP server using express with the following code running in node:
var express = require('express');
var app = express();
app.use(express.static(__dirname + '/public'));
app.listen(process.env.PORT || 3000);
This works fine, and exposes the /public directory on port 3000, which has a placeholder index.html as of right now. My problem is, that when I try to start adding my code that reads from the SQLite database, none of the necessary require() functions work (specifically, require('fs'), due to it not being defined.
At a basic level, my question boils down to this:
How can i have the ability to read from the SQLite database file in the HTML/Javascript pages that live on the webserver? Whenever I try to use the necessary functions, it tells me that require() is not defined, or other similar errors.
Any help would be appreciated.

Related

NodeJs: How do I access the functions of my JavaScript backend from my HTML frontend?

Here is my HTML code in index.html.
<!DOCTYPE html>
<html>
<body>
<button type="button" onclick="stuff()">Click</button>
<script>
async function stuff() {
await connectToServer();
}
async function connectToServer() {
const xhttp = new XMLHttpRequest();
xhttp.onload = function() {
alert(this.responseText);
};
xhttp.open('GET', 'C:/Users/myName/myFolder/index.js', true);
xhttp.send();
return;
}
</script>
</body>
</html>
Then, here is my backend code in index.js.
const express = require('express');
const axios = require('axios');
const port = process.env.PORT || 8080;
const app = express();
app.get('/', (req, res) => {
res.sendFile('C:/Users/myName/myFolder/views/index.html');
});
app.listen(port, () => console.log(`Listening on port ${port}`));
I can type node index.js on the command line and run this program and go to http://localhost:8080/ . When I do this, the html page shows up as intended. However, when I click the button in order to make a GET request to the server side, I get a console error saying Not allowed to load local resource: file:///C:/Users/myName/myFolder/index.js . I'm using Google Chrome by the way.
I know that it is a security thing, and that you are supposed to make requests to files that are on a web server (they begin with http or https). I suppose then, my question is:
How do I make it so that my server file index.js can be viewed as being on a server so that I can call functions on the backend from my frontend?
You have to make an HTTP request to a URL provided by the server.
The only URL your server provides is http://localhost:8080/ (because you are running an HTTP server on localhost, have configured it to run on port 8080, and have app.get('/', ...) providing the only path.
If you want to support other URLs, then register them in a similar way and write a route to handle them.
The express documentation will probably be useful.
You should not need to load your server-side code into the browser. It's server-side code. It runs on the server. It isn't client-side code. It doesn't run in the browser. The browser does not need access to it.
If you want to load some actual client-side JS from the server, then use <script src="url/to/js"></script> (and not Ajax) and configure express' static middleware.
Let's improve your current flow by separating your backend API process from frontend hosting process. While backend can, it's not good in serving static html files (especially for local development purposes).
Run your backend as usual, node index.js. But as soon as this command will become more complicated, you will probably want to use npm scripts and do just npm start)
Run separate server process for frontend. Check out parcel, snowpack, DevServer. It can be as easy as npx parcel index.html, but this command is likely to change frequently with your understanding of your tool features.
To call backend, just add an API endpoint to an express app (just like you already did for serving static content), and call it, using backend process URL.
Usually, you will see your app on http://localhost/ and it should do requests to http://localhost:8080/.
If for some strange reason you will want to dynamically download js file from your server to execute it, you just need to serve this file from your frontend hosting process. In order to do so, different development servers have different techniques, but usually you just specify file extensions and paths you want to be available.
After editing frontend files, you will see hot-reload in browser. You can achieve the same for node process with various tools (start googling from nodemon)
If you find this way of operating not ideal, try to improve it, and check what people already did in this direction. For example, you can run two processes in parallel with concurrently.

Why will my MEAN app only (partially) run when I set the Angular build directory to /src/ instead of /dist/?

I'm following Heroku's tutorial to create a contact list using the MEAN stack (Heroku's running example here). I'm able to deploy it to Heroku and it works there. But when I run it locally on my machine, the browser (Chrome 67.0.3396.87 on macOS High Sierra) only displays a "Cannot GET /" message.
I believe it's related to how the Angular build directory /dist/ referenced in line 12 of server.js does not exist (as far as I can tell). The beginning of server.js looks like this:
var express = require("express");
var bodyParser = require("body-parser");
var mongodb = require("mongodb");
var ObjectID = mongodb.ObjectID;
var CONTACTS_COLLECTION = "contacts";
var app = express();
app.use(bodyParser.json());
// Create link to Angular build directory
var distDir = __dirname + "/dist/";
app.use(express.static(distDir));
// Create a database variable outside of the database connection callback to reuse the connection pool in your app.
var db;
I looked into it and found that Angular deletes the /dist/ directory upon ng serve. I also found that there is a flag --delete-output-path whose default is true.
I set the --delete-output-path flag to false in .angular-cli.json as recommended by this answer as well as in /node_modules/#angular/cli/lib/config/schema.json. Despite those changes (trying to set the flag in one file, or the other file, or both files at the same time), I'm still getting the "Cannot GET /" message and the /dist/ directory still doesn't appear to be there.
The only way I've been able to even run part of the app is to change server.js's line 12 reference from /dist/ to /src/. This allows /src/index.html to begin loading at localhost:5000/ (the browser displays the text "Loading..." as specified in line 16 of index.html) and gets the contacts API up and running at localhost:5000/api/contacts/. But the Angular components (the list of contacts that is the purpose of the tutorial) don't load. Maybe because I changed the build directory to a totally different location.
Is there something with the /dist/ directory that I'm missing? Or does my issue with getting the app to run locally have nothing to do with /dist/ at all?
Notice that you don't have a way of handling requests to the route '/' since the line:
app.use(express.static(distDir));
only ensures that all bundled files generated in your "dist" folder are accessible when your index.html requires them, but you still have to serve the index.html itself. When using the MEAN stack one normally would do something like this:
app.use ('/api', yourApiRouter);
//and for everything else let the client-side routing handle the route:
app.get ('*', function(req, res) {
res.sendFile(distDir + 'index.html');
}
I recommend to use the native "path" module to join your __dirname with your "dist" folder and your index.html location rather than simple concatenation.
You can use an arrow function instead of a callback when using app.get function if you are using ES6

Getting web application production ready (angularjs/nodejs)

My web application consists of angularjs on front end side and nodejs server listening to client requests. This is my folder structure:Folder Structure
UX contains client side code and IT contains server side code. I am using gulp to watch over development changes and for packaging (you can see the dist folder in UX). I use two terminals to launch this web application locally. From one terminal, I use gulp serve (UX folder) to start a static UI server which monitors the changes as I make to UI and reflect back the changes on the browser immediately. From the second terminal, I start a node server2.js server.
The UX/src/app folder has a config file where I specify server ip address and app.js uses this info to connect to server (currently).
Now, I want to deploy this app over cloud. On the cloud, I have to specify a node it/server2.js as a starting point in its config file. Hence, I want the corresponding web link should point to index.html in UX/src/app folder.
Hence, I need some advice on how to integrate my client side app.js file in the server2.js file on server side.
I am an amateur.
Thanks a lot!
I added this code to my server2.js file:
var express = require("express");
var app = express();
app.use(express.static("ux/dist/"));
app.get("/", function(req, res, next){
res.sendFile('index.html');
});
Currently, it is invoking index.html page from UX folder. But, I am not sure whether I have done it the ideal way. Need help on this.

Point domain to node express server on Azure

This must be an extremely common problem. I've seen various answers for this but none seem to work for me.
I have node installed on an apache server on Windows Azure. My app is built and ready to go (snippet below):
var express = require("express");
var app = express();
//example api call
app.get("/api/example", function(req, res){
//do some process
res.send(data);
});
app.listen(8080);
console.log("App listening on port 8080");
Now, when testing on my own computer, I could then go to localhost:8080, which works great. But now I've put it on the azure server I can't get an external domain to point to it properly. So for example, I have the domain:
framework.example.com
I've added this to my hosts file in Azure:
XXX.0.0.01 framework.example.com
Initially I tried also editing the http-vhosts.conf to point the domain to the correct directory. This worked for loading the frontend, but the app couldn't talk to the backend. API calls returned 400 not found errors.
I've also tried an Express vhost method but think I'm doing it wrong and don't fully understand it. What is the correct method?!
My app structure is like this:
- package.json
- server.js
- server
- files used by server.js
- public
- all frontend files
So to boot the server I run server.js which runs the code at the top. The server.js uses the below Express config to point to the public folder.
app.use(express.static(__dirname + "/public"));
Adding it to the hosts file in Azure won't help. You'll need to configure your domain's DNS to point to Azure. I'd recommend using the DNS Name of your Cloud Service instance. Your underlying VM IP address could change if you need to stop it for some reason, but your Cloud Service DNS name is configured to always route to your underlying VMs. That means you'll need to setup a CNAME with your DNS.
Read more about that here: Cloud Services Custom Domain Name
Next, you'll either need to host the node app on port 80, or put a proxy in front of it to handle that for you. Otherwise you'll be stuck typing framework.example.com:8080 which is not ideal. On linux, you'll likely need to be a privileged user to host on port 80, but you never want your node app to have root privileges. You can use authbind to work around this problem.
See an example of how to use it with node here: Using authbind with Node.js
All that being said, it seems like you're somewhat new with linux server management. If that's the case, I'd strongly recommend trying to use something like Azure Websites instead of a VM. You no longer have to manage the virtual machine OS. You simply tell it to host your application and it takes care of the rest. If you're using github, this is incredibly easy to test and iterate with. It does host on Windows under the hood, and that might problems for some applications, but I host all my node sites there (developed on Mac) without any issues.

Node.js /socket.io/socket.io.js not found express 4.0

So I'm trying to get chat working on my website, and when I was testing locally it worked great, because port 8080 on my localhost was available and all that good stuff. But now I pushed my code to my Heroku app, and when I try and load my chat page, I get the error stating that it can't get localhost:8080/socket.io/socket.io.js.
I've seen node.js /socket.io/socket.io.js not found
and tried the suggestions, but none worked, even moving the socket.io.js file into a resource file did not work. I'm guessing this is because I'm using express 4.0?
Any help would be appreciated
Thanks
Edit:
So to add more details, since my question could seem a little vague, here is my relevant app.js code:
var client = require('socket.io').listen(8080).sockets;
In my jade file for the chat page, I have:
script (src = `'http://localhost:8080/socket.io/socket.io.js`')
and later on
var socket = io.connect(`'http://localhost:8080`');
and all this works on localhost (I load up on port 5000, socket.io is connected to port 8080). I do this using 'foreman start' with the heroku toolbelt.
When I try and change these to work on heroku, it breaks and I'm not sure how to fix it. I hope this clarifies the question a bit.
Edit 2:
I'm running:
express 4.0.0
socket.io 0.9.16
node 0.10.x
Thanks
Do you have an explicit route in express which catches all other routes? Something like this perhaps:
app.get("/", handlers.home);
app.get("/..." ...);
...
app.get("*", handlers.error);
This might keep socket.io from being able to host it's own js file for the client. There is an easy way to fix this, since you probably already have a public or static folder setup in express. Something like:
app.use(express.static("public"));
Make a new folder called socket.io and copy over the appropriate socket.io.js file into said folder, and all should be well. However note that there are two files named socket.io.js!! So, if you see something like "Uncaught ReferenceError: require is not defined" it means you copied the "node-ey" server side file. Here is the correct client file to copy:
app_dir/node_modules/socket.io/node_modules/socket.io-client/dist/socket.io.min.js
Note #BHendricks: I would have just posted as a reply to your comment, but I currently lack the required reputation.
Edit:
The OPs question probably has more to do with the "localhost" issue. When connecting from a client (say your home IP), as far as your browser knows - localhost implies a connection with the machine which is locally hosting stuff. Since your home machine (or phone) does not host socket.io, this is failing.
What you need to do is have your server embed the socket connection information (either a fully qualified hostname, ip etc). This can be done when the server "renders" the page with the client connection.
What happens when you go to http://localhost:8080/socket.io/socket.io.js?
Does it 404? If it does you need to make sure you have it in a directory that Express is set to serve statically.
app.use(express.static(__dirname + '/public'));
Then put your socket.io.js file in public/socket.io/socket.io.js (relative to your app.js file)
Restart your server and see if that fixes it.
Basically, Express doesn't serve files statically from the file system unless you explicitly tell it where to map from.

Categories

Resources