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>
Related
I am trying to write a middleware for my express js website so that I can use subdomains. I also want to use static image, css, and js serving. My HTML pages load just fine but whenever I try to call a .js file, I get a long page load time and the js doesn't load.
Any help is appreciated, thanks! :)
app.use("/assets", express.static(path.join(__dirname, "assets")));
app.get("*", (req, res, next) => {
let host = req.get("host").split(".");
console.log(req.originalUrl);
let url = req.originalUrl.split("/");
url.shift();
console.log(url);
if (host.length > 2) {
res.send("myWebsite.com");
} else {
const pages = Page.getPages();
pages.forEach(page => {
if ((url[0] == "" ? "home" : url[0] ?? "home").toLowerCase() == page.name) {
if (url.length == 1 || (url.length == 2 && url[1] == "")) {
page.publish(res);
}
}
});
}
});
So, in Pages.html, you have this:
<script type="text/javascript" src="/assets/js/Pages.js"></script>
That looks like it would generally be compatible with your express.static() statement (shown below) to load Pages.js from your assets/js folder:
app.use("/assets", express.static(path.join(__dirname, "assets")));
But, then that Pages.js script immediately starts out with this:
import Page from '../../Page.js';
That will not work when requested by the browser. Remember paths in import statements from Javascript running in the browser are relative to the current URL of the web page. The browser will attempt to combine that relative URL with the URL of the web page and then make a request to your server for that newly constructed URL.
In this case, you'll end up with something like a request for http://somehost/../../Page.js. But, you don't have any route in your server that will handle that. By default express.static() skips any routes that contain ../ because that can be a nasty security issues (allowing attackers to fetch things around your server file system). So, you'll probably end up with a 404 error when trying to fetch that file.
ALL files you want the browser to be able to load, including imports embedded within other JS files must be in your public assets folder (or some other folder you've explicitly enabled public access to with something like express.static()).
FYI, if you look in the browser console, you probably see error messages that would have indicated to you where to look for the error.
__dirname is an environment variable that tells you the absolute path of the directory containing the currently executing file. You have to make sure that the final bundle (your asset folder) is present in that directory. Try to hard code the assets absolute path, if it works then use the below snippet instead:-
app.use("/assets", "express.static(process.cwd() + '/assets'));
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 am trying to simply access a JavaScript file from within an HTML file using the script src attribute, and I have been unable to do so. Both files are in my functions folder.
I have the following Cloud Function index.js file in my functions folder:
const functions = require('firebase-functions');
const db = require('./admin');
var viewerApp = require('./viewerApp');
exports.view = functions.https.onRequest(viewerApp);
the viewApp.js file looks like this:
const express = require("express");
const fs = require('fs');
const viewerApp = express();
module.exports =
viewerApp.get('/:collection_name/:id', (req, res) =>
{
var viewerHTML = fs.readFileSync('./viewerApp.html').toString();
var id = req.params.id;
var collection_name = req.params.collection_name;
var rendered_HTML = eval(viewerHTML);
res.send(rendered_HTML);
}
)
You will notice the eval(viewerHTML) statement, which refers to a separate html file called viewerApp.html, which basically contains a template literal and looks like so:
<!DOCTYPE html>
<html lang="en">
<body>
...
</body>
</html>
(if someone has a better suggestion for separating the HTML into a separate file while being able to use ${variables} that would be helpful as well, as eval() is not ideal and perhaps is part of what is causing my problem)
The above works fine, except that I cannot figure out how to reference a JavaScript file located in the same functions folder, which means I would need to include all my JavaScript in the viewerApp.html file, which will be a mess.
I have tried all these possibilities in the viewerApp.html file (to try and refer to a JavaScript file called test.js):
<script src="./test.js"></script>
<script src="/test.js"></script>
<script src="test.js"></script>
<script src=test.js></script>
All of the above yield the following error in the console:
Uncaught SyntaxError: Unexpected token < test.js:2
(I get the same error if I try and refer to a filename that doesn't exist so I suspect a problem in the file path or limitation on the ability to access the local file system)
I don't know what to make of the error being related to a < character, as the content of test.js is simply:
console.log("logging happened");
Any assistance would be MUCH appreciated. Thank you!!
The problem in the end was that I did not initialize and configure firebase hosting which seems to be what allows html/js/css and other static files to be accessible in HTML returned from the cloud function. Once I did that and setup the public folder, I was able to refer to the test.js file by putting it in the public folder. That plus addition tweaks to the rewrite section of the firebase.json file, and I was all set. Following this video helped a lot and contains all the required steps.
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'));
I have an index.html that has a couple script tags, but they are all returning 404 errors, and I can't figure out how to fix it. Currently they are in the top directory and referenced as such. e.g. <script type="text/javascript" src="./util.js"></script>.
I tried using require('./file.js'); but it would seem to me that this is not what I want. Would this not give me access only in the backend? It needs to be served with the html.
The root path that's given to express.static() is the directory that Express will begin at to match files on disk.
app.use(express.static(path.join(__dirname, 'static')));
That path also won't be part of the URL. It's combined with the req.path in a manner similar to:
var rootPath = 'orbit'; // from `express.static('orbit')`
console.log(path.join(rootPath, req.path));
// 'orbit/orbit/util.js'
Note that orbit appears twice and static is missing, compared to the path in your comment:
./static/orbit/util.js
Or, with the path suggested above:
var rootPath = path.join(__dirname, 'static');
console.log(path.join(rootPath, req.path));
// "/path/to/your/application/static/orbit/util.js"
// assuming `__dirname` is `/path/to/your/application/`