Node.js + Express.js : express.static not serving image (contains errors) - javascript

I'm trying to use express.static to serve an image at http://localhost:3000/logo/logo.jpg.
The image logo.jpg is in /public/images and my code is:
app.use("/logo", express.static(__dirname + '/public/images'));
The page loads, but the image is broken. Firefox says: The image at http://localhost:3000/logo/logo.jpg cannot be displayed because it contains errors. When I look at the page info, Firefox tells me the image dimensions for logo.jpg are 0x0. I've tried using various images and different browsers, but they all have the same issue.
How can I get the image to load properly?

I couldn't get my directory with static files served, but when I started to use path.join it began to work as expected. Try this:
var path = require('path');
app.use('/logo', express["static"](path.join(__dirname, 'public/images')));

I found the culprit. For some reason, if I placed the line:
app.use("/logo", express.static(__dirname + '/public/images'));
after this code:
// load liveReload script only in development mode
// load before app.router
// development only
if ('development' == app.get('env')) {
var liveReloadPort = 35729;
var excludeList = ['.woff', '.flv'];
app.use(require('connect-livereload')({
port: liveReloadPort,
excludeList: excludeList
}))
}
It didn't work. However, if I moved the app.use("/logo")... line before the liveReload code, it works.
Don't exactly understand why the position affected how the code works, but at least it does!

Related

Static serving on express js not working when also using custom middleware

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'));

HTML <script> src url no longer works after rearranging files

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>

template node local library import

I have to setup a, most of the time, offline installation of Node-RED and need to use the "Chart.js" Library in a template node. Currently my working approach is to copy the Chart.js dictory to node-red-dashboard/dist/js and import it with <script src= "js/chart.js/dist/Chart.min.js"></script>. But when I want to update the dashboard I need to copy everything again. So it would be nice to have a permanent Solution for this.
I tryed two other approaches until now. For both I installed Chart.js to the .node-red dictory.
First I tryed it like this:
var canvas = document.getElementById('myChart').getContext('2d');
var ChartJs = require('Chart.js');
var chart = new ChartJs(canvas, {... }
in a script tag (... stands for the working chart code that is not edited), but it didn't work aswell as to put
functionGlobalContext: {chartjs:require('Chart.js')} into settings.js and change require('Chart.js') to global.get('chartjs')
Does anyone here has an Idea to solve this properly? Unfortunately the node throws no Error to the console so I don't get an idea whats wrong here.
Thanks in advance for every hint or solution,
manni
When I want to use any 3rd party charting library in my node-red dashboard, I put 2 ui_template nodes into my flow:
under "Template Type" select the "Added to site <head> section" and add the link to the library's url:
<script src="url/to/library.js"></script>
(which in your offline case would be a local url)
use the library's exported objects directly within the template, without using require, such as:
<div id="myChart"></div>
<script>
var canvas = document.getElementById('myChart').getContext('2d');
var chart = new ChartJs(canvas, { ... }
</script>
The trick is to have your local node-red instance serve the ChartJS library through a local url. For that, first add this require path line to the settings.js file, before the exports section:
// The `https` setting requires the `fs` module. Uncomment the following
// to make it available:
var fs = require("fs");
var path = require ("path");
then, uncomment the httpStatic section below that, within the exports:
// When httpAdminRoot is used to move the UI to a different root path, the
// following property can be used to identify a directory of static content
// that should be served at http://localhost:1880/.
httpStatic: path.join(__dirname, 'public'),
(you can use any directory name, in place of public) The __dirname references the node-red server's working directory, usually .node-red under your home directory.
Create this new public directory, copy the ChartJS files under it, and restart node-red. At startup, you should see a line in the console log showing the path to your new static file location:
5 Feb 12:12:23 - [info] Settings file : C:\NODE\node_red_ui\settings.js
5 Feb 12:12:23 - [info] HTTP Static : C:\NODE\node_red_ui\public
5 Feb 12:12:23 - [info] User directory : C:\NODE\node_red_ui
Now you can serve the local file public\scripts\abc.js using the local url
http://localhost:1880/scripts/abc.js
This way, npm updates to the dashboard code will not overwrite your static files.

script tags in Express

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/`

Protractor won't take screenshot in Jenkins

I am using the following code to take screenshots (in after each) when a test fails in Protractor:
function failScreenshot() {
var fs = require('fs');
var spec = jasmine.getEnv().currentSpec;
var specName = spec.description.split(' ').join('_');
if (spec.results().passed()) {
return;
} else {
browser.takeScreenshot().then(
function(png) {
var stream = fs.createWriteStream('screenshots/' + specName + '.png');
stream.write(new Buffer(png, 'base64'));
stream.end();
});
}
}
When I am running the tests locally, the screenshot works just as expected. When running the tests via Jenkins, the tests will stop at the first fail and the screenshot is not created. Also, the folders and paths are correct, I have checked them over and over again. My Jenkins version is 1532.1
Any ideeas on how could I solve this issue?
After further documentation I have found the answer. It was a problem with the path. It seems like NODE JS does not read the path as I thought.
The ./ returns the current directory, except in the require() function. When using require(), it reads ./ to the directory of the file in which it was called (obviously, the mistake was here). __dirname is always the directory of the file in which is used.
The code to be used for my path is the following:
__dirname + '/screenshots/' + specName + '.png'
You can also take the screenshots in jenkins by using the mocha-proshot reporter.
It is a npm package which can be downloaded easily and is very easy to setup.

Categories