Nodejs application created using Express (express genrator) and used handlebars as view engine. Created couple of routes and works fine. Application running on port 3000.
Express routes:
...
app.use('/', index);
app.use('/landing', landing);
app.use('/home', home);
app.use('/api', api);
...
There is an admin panel separate application built on Angular
Currently Angular application running on port 4200 and uses APIs from NodeJs application which running on port 3000.
Angular application routes
const routes : Routes = [
{ path: '', redirectTo: '/user', pathMatch: 'full' },
{
path: 'user',
component : UserComponent,
children : [
{ path:'', redirectTo: '/account', pathMatch: 'full' },
{ path: 'account', component: AccountComponent },
]
},
]
NodeJs application folder structure
api/
api.js
bin/
www
modules/
mongoose.js
node_modules/
public/
css/
fonts/
img/
js/
ngapp/ => Angular resources created with ng build
inline.bundle.js
main.bundle.js
polyfills.bundle.js
styles.bundle.js
vendor.bundle.js
routes/
home.js
index.js
landing.js
views/
common/
header.hbs
footer.hbs
layouts/
master.hbs
ngapp/
index.html => Angular index.html file
index.hbs
landing.hbs
home.hbs
app.js
package.json
What I'm trying:
Want to run both NodeJs and Angular application on same port i.e. port 3000.
What I have done:
Ran ng build and placed index.html file inside /views/ngapp/ of nodejs folder structure.
Created one 'user' route in nodejs and serving that index.html file of angular application. (May be this is not a good way)
app.get('/user', function (req, res, next) {
res.sendFile(path.join(__dirname + '/views/ngapp/index.html'));
});
Somehow its loaded but encountered an error:
My question is about how we can integrate Angular Application (may be running on separate route but on the same port) with NodeJs application which already have some routes defined and used view engine to render pages.
There are two possible solutions.
Use your node application to serve the static frontend files. Then you can't really use ng serve (this is probably what you'd do when running live).
You should be able to tell Express to serve static content from an Angular build directory like this:
app.use(express.static('../angular/dist'));
Which would work if you had a file structure like so and were running serve.js with Node:
-node server
-serve.js
-angular
-dist/*
You can customize as needed by configuring the Angular build folder to be wherever you need it, or use Grunt/Gulp to move files around to the folders you prefer with a build task.
Use nodejs with a different port, and use Angular's proxy config, to have Angular think the api port is actually 4200 (this is probably best during development).
This is primarily a concern during development I reckon, since you most likely wont (and shouldn't) be using ng serve live, so option 2 would be my best recommendation.
To configure a proxy, you create a file in your angular application root directory called proxy.config.json with the following content:
{
"/api/*": {
"target": "http://localhost:3000",
"secure": false,
"changeOrigin": true
}
}
Then when you run ng serve, you run it with ng serve --proxy-config proxy.config.json instead.
Related
I have Node.js + Express backend app with some static routes, some internal (api) routes and Angular 11 app on frontend.
Now I'm trying to rebuild frontend using nrwl nx into three independent apps with shared libs but stuck with express routes.
Current version use one static route to serve whole angular app:
app.use("/", express.static(path.join(__dirname, "frontend")));
It works well, but when I'm trying to split routes like
app.use("/crm/admin/", express.static(path.join(__dirname, "crm-admin")));
app.use("/crm/moderator/", express.static(path.join(__dirname, "crm-moderator")));
app.use("/", express.static(path.join(__dirname, "client")));
I've got issues with angular routing inside admin or moderator apps - production build static app won't load anything
If I edit index base href to point to /crm/admin/ it still won't load page for same reason
Only if I remove all hash from filenames app loading but still have ussues with internal routing: It gives ability to log in and then redirect as it assumed in auth effect. but any other routes are not working as they do in serving app and written in root routes:
path: '',
component: AppComponent,
children: [
{
path: 'login',
component: AuthComponent,
},
{
path: 'logout',
component: AuthLogoutComponent,
},
{
path: 'personal',
loadChildren: () =>
import('./components/personal/personal.module').then(
(m) => m.PersonalModule
),
canActivate: [AuthGuardService],
},
{
path: 'orders',
loadChildren: () =>
import('./components/orders/orders.module').then(
(m) => m.OrdersModule
),
canActivate: [AuthGuardService],
},
{
path: '**',
redirectTo: 'personal',
pathMatch: 'full',
},
],
For testing purposes I've already tried to point crm-admin folder to "/" route. It works same as if I reproduce steps written above with broken routing.
Please, point me what I'm missing during building nx angular app with internal routing and trying to serve it from static express route.
Highly unlike to rebuild existing express app into nx controlled express app, if it possible. It works as intended and no needed to any changes.
Thanks in advance.
upd:
tried to add this
app.use("/crm/admin/", express.static(path.join(__dirname, "crm-admin")));
app.get("/crm/admin/", function (req, res) {
res.sendFile(path.join(__dirname, "./crm-admin/index.html"));
});
and rebuild not using --configuration=production. After fixing base href token in index file it works, but still have issues with routing If I try to change path in the browser address bar.
upd2:
If I add
"baseHref": "/crm/admin/",
"deployUrl": "/crm/admin/",
into angular.json into build section, builded app already have base href token pointed to express route, I've want it be served from, as well as it serving locally from localhost:4201/crm/admin but routing errors still present on builded app.
Well. after googling I've found an answer here, on stackoverflow.
Maybe it can be useful for someone else.
So I have created a React app with
npx create-react-app my-app
and written a few functions and some content to my web app. Now I do need to implement backend for connecting to my SQL database and reading/writing from there. It is my understanding that server-side logic (NodeJS) and front-end code (React) should be in same repository, but how exactly is that done? I should probably create /backend folder and server.js inside it, but where? In the same folder with node_modules, public and src or elsewhere? Also, it would be nice to know more about how information exchange between Node and React works so I can display data fetched from database with React. Thanks in advance.
For development I have two folders on same level - src with react and server with node.
You start (e.g.)
nodejs server on port 5000
webpack-dev-server on port 3000
React communicates with backend via REST API. You have to proxy api requests to your server (part of webpack dev configuration):
devServer: {
contentBase: path.join(__dirname, 'server', 'static', 'public'),
port: 3000,
publicPath: 'http://localhost:3000/',
historyApiFallback: true,
disableHostCheck: true,
hot: true,
proxy: {
'/api': {
target: 'http://127.0.0.1:5000/',
},
},
},
In production environment the react is compiled to server/reactapp subfolder and served with expressjs as any other webpage.
Part of webpack production:
output: {
path: path.join(__dirname, 'server', 'reactapp'),
// publicPath: path.join('dist'),
filename: '[name].bundle.js',
publicPath: '/',
},
In Express (or any other web framework) you then serve the /api path with your backend tasks.
This all means I have two separated development environments - server and react, which partly join till in production environment. They both have separated package.json and node_modules.
In newer versions I have replaced REST API communication with websocket, what needs some other settings in communication.
I have a working NodeJS server and an Angular 9 app. I'm able to test the app in development mode, it works perfectly.
But, when I build the app with ng build --prod and try to access it with NodeJS server I get several errors about file load:
Refused to apply style from
'http://localhost:8080/styles.09cf2cc3740ba29d305c.css' because its
MIME type ('text/html') is not a supported stylesheet MIME type, and
strict MIME checking is enabled.
GET http://localhost:8080/runtime.689ba4fd6cadb82c1ac2.js
net::ERR_ABORTED 404 (Not Found)
I have a proxy file in the app to redirect all its petitions to NodeJS:
proxy.conf.json
{
"/api/*": {
"target": "http://localhost:8080",
"secure": false,
"logLevel": "debug",
"changeOrigin": true
}
}
Am I missing something?
proxy.conf.json aims to provide you an easy way to access to backend by rewriting url in development environment, by using ng serve.
For example, by accessing http://localhost:4200/api, in fact, you access http://localhost:3000/api. (so your backend).
But here, you're issue is how to serve Angular files with NodeJS.
Here is a minimal express code which serves an API endpoint /api, and also static files inside public sub-directory.
const express = require('express')
const app = express()
app.use(express.static('public'));
app.get('/api', function (req, res) {
res.send({ message: 'api ok' })
})
app.listen(3000, function () {
console.log('Example app listening on port 3000!')
})
Copy all files generated by ng build --prod, (see inside dist folder, and your-app-name subfolder) to public folder.
node app.js
You will be able to access your Angular app at http://localhost:3000, and your Angular app will be able to access your API at http://localhost:3000/api.
I'm starting off a new project. I currently have a strucute like this, from root folder:
/app (CRA frontend app)
/server (Node.js Express app)
Dockerfile
docker-compose.yml
My requirements is the following:
Development
Fire up Docker that creates necessary container(s)
Hot reloading for frontend React app (using CRA)
Node.js server that can serve my React app with SSR (automatically updated when editing)
Accessible via http://localhost:3000
Production
Potentially fire up Docker that creates necessary container(s)
Creates production ready version of React app
Creates production ready version of Express app
Accessible via port 80
Where I am right now is somewhere between everything. I don't know how to setup Docker the right way in order to make this whole thing work, and I don't really know how to structure my React app vs the Express app while developing. The Production part seems to be easier as soon as I know how to structure the Development part... + Nginx as a proxy for the Express app?
I'm currently building a Docker container which fires up a container where hot reloading is working etc, but I don't know how to setup the Express part so they work nicely together...?
Any help is much appreciated.
Thanks
Very broad question. Perhaps better to break it down into more direct questions. Anyway, I don't think running your dev setup in Docker is ideal. Instead build your app normally with CRA. Then deploy in Docker.
In my own projects, I have a docker container running a node server which serves the react app using SSR.
Here is the docker part. Note that your package.json should have a script named start:prod for this to work. That script then starts your app in production.
// --- Dockerfile
# Pulled from docker hub and has everything
# needed to run a node project
FROM node:alpine
ENV PORT 3000
# Navigate (cd) to the app folder in the docker container
WORKDIR /usr/src/app
# Copy all package.json / package-lock.json etc. to the root folder
# Executed on build: docker build .
COPY ./package*.json ./
RUN npm i
# copy entire project into docker container
COPY . .
# build front-end with react build scripts and store them in the build folder
RUN npm run build
EXPOSE 3000
CMD ["npm", "run", "start:prod"]
Here's the express server that will start the server.
// -- server.js
import express from "express";
import router from "./controller/index";
const app = express();
const port = 4000;
// Tell the app to use the routes above
app.use(router);
// start the app
app.listen(port, () => {
console.log(`express running on port ${port}`);
});
Here is the controller/index.js file you'll need to start up
// -- controller/index.js
import express from "express";
import path from "path";
import serverRenderer from '../middleware/renderer';
const router = express.Router();
// root (/) should always serve our server rendered page
router.use('^/$', serverRenderer());
// other static resources should just be served as they are
router.use(express.static(
path.resolve(__dirname, '..', '..', 'build'),
{ maxAge: '30d' },
));
export default router;
And finally the renderer which renders the app on the server.
// -- renderer.js
import React from "react";
import { renderToString } from "react-dom/server";
import App from "../../src/App";
const path = require("path");
const fs = require("fs");
export default () => (req, res) => {
// point to html file created by CRA's build tool
const filePath = path.resolve(__dirname, "..", "..", "build", "index.html");
fs.readFile(filePath, "utf8", (error, htmlData) => {
if (error) {
console.error("error", error);
return response.status(404).end();
}
// render the app as string
const html = renderToString(<App />);
// inject rendered app into final html and send
return res.send(
htmlData
.replace('<div id="root"></div>', `<div id="root">${html}</div>`)
);
})
}
You will need bootstrap.js to inject support for certain packages.
// -- bootstrap.js
require('ignore-styles');
require('url-loader');
require('file-loader');
require('babel-register')({
ignore: [/(node_modules)/],
presets: ['es2015', 'react-app'],
plugins: [
'syntax-dynamic-import',
'dynamic-import-node'
]
});
require("./index");
You can find the details of it all here:
https://blog.mytoori.com/react-served-by-express-running-in-docker-container
I am new to AngularJs and wanted to start learning it. I was going to use Restify as my api/backend and was hoping it was possible to serve static files up for the route /.
app layout is something like this..
/nodesprinkler
node_modules/
public/
css/
main.css
bootstrap.css
js/
angular.js
app.js
...
img/
...
index.html
favicon.ico
server.js
routes.js
...
My server.js looks like so:
var restify = require('restify'),
app = module.exports = restify.createServer();
app.listen(8000, function() {
console.log('%s listening at %s', app.name, app.url);
});
/* Client Side Route */
app.get('/', restify.serveStatic({
directory: 'public',
default: 'index.html'
}));
module.exports.app = app;
routes = require('./routes');
How can i get Restify to serve up my static assets so it'll work like a regular express app works? I know restify is based off express, so there must be something simple that i'm missing. It will serve up / as index.html but any of my css and js files I dont have access to.
try express.static()
before app.listen put
app.use(express.static(__dirname+"/public"))
The docs
Try this:
app.get("/css|js|img/", restify.plugins.serveStatic({
directory: "./public"
}));
app.get(
"/.*/",
restify.plugins.serveStatic({
directory: "./public",
file: "index.html"
})
);
I'm creating my futur startup with the same technologies: Restify (that I rewrite) and Angular JS for the single app view.
I've tried of lots of solutions and the best one for me is :
Keep a WS with Restify (or what you want) WITHOUT any static files... I serve it with a dedicated server (python for dev, NGinx for production).
I know this is not the expected answer but give it a try.
python -m http.server on your angular directory is so simple :p