Deploying an Angular Build on Nginx for Windows - node.js

I'm trying to deploy my Angular Project's build (which also has a REST API in it) on nginx, but the localhost refuses to connect when I load the Dist inside the html folder.
A localhost run using npm run build does listen to it, but I cannon seem to crack the code on how to deploy that exact output onto the Nginx webserver.
(Inside my Angular Project)
server.js
// Get dependencies
const express = require('express');
const path = require('path');
const http = require('http');
const bodyParser = require('body-parser');
// Get our API routes
const api = require('./server/routes/api');
const app = express();
// Parsers for POST data
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
// Point static path to dist
app.use(express.static(path.join(__dirname, 'dist')));
// Set our api routes
app.use('/api', api);
// Catch all other routes and return the index file
app.get('*', (req, res) => {
res.sendFile(path.join(__dirname, 'dist/ProjectName/index.html'));
});
/**
* Get port from environment and store in Express.
*/
const port = process.env.PORT || '3000';
app.set('port', port);
/**
* Create HTTP server.
*/
const server = http.createServer(app);
/**
* Listen on provided port, on all network interfaces.
*/
server.listen(port, () => console.log(`API running on localhost:${port}`));
server/routes/api (for testing)
const express = require('express');
const router = express.Router();
// declare axios for making http requests
const axios = require('axios');
const API = 'https://jsonplaceholder.typicode.com';
/* GET api listing. */
router.get('/', (req, res) => {
res.send('api works');
});
// Get all posts
router.get('/posts', (req, res) => {
// Get posts from the mock api
// This should ideally be replaced with a service that connects to MongoDB
axios.get(`${API}/posts`)
.then(posts => {
res.status(200).json(posts.data);
})
.catch(error => {
res.status(500).send(error)
});
});
module.exports = router;
package.json script
"scripts": {
"ng": "ng",
"start": "ng serve --proxy-config proxyConfig.json",
"build": "ng build && node server.js",
"test": "ng test",
"lint": "ng lint",
"e2e": "ng e2e"
}
proxyConfig.json
{
"/api": {
"target": "http://localhost:3000",
"secure": false,
"changeOrigin": true
}
}
nginx.conf
server {
listen 8080;
server_name localhost;
#charset koi8-r;
#access_log logs/host.access.log main;
location / {
root html/dist/ProjectName;
index index.html index.htm;
}
location /api {
proxy_pass http://localhost:3000;

Replace the line
app.use(express.static(path.join(__dirname, 'dist')));
with
app.use(express.static(path.join(__dirname, 'dist/ProjectName')));

Related

HPM Error occurred while trying to proxy request in Heroku

I get this error: [HPM] Error occurred while trying to proxy request /api/artefact from myapp.herokuapp.com to http://localhost:5000 (ECONNREFUSED) when I deploy my MERN app.
These are the relevant files in terms of proxying and deploying:
setupProxy.js
const proxy = require("http-proxy-middleware");
module.exports = app => {
app.use(proxy("/api/", { target: "http://localhost:5000" }));
};
server.js
const mongoose = require("mongoose");
const bodyParser = require("body-parser");
const logger = require("morgan");
const { mongo_uri } = require("./config/config");
const path = require("path");
let cors = require("cors");
const PORT = process.env.PORT || 5000;
const app = express();
app.use(cors());
// Set up Routes
const artefactRoutes = require("./routes/api/artefact.js");
const userRoutes = require("./routes/api/users.js");
const authRoutes = require("./routes/api/auth.js");
// Connect to MongoDB Database
const dbRoute = mongo_uri;
mongoose
.connect(dbRoute, { useNewUrlParser: true })
.then(() => console.log("Connected to Database"))
.catch(err => console.log(err));
// Body Parser Middleware to parse request body into readable json format
app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser.json());
// Used for logging
app.use(logger("dev"));
app.use("/api", artefactRoutes);
app.use("/api/users", userRoutes);
app.use("/api/auth", authRoutes);
if (process.env.NODE_ENV === "production") {
app.use(express.static(path.join(__dirname, "../client/build")));
app.get("*", (req, res) => {
// relative path
res.sendFile(path.join(__dirname, "../client", "build", "index.html"));
});
}
app.listen(PORT, () =>
console.log(`Static server has started. Listening on port ${PORT}`)
);
static.json (though I'm not sure really what this does as I just found someone do this on another thread but it didn't change anything for me)
{
"root": "build/",
"clean_urls": false,
"routes": {
"/**": "index.html"
}
}
and my scripts in the parent directory package.json
"scripts": {
"start": "concurrently \"cd backend && node server.js\" \"cd client && npm start\"",
"format": "prettier",
"heroku-postbuild": "cd client && npm install && npm run build"
},
and it might help to mention that my folder structure is like:
-/project
--/client
--/backend
Basically the problem I'm having is that I've deployed my react app to heroku and the frontend loads fine, but none of the axios api calls to my backend are returning anything and just give me a 504 timeout error, and in the heroku logs it just says the proxy error. Any help would be much appreciated!

MERN App Deployed to Heroku Not Working Properly

I've deployed a MERN app to Heroku. When I go to the app, I'm able to post data through my APIs to the MongoDB database, however, whenever I make a GET request, Heroku responds with:
at=info method=GET path="/api/lists/5b44001a558fe30014e8c43c" host=bootcamp-bucket-list.herokuapp.com request_id=e9b06431-aa30-4811-bf7d-a46720991646 fwd="24.124.88.220" dyno=web.1 connect=0ms service=2ms status=304 bytes=237 protocol=https
I am able to run the app locally on my servers without any issues, it's just when we're in prodution, the GET requests fail. Has anyone experienced this before and know what could be causing this issue? Let me know if any additional info is needed.
Here is the setup of my server.js file:
const express = require('express');
const path = require('path');
const users = require('./routes/api/users');
const routes = require('./routes');
const app = express();
const port = process.env.PORT || 5001;
const bodyParser = require("body-parser");
const passport = require('passport');
const mongoose = require("mongoose");
const Models = require('./models');
app.use(bodyParser.urlencoded({
extended: true
}));
app.use(bodyParser.json());
mongoose.Promise = Promise;
var MONGODB_URI = process.env.MONGODB_URI || "mongodb://localhost/testdb";
console.log(MONGODB_URI);
mongoose.connect(MONGODB_URI);
const db = mongoose.connection;
app.use(passport.initialize());
// PASSPORT CONFIG
require('./config/passport')(passport);
app.get('*', function(req, res) {
res.sendFile(path.join(__dirname, './client/build/index.html'));
});
if (process.env.NODE_ENV === 'production') {
// Serve any static files
app.use(express.static('client/build'));
}
// USE ROUTES
app.use('/api/users', users);
app.use(routes);
app.listen(port, () => console.log(`Listening on port ${port}`));
I also have the following scripts in my package.json file:
"start": "node server.js",
"heroku-postbuild": "NPM_CONFIG_PRODUCTION=false npm install --prefix client && npm run build --prefix client"
You need to make sure that when running in production mode that you are reserving your api endpoint.
app.get('*', function(req, res) {
res.sendFile(path.join(__dirname, './client/build/index.html'));
});
should be something like
if (process.env.NODE_ENV === 'production') {
app.use(express.static('client/build')); // serve the static react app
app.get(/^\/(?!api).*/, (req, res) => { // don't serve api routes to react app
res.sendFile(path.join(__dirname, './client/build/index.html'));
});
console.log('Serving React App...');
};

Error with ports: vue.js+node.js project in heroku

Trying to deploy my fullstack project. Locally it builds and working well, but in Heroku, after 'git push heroku master' command and automatic build after it I get the application error - 503 Service Unavailable. It looks like there are different ports or maybe incorrect path to the root folder, where it is index.html
My vue.js config/index.js
'use strict'
const path = require('path')
module.exports = {
dev: {
assetsSubDirectory: 'static',
assetsPublicPath: '/',
proxyTable: {},
port: 80,
autoOpenBrowser: false,
errorOverlay: true,
notifyOnErrors: true,
poll: false,
useEslint: true,
showEslintErrorsInOverlay: false,
devtool: 'cheap-module-eval-source-map',
cacheBusting: true,
cssSourceMap: true
},
build: {
index: path.resolve(__dirname, '../dist/index.html'),
assetsRoot: path.resolve(__dirname, '../dist'),
assetsSubDirectory: 'static',
assetsPublicPath: '/',
productionSourceMap: true,
devtool: '#source-map',
productionGzip: false,
productionGzipExtensions: ['js', 'css'],
bundleAnalyzerReport: process.env.npm_config_report
}
}
My package.json
...
"scripts": {
"dev": "webpack-dev-server --inline --progress --config build/webpack.dev.conf.js",
"postinstall": "nodemon app.js",
"start": "npm run build",
"unit": "cross-env BABEL_ENV=test karma start test/unit/karma.conf.js --single-run",
"e2e": "node test/e2e/runner.js",
"test": "npm run unit && npm run e2e",
"lint": "eslint --ext .js,.vue src test/unit/specs test/e2e/specs",
"build": "node --optimize_for_size --max_old_space_size=2048 --gc_interval=100 build/build.js"
},
...
And the app.js, where I've defined 'dist' as a folder, where app should get main index.html - 'app.use(express.static('dist'))'
const express = require('express');
const path = require('path');
const favicon = require('serve-favicon');
const morgan = require('morgan');
const bodyParser = require('body-parser');
const book = require('./api/routes/book');
const doingsRoutes = require('./api/routes/doings');
const targetsRoutes = require('./api/routes/targets');
const topsRoutes = require('./api/routes/tops');
const usersRoutes = require('./api/routes/users');
const app = express();
const mongoose = require('mongoose');
mongoose.Promise = require('bluebird');
mongoose.connect(
'mongodb://nodejs-rest:' +
'nodejs-rest' +
'#nodejs-rest-shard-00-00-vwe6k.mongodb.net:27017,nodejs-rest-shard-00-01-vwe6k.mongodb.net:27017,nodejs-rest-shard-00-02-vwe6k.mongodb.net:27017/test?ssl=true&replicaSet=nodejs-rest-shard-0&authSource=admin',
{
promiseLibrary: require('bluebird')
}
);
app.use(morgan('dev'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({'extended':'false'}));
app.use('/api/doings', doingsRoutes);
app.use('/api/targets', targetsRoutes);
app.use('/api/tops', topsRoutes);
app.use('/api/users', usersRoutes);
app.use(function(req, res, next) {
const err = new Error('Not Found');
err.status = 404;
next(err);
});
app.set("port", process.env.PORT || 80);
if (process.env.NODE_ENV === 'production') {
console.log('dist')
app.use(express.static('dist'));
}
app.listen(app.get("port"), () => {
console.log(`Find the server at: ${app.get("port")}`);
});
app.use(function(err, req, res, next) {
res.locals.message = err.message;
res.locals.error = req.app.get('env') === 'development' ? err : {};
res.status(err.status || 500);
res.sendFile(path.join(__dirname, '../dist', 'index.html'));
});
app.set('view engine', 'html');
You need to add a server.js file with express and the entry route on the root foolder of you app (in the same folder where package.json/index.html is located) . I have a vue app on heroku as well, it's not very hard.
// server.js
const express = require('express')
const path = require('path')
const history = require('connect-history-api-fallback')
const app = express()
const staticFileMiddleware = express.static(path.join(__dirname + '/dist'))
app.use(staticFileMiddleware)
app.use(history({
disableDotRule: true,
verbose: true
}))
app.use(staticFileMiddleware)
app.get('/', function (req, res) {
res.render(path.join(__dirname + '/dist/index.html'))
})
var server = app.listen(process.env.PORT || 8080, function () {
var port = server.address().port
console.log('App now running on port', port)
})

Deployment of Nodejs Code with Google Cloud

I am trying to deploy my webapp code built on NODE JS. I deployed a simple application hello-world from
https://github.com/GoogleCloudPlatform/nodejs-docs-samples/tree/master/appengine/hello-world
and it worked.
Attached is my project structure.
In the client folder i have angular4 where the build files will be stored in public
In the server folder i have defined routes.
This setup is working find on my local. No errors.
But when i deploy it on google cloud i am getting
Error: Server Error
The server encountered a temporary error and could not complete your request.
Please try again in 30 seconds.
and error log says
Error: No default engine was specified and no extension was provided.
at View (/app/server/node_modules/express/lib/view.js:61)
at EventEmitter.render (/app/server/node_modules/express/lib/application.js:570)
at ServerResponse.render (/app/server/node_modules/express/lib/response.js:1008)
at (/app/server/app.js:42)
at Layer.handle_error (/app/server/node_modules/express/lib/router/layer.js:71)
at trim_prefix (/app/server/node_modules/express/lib/router/index.js:315)
at (/app/server/node_modules/express/lib/router/index.js:284)
at Function.process_params (/app/server/node_modules/express/lib/router/index.js:335)
at next (/app/server/node_modules/express/lib/router/index.js:275)
at Layer.handle_error (/app/server/node_modules/express/lib/router/layer.js:67)
Can anyone guide me on why this error?
My root package.json file to run npm start is
{
"name": "test-application",
"description": "A simple application for testers who run",
"version": "0.0.1",
"private": true,
"license": "Apache-2.0",
"author": "Alaksandar Jesus Gene",
"repository": {
"type": "git",
"url": ""
},
"engines": {
"node": ">=4.3.2"
},
"scripts": {
"deploy": "gcloud app deploy",
"start": "node server/app.js"
},
"dependencies": {
},
"devDependencies": {
},
"cloud-repo-tools": {
"test": {
"app": {
"msg": "Hello, world!"
}
},
"requiresKeyFile": true,
"requiresProjectId": true
}
}
And my app.yaml file is
# [START app_yaml]
runtime: nodejs
env: flex
skip_files:
- ^client$
# [END app_yaml]
Point to note, both files were copied from google sample github project and added values.
Project Folder Structure - Expanded
Project Folder Structure - Collapsed
Can anyone guide me on why this error?
Fixed it. My mistake in app.js coding
var express = require('express');
var path = require('path');
var favicon = require('serve-favicon');
var logger = require('morgan');
const http = require('http');
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser');
var api = require('./routes/api');
var app = express();
// uncomment after placing your favicon in /public
//app.use(favicon(path.join(__dirname, 'public', 'favicon.ico')));
app.use(logger('dev'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, '../public')));
app.use('/api', api);
app.get('*', (req, res) => { //i think the issue was here. I had app.use
res.sendFile(path.join(__dirname, '/index.html'));
});
// catch 404 and forward to error handler
app.use(function(req, res, next) {
var err = new Error('Not Found');
err.status = 404;
next(err);
});
// error handler
app.use(function(err, req, res, next) {
// set locals, only providing error in development
res.locals.message = err.message;
res.locals.error = req.app.get('env') === 'development' ? err : {};
// render the error page
res.status(err.status || 500);
res.render('error');
});
const port = process.env.PORT || '3000';
app.set('port', port);
const server = http.createServer(app);
server.listen(port, () => console.log(`Running on localhost:${port}`));
module.exports = app;

Node (Express) / React app only works locally

Issue Outline
I have a simple Node / React app, which runs fine using heroku local.
The Node backend has an /api/users endpoint, which returns some hardcoded JSON.
After heroku local, visiting localhost:5000/users works as expected, displaying the hardcoded users as per the Users.js React component.
However, when pushed to Heroku, only the / root page works. Going to /users shows Not Found, and going to /api/users returns the JSON.
I'm not sure why it works locally and not on Heroku, any help is appreciated.
Code
Express routes:
var express = require('express');
var router = express.Router();
var path = require('path');
router.get('/api/users', function(req, res, next) {
res.json([{id: 1, name: 'Colin'}, {id: 2, name: 'Spodie'}])
});
module.exports = router;
The Express app.js file:
var express = require('express');
var path = require('path');
var favicon = require('serve-favicon');
var logger = require('morgan');
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser');
var cors = require('cors');
var config = require('./config/dev')
var index = require('./routes/index');
var app = express();
app.use(cors())
app.use(logger('dev'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(cookieParser());
// serve static files from React
app.use(express.static(path.join(__dirname, '../frontend/build')));
// catch 404 and forward to error handler
app.use(function(req, res, next) {
var err = new Error('Not Found');
err.status = 404;
next(err);
});
// error handler
app.use(function(err, req, res, next) {
// set locals, only providing error in development
res.locals.message = err.message;
res.locals.error = req.app.get('env') === 'development' ? err : {};
// render the error page
res.status(err.status || 500);
res.render('error');
});
module.exports = app;
React App.js file:
import React, { Component } from 'react';
import { Switch, Route } from 'react-router-dom';
import Users from './Users';
import NotFound from './NotFound';
import Home from './Home';
class App extends Component {
state = {users : []}
render() {
return (
<div>
<Switch>
<Route exact path='/' component={Home}/>
<Route exact path='/users' component={Users}/>
<Route component={NotFound} />
</Switch>
</div>
);
}
}
export default App;
React api.js file:
const api = process.env.BACKEND_URL || 'http://localhost:5000'
export const getUsers = () => (
fetch(`${api}/api/users`)
.then(res => res.json())
)
React package.json
{
"name": "frontend",
"version": "0.1.0",
"private": true,
"dependencies": {
"react": "^15.6.1",
"react-dom": "^15.6.1",
"react-router-dom": "^4.2.2",
"react-scripts": "1.0.12"
},
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test --env=jsdom",
"eject": "react-scripts eject"
},
"proxy": "http://localhost:5000"
}
Screenshots
Home page running locally
Home page running on Heroku
Users page running locally
Users page running on Heroku
You are serving static files but you also need to forward all HTTP GET requests to client side react router so it can handle. You may want to put this route to your app.js:
app.get("*", function (req, res) {
res.sendFile(__dirname + "/path/to/index.html")
})

Resources