Is html-webpack-plugin hijacking my express server? - javascript

I've been working through the tutorials at https://webpack.js.org/guides/output-management/ and they've solidified my understanding of how webpack typically bundles your whole frontend into a script that is run by a barebones HTML page like this:
<html>
<head>
<title>Output Management</title>
</head>
<body>
<script src="./app.bundle.js"></script>
</body>
</html>
This file is in a src directory, which sits in the project root.
I've modified the tutorials slightly by serving that HTML page from an Express server, which looks like this:
const express = require("express");
var path = require("path");
const server = express();
server.use(express.static(path.join(__dirname, "../dist")));
server.use(express.urlencoded({ extended: true }));
var indexPath = path.join(__dirname, "../src/index.html");
//create a server object:
server
.get("/", function(req, res) {
res.status(200)
res.sendFile(indexPath);
//res.send('<h1>I am not the webpack script!</h1>')
})
module.exports = server
So far everything makes sense. This server serves my index.html, which runs the webpack script, and that script causes the HTML page to show some text, images, and CSS. If I uncomment the res.send line, the server serves a one-line website instead.
However, the linked tutorial recommends trying HTML-webpack plugin, and when that comes in I get confused. I understand that the plugin creates an index.html file in the same directory as the bundled scripts (in my case /dist) that incorporates any and all scripts created by webpack. Sure, makes sense. But nothing is explicitly serving that HTML file. However, if I add the plugin to my webpack config:
entry: {
app: "./src/index.js",
print: "./src/print.js"
},
+ plugins: [
+ new HtmlWebpackPlugin({
+ title: 'Output Management',
+ }),
+ ],
output: {
filename: "[name].bundle.js",
path: path.resolve(__dirname, "dist")
},
then navigate to localhost:3000 in the browser, it displays the /dist/index.html file, NOT the /src/index.html file. Nothing I do to modify the server.js file changes what is displayed in the browser, but if I stop that server from being listened to I see nothing, so apparently webpack-html-plugin is not creating a server of its own.
So seemingly what is happening is that webpack-html-plugin is not just dynamically creating an HTML file to run bundled scripts, it is also changing the behavior of my server in a way that I am not explicitly instructing it to and seemingly cannot modify.
TLDR: Specifically, something in webpack-html-plugin is causing the root route of my express server to serve /dist/index.html, not /src/index.html as I am explicitly instructing it to. Why?
The repo is at https://github.com/CliffRobinson/webpack-tutorial-sandbox and you can (probably) have a look at codesandbox here to see if you can replicate this odd behavior.

What is happening is that you are serving all the files inside the dist directory as static files where your index.html is generated by html-webpack-plugin. I'm not sure how paths are handled in express but it seems that static files take precedence over any route defined that is why dist/index.html is overriding / path.

Related

How to run/view ExpressJS server for webpages other than index.html?

So, I want to view/run/display webpages other than the index.html from my public folder which has multiple html files using ExpressJS and NodeJS. Every time I run my server, I can only view the index.html file. Is there a way I can access other html files? I am a beginner and just getting started with the backend part.
This is my app.js
app=express();
const path=require('path');
const Router=express.Router();
const port=process.env.PORT||3000;
require("./db/connectdb");
const static_path=path.join(__dirname,"../../frontend/public");
app.use(express.static(static_path));
app.get('/createelection',(req,res)=>{
console.log("Create an Election here");
});
app.listen(port,()=>{
console.log('Server is running at port no. '+ port);
});
My Public Folder
Public
-index.html
-createelection.html
-voterlogin.html
From a comment on the question:
localhost:3000/createelection
By default the static module will:
Give you index.html if you ask for a path ending in /
Give you the file you ask for
You are asking for createelection but the file is named createelection.html.
With your current code you need to ask for http://localhost:3000/createelection.html.
Alternatively you can tell Express to try to autocomplete the file extension for you. Look at the documentation for the static module:
extensions: Sets file extension fallbacks: If a file is not found, search for files with the specified extensions and serve the first one found. Example: ['html', 'htm'].
The setting defaults to false
So you would need:
app.use(express.static(static_path, { extensions: true }));

Static Routing in Express.js returning 404 Error

I'm trying to create routing for different pages of my website, using express.js.
When going to 127.0.0.1:8080, it loads the index.html page fine, however, when I go to 127.0.0.1:8080/questionaire, it comes back with a 404 error and doesn't load questionaire.html. I thought that using the line:
app.use(express.static('client', { extensions: ['html'] }));
meant that this would be possible, however, it doesn't work. If there is a better way to do this then fixing the solution, inform me please.
Directory
client
-- index.html
-- index.js
-- questionaire.html
-- questionaire.js
svr.js
viewapi.js
svr.js
'use strict';
const express = require('express');
const app = express();
const view_api = require('./viewapi');
app.use(express.static('client', { extensions: ['html'] }));
const api = require('./api');
app.use('/view', view_api); // routing to api which will get data in form of JSON
app.listen(8080);
I just tried your setup and loading questionare.html worked fine for me. Did you receive any other errors from the Express server when you tried to load the page? I'm asking because I'm not sure what the contents are inside viewapi.js so when I tested it, I didn't have that file.
However, to answer this:
If there is a better way to do this then fixing the solution, inform me please.
it's good practice to separate the assets that you serve (html, css, js, images, etc.). For example, you could create sub-folders inside your client folder and put your static files in the appropriate folder.
You can also find examples and better documentation here: https://expressjs.com/en/starter/static-files.html

Express.js server not working all of a sudden - Cannot GET /

My extremely simple express server using node.js suddenly stopped working. It was working fine (only testing it on my local machine for now), then I tried using browserify (which didn't work and I ended up deleting it) and when I went back to the site I was getting a Cannot GET / error.
I've tried uninstalling browserify, re-installing it, uninstalling and re-installing the two npm packages I'm using, even deleting all of my folders and starting from scratch (just pasting in the code on a couple of files). No matter what I still get the same error and I have no idea why. If I open index.html it still opens perfectly, while when I run my server (index.js) it doesn't throw any errors and seems to be listening as it's supposed to.
The server at the moment:
var path = require('path');
var express = require('express');
var app = express();
var dir = path.join(__dirname, 'public');
app.use(express.static(dir));
app.listen(3000, function () {
console.log('Listening on http://localhost:3000/');
});
My files are currently structured like this:
public
assets (just has some images)
node_modules
index.html
index.js
package-lock.json
styles.css
Your index.html file should be in public folder and then it will work. At the moment, you have set the static path to public folder which doesn't contain any file.
Since your server's path is /public/index.js, path.join(__dirname, 'public') is resolving to /Users/.../your_directory/public/public. Express cannot find such a directory, so it proceeds down its pipeline. Since you did not define a GET / route, Express throws the error.
I would recommend removing your server file from /public.
Here's what your new directory tree would look like:
my_directory
node_modules
public
assets
index.html
styles.css
server
server.js (index.js in your case)
After you set up your directory tree as such, you can change the following:
var dir = path.join(__dirname, 'public');
// becomes
var dir = path.join(__dirname, '..', 'public');
// The '..' is used to move one directory level up.
Then, you should be able to see index.html when going to http://localhost:3000.

onload js call not working with node

I am starting to learn node.js, for now I am just trying to execute my old none node app with node. In this app, I have a html page with a body calling an onload js function. It's working just fine.
Now I have a a node app: app.js, simple as that:
var express = require ('express');
var app = express ();
app.use(express.static(__dirname + '/images'));
app.use(express.static(__dirname + '/CSS'));
app.use(express.static(__dirname + '/font'));
app.use(express.static(__dirname ));
app.use(express.static(__dirname +'/ketcher'));
app.use(express.static(__dirname +'/ChemAlive_JS'));
app.get('/', function(req, res) {
res.sendFile('/home/laetitia/Project/ChemAlive_Interface_Node/ChemAlive_Interface.html');
});
app.listen(8080);
And in the .html I still have:
<body onload="ketcher.init();">
but the function I want to load is not load at all anymore.
Any clue?
Thanks
You have not provided a lot of info in the question but from what you provide I can have few suggestions:
Suggestions
Instead of adding a lot of express.static uses:
app.use(express.static(__dirname + '/images'));
app.use(express.static(__dirname + '/CSS'));
app.use(express.static(__dirname + '/font'));
app.use(express.static(__dirname ));
app.use(express.static(__dirname +'/ketcher'));
app.use(express.static(__dirname +'/ChemAlive_JS'));
put those files (and directories) that you want to be served into one directory, e.g. called static, and use express.static once:
app.use(express.static(__dirname + '/static'));
or better yet, using the path module:
app.use(express.static(path.join(__dirname, 'static')));
you need to require the path module first with:
var path = require('path');
Now, instead of serving the single file for the '/' route with:
app.get('/', function(req, res) {
res.sendFile('/home/laetitia/Project/ChemAlive_Interface_Node/ChemAlive_Interface.html');
});
just put that file into the static directory as index.html so it will be served by the express.static middleware automatically.
Rationale
The way you have it configured currently, is that e.g. everyone can download your Node application - app.js with all of its configuration and even submodules etc.
Also, by using the express.static middleware many times I suspect that you are not sure how the files in those directories will be mapped to URLs.
Having a one place for static files makes it easy to verify whether any script tags have correct paths etc.
My guess
You don't provide enough info to be sure but my guess is that the JavaScript files for the main HTML file are not loaded correctly but you provide not enough info to be sure.
You can open the developer tools console in the browser and reload the page while the console is open and see for errors.
I suspect that the ketcher.init() method is being run but either the method, or the ketcher object is undefined, because some <script> tags failed to be loaded.
Example
The full example after following my suggestions would be much simpler:
var path = require('path');
var express = require ('express');
var app = express();
app.use(express.static(path.join(__dirname, 'static')));
app.listen(8080);
Maybe I would add some output to see what's going on:
var path = require('path');
var express = require ('express');
console.log('starting app.js');
var app = express();
app.use(express.static(path.join(__dirname, 'static')));
app.listen(8080, function () {
console.log('listening on http://localhost:8080/');
});
And now you will have all files that can be served to the browser in one place: in the static directory in this example.
Working app
You can see my example of a working Express application serving static files on GitHub:
https://github.com/rsp/node-express-static-example
In this example the directory for static files is called html but you can call it how you want, as long as it's consistent with how you use the express.static middleware.
You can start from this example project and just put your own files into the directory where express.static is told to look for files to serve.
You can also change the port number to match your needs.
More examples to do the same with and without Express, plus better explanation:
https://github.com/rsp/node-static-http-servers
More hints
The onload callback may not be fired if the page is waiting for some resources to load.
To see if your onload callback is firing you can change it to:
<body onload="alert('onload callback fired');">
Also the ketcher object may be not initialized or it may not have the init() method. After the page is loaded you can open the JavaScript Console and try running the method manually to see if it would work if it was fired:
ketcher.init();
You can also try commands like:
console.dir(ketcher.init);
console.dir(ketcher);
console.log(typeof ketcher.init);
console.log(typeof ketcher);
to see if the ketcher object contains what it should.
Even if the GET localhost:8080/ketcher.js gives a 200 OK status, it can still load some other resources that are not available or, as is very common with code that serve files with res.sendFile() (though unlikely in this case), it can serve HTML instead of JavaScript and result in a cryptic parse error on the < character - see this question for example:
Uncaught (in promise) SyntaxError: Unexpected token < in JSON at position 0 while acess static files in node server
Other related answers:
How to serve an image using nodejs
Failed to load resource from same directory when redirecting Javascript
Sending whole folder content to client with express
Loading partials fails on the server JS
Node JS not serving the static image

Loading scripts in a Node app

This is my folder structure:
- getable_challenge
- node_modules
- stuff
- main.html
- main.js
- backend.js
- README.md
I want to load main.js from within main.html. Previously I had been accessing the page using the URL of file:///Users/adamzerner/code/getable_challenge/main.html, and a simple <script src="main.js"></script> allowed me to load the script.
But then I set up a Node server, at localhost:3000, and now it won't load the script. It's trying to load localhost:3000/main.js, which presumably is the wrong path. I'm not sure how to structure this... what should I do?
Server code (essentially)
var express = require('express');
var app = express();
app.listen(3000);
When you use the "file" protocol like that you aren't even using the web app to serve the script, you are directly accessing it on the local file system. That works fine when you are just running your app on your local machine but it completely breaks when you try to run it as a real app since the browser will have no idea where "file:///..." is, or even have permission to access it.
You need to put the client side scripts into a separate directory, usually named 'public', and then make your application aware of it. If you're using express you would do this:
app.use(express.static(__dirname + '/public'));
You want to put your statically served scripts ("public") into a separate directory so as to control access by your clients. If you just put them into the main directory and made the main directory accessible you could expose all your other files to public view, such as config files that sometimes contain passwords.
It also makes your structure much cleaner.
Try adding this line after var app
app.use(express.static(__dirname));
This should make your resources that are within your servers folder accessible. the var __dirname is the path to where your server is executed.

Categories