How to serve both react application and api from express server? - node.js

So my node code looks like this (simplified):
const express = require('express');
const app = express();
const routers = require('./routers');
app.use(express.static(`${__dirname}./../dist/`)); // serving index.html
app.use('/api', routers.api);
app.listen(80, () =>
console.log(`listening on port 80`)
);
and let's say my react router has a /fun/:param route and a link to the /fun/foo page.
If I click the link, I end up on mypage.com/fun/foo, but if I refresh I get Cannot GET /fun/foo.
Now I understand that what's actually going on is I shoot a request to my express server and it tries to find the /fun/foo route, fails and returns Cannot GET but how do I make it go to the SPA's /fun/:param-ruote?
I found this link and tried to add the following to the bottom:
app.get('/*', (req, res) => {
res.sendFile(path.join(`${__dirname}./../dist/index.html`));
});
If I log incoming requests to the server I get the following when refreshing /fun/foo:
a connection is made for /fun/foo
a connection is made for /dist/main.js
a connection is made for /fun/main.js
and the client shows nothing, the console logs two:
Uncaught SyntaxError: Unexpected token < main.js:1
EDIT:
Turns out the main.js that is delivered when refreshing the site IS the index.html??? (the main.js file on the server is an actual js-file), how does this even happen!?!?!
New info: Folder structure and relative paths
server
index.js
src
App.js
index.js
public -- only used for devServer(?)
index.html
favicon.ico
dist -- what's used in production(?)
index.html
main
main.js
main.js.map
The project is built with webpack
index.html references main.js with:
<script src="../dist/main.js"></script>
Oh, and if I change the reference to main.js in index.html to:
<script src="./main.js"></script>
I get:
Invariant Violation: Minified React error #321; visit
https://reactjs.org/docs/error-decoder.html?invariant=321 for the full
message or use the non-minified dev environment for full errors and
additional helpful warnings.

Related

express app is not sending index.html file to client

So my express app has a small Node server setup so it can serve up the index.html file when the home route '/' is hit. This is a requirement of using the App Services from Azure, there has to be this server.js file to tell the server how to serve up the client, and i had a previous implementation of this working, however i wanted to change my file structure. previously i had, the client React app in a folder client and the server.js in a folder server along with all of the conrtollers and routes. i've since moved the server API to its own application as there are other apps that depend on it. and i moved the client up one directory into the main directory. Everything was working fine till the other day when all of the sudden when you hit the home route / it will not serve up the index.html file. if you hit any other route it works, if you even hit a button linking back to the homepage, it works, but it wont serve up the app from the / and i cannot for the life of me figure out why, on my development server there are no errors in the console. and im most definitely targeting the correct directory and place for the index. but its like the server isnt reading the route to serve up.
if (process.env.NODE_ENV === 'production') {
console.log('running');
app.use(express.static(path.resolve(path.join(__dirname, 'build'))));
// no matter what route is hit, send the index.html file
app.get('*', (req, res) => {
res.sendFile(path.resolve(path.join(__dirname, 'build', 'index.html')));
});
} else {
app.get('/', (req, res) => {
res.send('API is running...');
});
}
So here im saying if the NODE_ENV is in production make the build folder static, and then whatever route is hit. (Note: i also tried this app.get with other route formats such as /* or / all have the same issues. however in my previous iteration when the client and server where deployed in the same location, /* is what i used.) The .env varialbes are setup correctly, as when the server is ran, itll console log running.. but even if i put a console log inside of the app.get() its like its never hit unless i access the route from something else first.
for example, if i place a console log inside of app.get that states hit whenever the route is hit, hitting / directly does nothing, but if i go to /login itll serve up the correct html on the client and console log hit in the terminal...
If you are having server files inside the client react app, then we are basically accessing file which are not inside our server file. So, we can serve static files using the following code:
const express = require("express");
const app = express(); // create express app
const path = require('path');
app.use(express.static(path.join(__dirname, "..", "build")));
app.use(express.static("build"));
app.listen(5000, () => {
console.log("server started on port 5000");
});
Now in your packages.json of the client react app change the name of start tag under scripts tag to start-client. Then add this following tag to the scripts tag:
"start":"npm run build && (cd server && npm start)",
Basically, this will build the react app and start the server.
It should look like this :
Also in the packages.json of your server add the following tag under script tag
"start":"node server.js"
So when you run the following command npm start it should look like this :

Content Security Policy error: the backend page cannot load in firefox browser

Hi guys I am using a typical react folder structure;
- React Blog
- public
- react-blog-end
- src
server.js
- src
...
Some background information: the src folder obviously runs on port 3000 (react convention). My server.js file is a node.js script. It runs on port 8000. The code is here:
const express = require('express');
const app = express();
app.get('/test', (req, res)=> {
res.send("Hello");
})
app.listen(8000, () => console.log("Listening on port 8000"));
It is extremely simple. I just got started to work on the back-end. When run the server.js script in the browser, it shows:
GEThttp://localhost:8000/test
[HTTP/1.1 404 Not Found 7ms]
Content Security Policy: The page’s settings blocked the loading of a resource at inline (“default-src”). injectGlobalHook.js:513:49
Content Security Policy: The page’s settings blocked the loading of a resource at http://localhost:8000/favicon.ico (“default-src”).
Does anyone knows what is the problem and how to solve it? Thanks!

Error trying to render the index.html that ng build generates with node and express

I want to deploy an application that I perform with the MEAN stack on Heroku, but I encounter 1 problem.
I have this folder structure, my node server, with a public folder, where is the dist / fronted folder and all the files generated by Angular's ng build --prod, it works when I start the server and browse normally, but if I refresh the page or write a route myself, I get these errors:
Errores
Sorry for my English.
If your are building a MEAN stack, you probably have a server.js or index.js or app.js as an entry point to your application. An SPA by definition manages all the routes within the router configuration. But if you try to refresh or type a route yourself, it is like you were trying to access that folder on the server (ex: www.mywebsite.com/about, here the folder about might not exist on the server, it is just known by your Angular app)
My suggestion is that you try to add this fix to the app.js (or server.js or app.js) file, so all unexisting routes or refresh go back to your index.html:
// Check your port is correctly set:
const port = process.env.PORT || 8080;
// Is saying express to put everything on the dist folder under root directory
// Check the folder to fit your project architecture
app.use(express.static(__dirname + "/dist"));
// RegEx saying "capture all routes typen directly into the browser"
app.get(/.*/, function(req, res) {
// Because it is a SPA, all unknown routes will redirect to index.html
res.sendFile(__dirname + "/dist/index.html");
});
app.listen(port);
This guy shows full deploy on Heroku with Angular: https://www.youtube.com/watch?v=cBfcbb07Tqk
Hope it works for you!

How to properly set Angular for production in NodeJS Express Server?

I have been working for hours on figuring out how to deploy my Angular 6 project on NodeJS Express server,
First, in development i use ng serve which refer to localhost:4200 (default) and another one is Node Express for API (interacting with DB) on localhost:3000. In production i want the Angular build to be served from that Node Express server too.
So what i did was:
Setting up <base href="/"> on index.html on Angular Project
Run ng build --prod it went 100% smooth, no errors.
Copy all files from dist/myprojectname on Angular to Node Express server directory under views/.
In index.js i add following lines app.use(express.static(path.join(__dirname, '/views/')));
it got error something like this
Refused to apply style from 'http://localhost:3001/styles.a64e6aa0f6090e05d2190.css/' because its MIME type ('text/html') is not a supported stylesheet MIME type, and strict MIME checking is enabled.
3localhost/:16 GET http://localhost:3001/runtime.16a329deb1d564eef6599.js/ net::ERR_ABORTED 404 (Not Found)
If i use app.use('/*', express.static(path.join(__dirname, '/views/')));
it will give following error:
Uncaught SyntaxError: Unexpected token <
This seems similar to this issue, are you sure that your css files are NOT starting with comments?
From the linked question's answer:
The issue i think it was with a CSS library starting with comments.
While on dev, i do not minify files and i don't remove comments, this
meant that the stylesheet started with some comments, causing it to be
seen as something different from css.
Hope this helps you this worked perfectly fine for me. The important part of the code is below. My angular application is in ROOT_FOLDER/dist/index.html . You can set the compile/output path in angular.json (variable is outputPath). My express.js file and package.json file is just under the root folder.
const bodyParser = require('body-parser');
const DIST_FOLDER = join(process.cwd(), 'dist');
const STARTING_SERVER_MSG = 'Running server on port %s';
const VIEW_ENGINE_STR = 'view engine';
const HTML_STR = 'html';
const VIEWS_STR = 'views';
const BROWSER_STR = 'browser';
private routes() {
// This part might be useless STRAT_LINK later
this.app.set(VIEW_ENGINE_STR, HTML_STR);
this.app.set(VIEWS_STR, join(DIST_FOLDER));
this.app.use(express.static(join(DIST_FOLDER)));
this.app.use(bodyParser.json());
this.app.use(bodyParser.urlencoded({extended: false}));
// this.app.use('/env', envRouter);
// get router
this.app.use(function (req, res, next) {
res.sendFile(join(DIST_FOLDER, 'index.html'), {req});
});
}

Why I'm getting a blank page from running a node server that point to the /dist folder of an Angular app?

My simple node server is:
const express = require('express');
const app = express();
app.get('*', (req, res) => {
res.sendFile(__dirname + '/dist/page/index.html');
})
app.listen(3335, () => { console.log('Server is listening on 3335'); });
But I'm getting the index file that seems not running the main.js
The Angular app, at the moment it's literally a page/component that is app.component.ts, so there is not any routing.
Use express.static() for serving static files.
It is because you have set a response of 'index.html' file for each and every request the server would receive. The first response would be good that's the index.html page only as expected. But, the index.html page must be having some script and css tags to fetch your Angular Javascript code which I assume would be on the same node server. So when the browser would encounter a line like:
<script src="/angularApp.js"></script>
..in your index.html file while parsing it, it would make another request to the node server for http://localhost:<port>/angularApp.js but would get the index.html file as the response as that is what you have set.
Do it like this to serve static files like .html, .css, .js or what have you:
app.use(express.static(path.join(__dirname, '/dist')));

Resources