complete Angular/MEAN beginner here - sorry in advance if I have trouble understanding any of your responses. Recently, I tried creating a web application with the MEAN stack and I used the angular-cli to create a basic project structure (ng new appName). When running npm start (which used the angular-cli command, ng serve) without any changes to the files, everything went just fine and the default "Welcome to My App!" page rendered.
But once I created my own server.js file and changed the start script to node start.js, the <app-root></app-root> component no longer rendered. There were no errors in the console or during npm start, so I wasn't quite sure where to begin.
I checked on some forums and some users said that faulty HTML could be the reason. I replaced the entire template to simply "Testing", and yet nothing would load. Others said that I had to include the static path in my server.js file with app.use(express.static(path.join(__dirname, 'src')));, but my components still would not render. I also noticed my Typescript files were not compiling to Javascript so I took care of that issue, but no avail.
I was thinking that I may be missing something in my server.js file that imports or renders the Angular components, but I can't seem to find any discrepancies between my file and samples on Github. My server.js file is posted below and hopefully someone with more experience than me can spot out what I may be missing.
var express = require("express");
var bodyParser = require("body-parser");
var mongodb = require("mongodb");
var path = require("path");
var ObjectID = mongodb.ObjectID;
var api = require('./routes/api')
var app = express();
// Body Parser Middleware.
app.use(bodyParser.json());
app.use(express.static(path.join(__dirname, 'src')));
app.use('/api', api);
app.get('*', (req, res) => {
res.sendFile(path.join(__dirname, 'src/index.html'));
})
// Create a database variable outside of the database connection callback to reuse the connection pool in your app.
var db;
// Connect to the database before starting the application server.
mongodb.MongoClient.connect('the mongodb url goes here, but I have left it out for obvious security reasons', function (err, database) {
if (err) {
console.log(err);
process.exit(1);
}
// Save database object from the callback for reuse.
db = database;
console.log("Database connection ready");
// Initialize the app.
var server = app.listen(process.env.PORT || 8080, function () {
var port = server.address().port;
console.log("App now running on port", port);
});
});
package.json below:
{
"name": "mean-interact-angular2",
"version": "0.0.0",
"license": "MIT",
"scripts": {
"ng": "ng",
"start": "node server.js",
"build": "ng build",
"test": "ng test",
"lint": "ng lint",
"e2e": "ng e2e"
},
"private": true,
"dependencies": {
"#angular/animations": "^4.0.0",
"#angular/common": "^4.0.0",
"#angular/compiler": "^4.0.0",
"#angular/core": "^4.0.0",
"#angular/forms": "^4.0.0",
"#angular/http": "^4.0.0",
"#angular/platform-browser": "^4.0.0",
"#angular/platform-browser-dynamic": "^4.0.0",
"#angular/router": "^4.0.0",
"body-parser": "^1.17.2",
"core-js": "^2.4.1",
"express": "^4.15.3",
"mongodb": "^2.2.28",
"mongojs": "^2.4.0",
"mongoose": "^4.10.5",
"passport": "^0.3.2",
"rxjs": "^5.1.0",
"typescript": "^2.3.4",
"zone.js": "^0.8.4"
},
"devDependencies": {
"#angular/cli": "1.1.0",
"#angular/compiler-cli": "^4.0.0",
"#angular/language-service": "^4.0.0",
"#types/jasmine": "2.5.45",
"#types/node": "~6.0.60",
"codelyzer": "~3.0.1",
"jasmine-core": "~2.6.2",
"jasmine-spec-reporter": "~4.1.0",
"karma": "~1.7.0",
"karma-chrome-launcher": "~2.1.1",
"karma-cli": "~1.0.1",
"karma-jasmine": "~1.1.0",
"karma-jasmine-html-reporter": "^0.2.2",
"karma-coverage-istanbul-reporter": "^1.2.1",
"protractor": "~5.1.2",
"ts-node": "~3.0.4",
"tslint": "~5.3.2",
"typescript": "~2.3.3"
}
}
Don't merge front-end and back-end it will increase the complexity of understanding and managing , keep both part separately like web API,
one part for your angular created by ANGULAR-CLI and another your nodejs and express.
Then it will be easy to understand and work on..
BACK-END directory structure..
Example:
1.) Server.js
var express = require('express');
var path = require('path');
var app = express();
app.use(express.static(path.join(__dirname, 'public')));
app.set('views', __dirname + '/views');
app.engine('html', require('ejs').renderFile);
app.get('*', (req, res) => {
res.render('index.html');
})
app.listen(3000, () => {
console.log('server started');
})
2.) generated index.html from angular-cli [ng-build]
copy and past index.html from dist directory to the view directory of node
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>MahacelebrationFrontend</title>
<base href="/">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
<link rel="icon" type="image/x-icon" href="favicon.ico">
<link href="styles.4d731bc23993ad5ff6b1.bundle.css" rel="stylesheet" />
</head>
<body>
<app-root>Loading...</app-root>
<script type="text/javascript" src="inline.1e83bfad21d1a20819c7.bundle.js"></script>
<script type="text/javascript" src="polyfills.2024f3f29aec2a67603a.bundle.js"></script>
<script type="text/javascript" src="scripts.60ea08cac30c3ae8c3a5.bundle.js"></script>
<script type="text/javascript" src="vendor.31125e334b44bf11507e.bundle.js"></script>
<script type="text/javascript" src="main.6d7c8d757d6b638d29f5.bundle.js"></script>
</body>
</html>
3.) Keep all other generated files from ng-build into the public directory of nodejs.
and then run from the terminal
node server.js OR nodemon server.js as you wish
NOTE
1.) build directory will generate only after applying
[ng build] command.. of angular-cli
2.) There are other structure you can follow but I prefer it because of ANGULAR base path ,
This is my personal opinion , it not like, you have to follow same structure as mine. you can use as you like.
COMPELETE DIRECTORY STRUCTURE
-
Thank you ,
I hope it will help you.
I had the same problem.
I see that the path you are using is app.use(express.static(path.join(__dirname, 'src'))); which is wrong
When you compile angular project with ng build it compiles the project and writes compiled files in dist folder where a new compiled index.html will be built.
After running the ng build project you will see that dist folder contains the compiled javascript files of the typescript files.
You should send this index.html present in dist folder as a response and not the index.html in src folder.
So your code will be like this
var express = require("express");
var bodyParser = require("body-parser");
var mongodb = require("mongodb");
var path = require("path");
var ObjectID = mongodb.ObjectID;
var api = require('./routes/api')
var app = express();
// Body Parser Middleware.
app.use(bodyParser.json());
app.use(express.static(path.join(__dirname, 'dist'))); // see the change in this line
app.use('/api', api);
app.get('*', (req, res) => {
res.sendFile(path.join(__dirname, 'dist/index.html'));}) // see the change in this line
// Create a database variable outside of the database connection callback to reuse the connection pool in your app.
var db;
// Connect to the database before starting the application server.
mongodb.MongoClient.connect('the mongodb url goes here, but I have left it out for obvious security reasons', function (err, database) {
if (err) {
console.log(err);
process.exit(1);
}
// Save database object from the callback for reuse.
db = database;
console.log("Database connection ready");
// Initialize the app.
var server = app.listen(process.env.PORT || 8080, function () {
var port = server.address().port;
console.log("App now running on port", port);
});
});
After making the path changes your <app-root> component will be rendered in the browser.
Another important point is that app.use() should take the argument to the of the folder which is the immediate parent folder of compiled index.html and not necessarily dist folder otherwise <app-root> component will not be rendered.
Related
I am facing some problems in my (Dockerized) Angular application.
During the loading on Edge/Firefox of my angular application all Request (RestApi) needed to fill my homepage don't arrive to my application. If I load the same page with Chrome all requests arrived and the page is then filled.
The server.js of my Angular application is:
var express = require('express');
var bodyParser = require('body-parser');
var fs = require('fs');
var http = require('http');
var https = require('https');
var cors = require('cors');
var mongoose = require('mongoose');
var qs = require('querystring');
var fs = require('fs');
const nodemailer = require('nodemailer');
var env = process.env.NODE_ENV;
// Node express server setup.
var app = express();
app.set('port', 4200);
app.use(cors());
app.use(function(req, res, next) {
res.header("Access-Control-Allow-Origin", "*");
res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
next();
});
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({
extended : true
}));
app.use(express.json()); // to support JSON-encoded bodies
var server = https.createServer(proxyOption, app);
server.listen(app.get('port'), function() {
console.log('Express server listening on port ' + app.get('port'));
});
// redirect requests from HTTP to HTTPS
http.createServer(function (req, res) {
console.log('Redirect HTTP request to https://' + req.headers['host'] + req.url);
res.writeHead(301, { "Location": "https://" + req.headers['host'] + req.url });
res.end();
}).listen(80);
Is this a problem of CORS doesn't working properly?
I have also seen that is suggested to put the following value in the polyfills.ts file:
-----> (window as any).__Zone_enable_cross_context_check = true;
import 'zone.js/dist/zone'; // Included with Angular CLI.
Microsoft Edge
Here you can see that on Edge the same request loaded is not working and the header is empty, that sounds strange
Edge Console:
On Chrome :
Firefox:
Why Access-Control-Allow-Headers are only in Chrome and not present in Firefox? (same page)
Why the following code is not visible when I load with Edge/Firefox?
app.all("/db/config", function(req, res, next) {
console.log(req.method + ' ' + req.url); <--- Visible only with Chrome
processDbRequest(req, res, Config);
});
I am starting the application with the following command:
ng serve --host 0.0.0.0 --port 443 --public-host IP --ssl --ssl-key /run/secrets/secret.key --ssl-cert /run/secrets/secret.cert --proxy-config server.js --prod
What do you think?
Tks
Anyhow on Chrome there is the section (CORS) not visible in the headers of Edge/Firefox.
UPDATE
The Error visible in EDGE are:
Uncaught (in promise): Response with status: 0 for URL: null"
[object Error]: {description: "Uncaught (in promise): Response with status: 0 for URL: null", message: "Uncaught (in promise): Response with status: 0 for URL: null", promise: Object, rejection: Object, stack: "Error: Uncaught (in promise): Response with status: 0 for URL: null at M (https://<IP>/polyfills.126a602ce79d269ee3a3.js:1:14070) at M (https://<IP>/polyfills.126a602ce79d269ee3a3.js:1:13634) at Anonymous function (https://<IP>/polyfills.126a602ce79d269ee3a3.js:1:14864) at t.prototype.invokeTask (https://<IP>/polyfills.126a602ce79d269ee3a3.js:1:8720) at onInvokeTask (https://<IP>/main.962c274fd5e7aea50f8c.js:1:422471) at t.prototype.invokeTask (https://<IP>/polyfills.126a602ce79d269ee3a3.js:1:8720) at e.prototype.runTask (https://<IP>/polyfills.126a602ce79d269ee3a3.js:1:4000) at g (https://<IP>/polyfills.126a602ce79d269ee3a3.js:1:11104) at e.invokeTask (https://<IP>/polyfills.126a602ce79d269ee3a3.js:1:9950) at m (https://<IP>/polyfills.126a602ce79d269ee3a3.js:1:23265)"...}
Here package.json configuration:
{
"name": "elg-dash",
"version": "0.0.0",
"scripts": {
"ng": "ng",
"start": "export NODE_ENV=dev && ng serve --port 3000 --proxy-config server.js ",
"build": "ng build",
"test": "ng test",
"lint": "ng lint",
"e2e": "ng e2e"
},
"private": true,
"dependencies": {
"#angular/animations": "~7.2.0",
"#angular/common": "~7.2.0",
"#angular/compiler": "~7.2.0",
"#angular/core": "~7.2.0",
"#angular/forms": "~7.2.0",
"#angular/http": "^7.2.15",
"#angular/platform-browser": "~7.2.0",
"#angular/platform-browser-dynamic": "~7.2.0",
"#angular/router": "~7.2.0",
"#eds/vanilla": "^3.4.0",
"body-parser": "^1.19.0",
"core-js": "^2.5.4",
"cors": "^2.8.5",
"d3": "^5.12.0",
"dragula": "^3.7.2",
"express": "^4.17.1",
"mapbox-gl": "^1.4.1",
"microsoft-adal-angular6": "^1.3.0",
"mongoose": "^5.7.5",
"ng2-completer": "^3.0.2",
"ng2-datepicker": "^3.1.1",
"ng2-smart-table": "^1.5.0",
"ngx-permissions": "^7.0.3",
"nodemailer": "^6.3.1",
"rxjs": "~6.3.3",
"tslib": "^1.9.0",
"zone.js": "~0.8.26"
},
"devDependencies": {
"#angular-devkit/build-angular": "~0.13.0",
"#angular/cli": "~7.3.9",
"#angular/compiler-cli": "~7.2.0",
"#angular/language-service": "~7.2.0",
"#types/jasmine": "~2.8.8",
"#types/jasminewd2": "^2.0.8",
"#types/node": "~8.9.4",
"codelyzer": "~4.5.0",
"jasmine-core": "~2.99.1",
"jasmine-spec-reporter": "~4.2.1",
"karma": "~4.0.0",
"karma-chrome-launcher": "~2.2.0",
"karma-coverage-istanbul-reporter": "~2.0.1",
"karma-jasmine": "~1.1.2",
"karma-jasmine-html-reporter": "^0.2.2",
"protractor": "~5.4.0",
"rxjs-compat": "~6.5.3",
"ts-node": "~7.0.0",
"tslint": "~5.11.0",
"typescript": "~3.2.2"
}
}
SMALL UPDATE
It seems that the same angular application works in Firefox with the following version : 72.0.1 (64-bit), the same app doesn't work on the Linux Version 72.0.1 (64-bit).
#Prisco It is hard to say it is CORS because in that case you cannot get 200 OK status.
Your image do not give any hint much. I GUESS some scenarios happened to you base on my experience that I faced same issue before with Angular on server using JBOSS (not docker).
Check the response and see there is the message like failed to load... or not?
If yes, then something block your response. It could be your web server and could be your computer software like antivirus.
Check your page look like? Empty page? If Yes, It is because your front-end configuration like polyfill and browserlist.
Compare line by line to see different between Chrome and Edge to see any different and google it.
Could you try to deploy your project without docker to see it work or not. If it is working, then your docker configuration have issue.
I have an Angular app that is talking to a REST service.
When I run the Angular app local with the CLI, correctly proxies all /api requests to the REST service. When I try to build the app and run through a server.js (so that I can deploy the app to Heroku) I lose the proxy routing.
The REST service is deployed on Heroku and runs fine.
I run the Angular with:
ng serve
My proxy.conf.json
{
"/api": {
"target": "https://my-app.herokuapp.com",
"secure": true,
"changeOrigin": true
}
}
I created a server.js as described in this article so that I can deploy onto Heroku.
// server.js
const express = require('express');
const app = express();
const path = require('path');
// If an incoming request uses
// a protocol other than HTTPS,
// redirect that request to the
// same url but with HTTPS
const forceSSL = function () {
return function (req, res, next) {
if (req.headers['x-forwarded-proto'] !== 'https') {
return res.redirect(
['https://', req.get('Host'), req.url].join('')
);
}
next();
}
}
// Instruct the app
// to use the forceSSL
// middleware
app.use(forceSSL());
// Run the app by serving the static files
// in the dist directory
app.use(express.static(__dirname + '/dist'));
// For all GET requests, send back index.html
// so that PathLocationStrategy can be used
app.get('/*', function (req, res) {
res.sendFile(path.join(__dirname + '/dist/index.html'));
});
// Start the app by listening on the default
// Heroku port
app.listen(process.env.PORT || 4200);
I also set up a post install build in my package.json scripts:
{
"name": "catalog-manager-client",
"version": "0.0.0",
"scripts": {
"ng": "ng",
"start": "node server.js",
"build": "ng build",
"test": "ng test",
"lint": "ng lint",
"e2e": "ng e2e",
"postinstall": "ng build --aot"
},
"private": true,
"dependencies": {
"#angular/animations": "^6.0.3",
"#angular/cdk": "^6.2.1",
"#angular/cli": "~6.0.8",
"#angular/language-service": "^6.0.3",
"#angular/common": "^6.0.3",
"#angular/compiler": "^6.0.3",
"#angular/compiler-cli": "^6.0.3",
"#angular/core": "^6.0.3",
"#angular/flex-layout": "^6.0.0-beta.16",
"#angular/forms": "^6.0.5",
"#angular/http": "^6.0.3",
"#angular/material": "^6.2.1",
"#angular/platform-browser": "^6.0.3",
"#angular/platform-browser-dynamic": "^6.0.3",
"#angular/router": "^6.0.3",
"#swimlane/ngx-charts": "^8.0.2",
"#swimlane/ngx-datatable": "^13.0.1",
"core-js": "^2.5.4",
"express": "^4.16.4",
"hammerjs": "^2.0.8",
"jquery": "^3.3.1",
"moment": "^2.22.2",
"ngx-perfect-scrollbar": "^6.2.0",
"ngx-quill": "^3.2.0",
"rxjs": "^6.0.0",
"rxjs-compat": "^6.2.1",
"rxjs-tslint": "^0.1.4",
"zone.js": "^0.8.26"
},
"devDependencies": {
"#angular-devkit/build-angular": "~0.6.8",
"typescript": "~2.7.2",
"#types/jasmine": "~2.8.6",
"#types/jasminewd2": "~2.0.3",
"#types/node": "~8.9.4",
"codelyzer": "~4.2.1",
"jasmine-core": "~2.99.1",
"jasmine-spec-reporter": "~4.2.1",
"karma": "~1.7.1",
"karma-chrome-launcher": "~2.2.0",
"karma-coverage-istanbul-reporter": "~2.0.0",
"karma-jasmine": "~1.1.1",
"karma-jasmine-html-reporter": "^0.2.2",
"protractor": "~5.3.0",
"ts-node": "~5.0.1",
"tslint": "~5.9.1"
},
"engines": {
"node": "9.11.2",
"npm": "6.5.0"
}
}
I am an Angular novice so I could be making a fundamental mistake, but how do I modify the server.js to use the proxy.conf.json settings?
The explanation falls into the yes, you're making a fundamental mistake category, but I've seen enough similar questions that I thought an explanation might just help the next dev.
The Angular CLI is running a full http server. The Angular UI is fully compiled and the CLI is serving it as static content from the /dist directory.
The proxy.conf.json settings are for the Server run by the Angular CLI, it has nothing to do with your compiled code.
When you move from a local environment to something like Heroku you need a server to take the place of the Angular CLI. This is where all the examples of node.js and express come in. The simple server.js file they walk you through is enough to set up a basic static content server. And that's fine, because your Angular code is static content!
But if you need routing to a dynamic backend server via a proxy.conf.json, well, your simple static server doesn't know anything about that.
In my case, my backend server runs on Koa, so I added static routing to the Angular code.
const router = require('koa-router')();
const body = require('koa-body')({ text: false });
const send = require('koa-send');
const fs = require('fs');
/**
* Code about server routes ommited
*/
async function main(ctx, next) {
//All dynamic routes start with "/api"
if (/\/api\//.test(ctx.path)) {
try {
await next();
}
catch (error) {
if (error instanceof ApplicationError) {
logger.error(error, { data: error.data, stack: error.stack });
ctx.status = error.code;
} else {
ctx.status = 500;
logger.error(error.message, { stack: error.stack });
}
}
return;
} else {
//Not a dynamic route, serve static content
if ((ctx.path != "/") && (fs.existsSync('dist' + ctx.path))) {
await send(ctx, 'dist' + ctx.path);
} else {
await send(ctx, 'dist/index.html');
}
}
}
module.exports = app => {
app.use(main);
app.use(router.routes());
};
NOTE - this isn't a performant solution for any kind of high workload, but if you've got a very small project that doesn't justify spending resources setting up something more scalable, this will work until you get bigger.
Any One looking for Implementation of angular application using proxy api on heroku you can use WebpackDev Server and http-proxy-middleware in server.js
npm install http-proxy-middleware
npm install webpack webpack-dev-server
webpack.config.js
const path = require('path');
module.exports = {
entry:'./src/index.js',//no implemenation needed by default webpack verification
mode: 'development',
devServer: {
historyApiFallback: true,// handle 404 cannot get error after refreshing url
https: true,//secure the server
compress: true,//invalid header multiple url proxy
client: {
webSocketURL: 'ws://0.0.0.0:8080/ws',// handle Invalid header error in heroku port 8080 maps in server.js
},
static: {
directory: path.join(__dirname, '/dist/<app-name>'),
},
proxy: {
/** Same as proxy.conf.json or proxy.conf.js */
' /api1/*': {
target: 'https://<other-heroku-deployed-url>',
changeOrigin:true,
secure:false,
pathRewrite: {
'^/api1':'https://<other-heroku-deployed-url>/api1' },
},
' /api2/*': {
target: 'https://<other-heroku-deployed-url>',
changeOrigin:true,
secure:false,
pathRewrite: {
'^/api2':'https://<other-heroku-deployed-url>/api2' },
}
},
},
};
server.js
const express = require('express');
const { createProxyMiddleware } = require('http-proxy-middleware');
const app = express();
const Webpack = require('webpack');
const WebpackDevServer = require('webpack-dev-server');
/** this is custom js to help proxy in server.js*/
const webpackConfig = require('./webpack.config.js');
const compiler = Webpack(webpackConfig);
const devServerOptions = { ...webpackConfig.devServer, open: true };
const server = new WebpackDevServer(devServerOptions, compiler);
const runServer = async () => {
console.log('Starting server...');
await server.start();
};
runServer();
/** If you have error creating proxy <app-url> to localhost
* Heroku internally redirect the Server port 8080 .
* For that reason we need to open listener port(I used 3000 here) redirect
through http-proxy-middleware*/
app.use("/*", createProxyMiddleware(
{ target: "https://localhost:8080",
ws: true ,
changeOrigin: true,
secure:false,
router: {
'dev.localhost:3000': 'https://localhost:8080',
},}))
app.listen(process.env.PORT || 3000)
npm start or node server.js
i have read some several articles about how to serve static files from create-react-app with express. I have tried everything now. Can someone please help me?
This is how my structure looks like
When i deploy this to Heroku i get following error: main.ac4887ed.js:1 Uncaught SyntaxError: Unexpected token <
Why is this happening? I have tried for some hours now.. Maybe something im missing?
This is the code i have in my server.js file:
if (process.env.NODE_ENV === "production") {
// Set static folder
app.use(express.static("../build"));
app.get("*", (req, res) => {
res.sendFile(path.resolve(__dirname, "../build", "index.html"));
});
My index.html file in public folder:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1,
shrink-to-fit=no">
<meta name="theme-color" content="#000000">
<link rel="manifest" href="%PUBLIC_URL%/manifest.json">
<link rel="shortcut icon" href="%PUBLIC_URL%/quiz.ico">
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
<title>QuizGame</title>
</head>
<body>
<div id="root"></div>
</body>
</html>
And the output from Heroku logs look like this when i try to enter the page:
Am i doing anything wrong?
This is index.html from my build folder:
<!doctype html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1,shrink-to-fit=no"><meta name="theme-color" content="#000000"><link rel="manifest" href="/manifest.json"><link rel="shortcut icon" href="/quiz.ico"><link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous"><title>QuizGame</title></head><body><div id="root"></div><script type="text/javascript" src="/static/js/main.ac4887ed.js"></script></body></html>
This is my package.json file to show dependencies, does it require any dependencies to make it work?
"dependencies": {
"axios": "^0.17.1",
"bcryptjs": "^2.4.3",
"body-parser": "^1.18.2",
"connect-mongo": "^2.0.1",
"express": "^4.16.2",
"express-session": "^1.15.6",
"immutable": "^3.8.2",
"jsonwebtoken": "^8.3.0",
"lodash": "^4.17.4",
"moment": "^2.19.2",
"mongoose": "^5.0.2",
"morgan": "^1.9.0",
"passport": "^0.4.0",
"passport-local": "^1.0.0",
"passport.socketio": "^3.7.0",
"react": "^16.1.1",
"react-bootstrap": "^0.32.4",
"react-countdown-now": "^1.3.0",
"react-dom": "^16.1.1",
"react-redux": "^5.0.5",
"react-router-dom": "^4.3.1",
"react-router-redux": "^4.0.7",
"react-scripts": "1.0.17",
"redux": "^4.0.0",
"redux-promise": "^0.5.3",
"redux-thunk": "^2.1.0",
"ws": "^6.1.0"
},
I figured it out:
In my server.js file I changed
if (process.env.NODE_ENV === "production") {
// Set static folder
app.use(express.static("../build"));
app.get("*", (req, res) => {
res.sendFile(path.resolve(__dirname, "../build", "index.html"));
});
to
if (process.env.NODE_ENV === "production") {
// Set static folder
app.use('/', express.static("build"));
app.get("*", (req, res) => {
res.sendFile(path.resolve(__dirname, "build", "index.html"));
});
}
Thanks for all help!
I have a deployed app with create-react-app. Here are some differences between my setup and yours that you might test:
if ( process.env.MODE !== 'development')
app.use( express.static( `${__dirname}/../build` ) );
if ( process.env.MODE !== 'development') {
app.get('*', (req, res)=>{
res.sendFile(path.join(__dirname, '../build/index.html'));
});
}
I'm using absolute path for both the static path and the get endpoint
These blocks are separated, I'm placing the static middleware before all other middleware, and the get * endpoint at the very bottom of the server file. Only app.listen() is below that.
You'll also notice I'm using path.join rather than path.resolve, and appending one sole argument to __dirname
Make sure you do npm run build and restart the server when it's done.
const express = require("express");
const app = express();
var path = require("path");
var jsonServer = require("json-server");
app.use(express.static("files"));
app.post("/mm", (req, res) => {
res.sendFile(express.static(path.join(__dirname, "/files/hey.`enter code here`html")));
});
app.use("/api", jsonServer.router("./db.json"));
app.listen(9924, () => {
console.log("hello");
});
I have an Angular 5+ application that gets served and runs perfectly fine when using ng serve --aot but when I do ng build --aot && node app.js I get the following errors in the browser:
Uncaught SyntaxError: Unexpected token < runtime.js:1
Uncaught SyntaxError: Unexpected token < polyfills.js:1
Uncaught SyntaxError: Unexpected token < styles.js:1
Uncaught SyntaxError: Unexpected token < vendor.js:1
Uncaught SyntaxError: Unexpected token < main.js:1
Below is my server code and dependencies.
app.js:
const express = require('express');
const path = require('path');
const http = require('http');
const bodyParser = require('body-parser');
// import environmental variables from our variables.env file
require('dotenv').config({ path: 'variables.env' });
// 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/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(`Server running on localhost:${port}`));
package.json dependencies
"dependencies": {
"#angular/animations": "^6.0.3",
"#angular/common": "^6.0.3",
"#angular/compiler": "^6.0.3",
"#angular/core": "^6.0.3",
"#angular/forms": "^6.0.3",
"#angular/http": "^6.0.3",
"#angular/platform-browser": "^6.0.3",
"#angular/platform-browser-dynamic": "^6.0.3",
"#angular/router": "^6.0.3",
"angular-font-awesome": "^3.1.2",
"body-parser": "^1.18.3",
"bootstrap": "^4.1.1",
"buttercms": "^1.1.1",
"core-js": "^2.5.4",
"cosmicjs": "^3.2.10",
"dotenv": "^6.0.0",
"express": "^4.16.3",
"font-awesome": "^4.7.0",
"http": "0.0.0",
"ngx-bootstrap": "^3.0.0",
"ngx-editor": "^3.3.0",
"path": "^0.12.7",
"rxjs": "^6.0.0",
"rxjs-compat": "^6.2.1",
"zone.js": "^0.8.26"
},
Has anybody else ever run into this error and maybe have any idea what I'm doing wrong here?
The < unexpected character usually means it's receiving HTML, such as in a 404 page or a 500 page. You can try navigating to those URLs and see which it is. Likely, the paths to those files are different between the webserver and ng serve. I would try to find what URL those files are actually hosted at and look into what the recommendation is for setting the proper base href. It has been a while since I've looked at the spec for setting the base href, though this question is recent and seems to cover the topic.
Good luck!
The problem is in your frontend section. It is not about your nodejs code.
After ng build go to dist/your project folder say 'something'. Then open the index.html file and change the base URL, which is by default.
If you put your project folder on nginx or apache then your base URL should be
<base href="http://localhost/something/">
and in my case, version of Angular is: 7.1.4
I followed the instructions to create a webpack build environment from the angular.io site: https://angular.io/docs/ts/latest/guide/webpack.html, and got it working. Then, I took the Tour of Heroes tutorial that I got working, and I migrated it to a webpack environment.
If I run the Tour of Heroes using the webpack dev environment (with npm start), it works great. If I then create a production build (with npm run build), and serve the resulting files with node, I cannot get the server to respond when I try to access a URL directly. Below I will outline the steps to create the environment and the problem step-by-step. I believe the solution is to modify my server.js file, but I don't know what is needed.
How to recreate:
Create the webpack build environment per the instructions on the website (link above).
Copy the app folder from the Tour of Heroes liteserver environment to the src folder of the webpack environment
In index.html of the webpack environment, comment out (or remove) all the scripts for polyfills and Configure SystemJS. Index.html should look like this:
<html>
<head>
<base href="/">
<title>Angular 2 QuickStart</title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<!--
<link rel="stylesheet" href="styles.css">
<script src="node_modules/core-js/client/shim.min.js"></script>
<script src="node_modules/zone.js/dist/zone.js"></script>
<script src="node_modules/reflect-metadata/Reflect.js"></script>
<script src="node_modules/systemjs/dist/system.src.js"></script>
<script src="systemjs.config.js"></script>
<script>
System.import('app').catch(function(err){ console.error(err); });
</script>
-->
</head>
<!-- 3. Display the application -->
<body>
<my-app>Loading...</my-app>
</body>
</html>
Modify the package.json so it has what is needed from both environments. Mine looks like this:
{
"name": "angular2-webpack",
"version": "1.0.0",
"description": "A webpack starter for Angular",
"scripts": {
"start": "webpack-dev-server --inline --progress --port 8080",
"test": "karma start",
"build": "rimraf dist && webpack --config config/webpack.prod.js --progress --profile --bail"
},
"licenses": [
{
"type": "MIT",
"url": "https://github.com/angular/angular.io/blob/master/LICENSE"
}
],
"dependencies": {
"#angular/common": "~2.1.1",
"#angular/compiler": "~2.1.1",
"#angular/core": "~2.1.1",
"#angular/forms": "~2.1.1",
"#angular/http": "~2.1.1",
"#angular/platform-browser": "~2.1.1",
"#angular/platform-browser-dynamic": "~2.1.1",
"#angular/router": "~3.1.1",
"angular2-cool-storage": "^1.1.0",
"angular2-in-memory-web-api": "0.0.20",
"bootstrap": "^3.3.6",
"core-js": "^2.4.1",
"reflect-metadata": "^0.1.3",
"rxjs": "5.0.0-beta.12",
"zone.js": "^0.6.25"
},
"devDependencies": {
"#types/core-js": "^0.9.34",
"#types/node": "^6.0.45",
"#types/jasmine": "^2.5.35",
"angular2-template-loader": "^0.4.0",
"awesome-typescript-loader": "^2.2.4",
"css-loader": "^0.23.1",
"extract-text-webpack-plugin": "^1.0.1",
"file-loader": "^0.8.5",
"html-loader": "^0.4.3",
"html-webpack-plugin": "^2.15.0",
"jasmine-core": "^2.4.1",
"karma": "^1.2.0",
"karma-jasmine": "^1.0.2",
"karma-phantomjs-launcher": "^1.0.2",
"karma-sourcemap-loader": "^0.3.7",
"karma-webpack": "^1.8.0",
"null-loader": "^0.1.1",
"phantomjs-prebuilt": "^2.1.7",
"raw-loader": "^0.5.1",
"rimraf": "^2.5.2",
"style-loader": "^0.13.1",
"typescript": "^2.0.3",
"webpack": "^1.13.0",
"webpack-dev-server": "^1.14.1",
"webpack-merge": "^0.14.0"
}
}
From the webpack folder, run npm install
From the webpack folder, run npm run build to create prod build files. This is what the webpack tutorial says to do.
Create a node server environment.
Create a server.js file at the root that looks like this:
var express = require("express");
var app = express();
app.use(function(req, res, next) {
console.log("Request recieved for:", req.url);
next();
});
app.use(express.static('public'));
app.use(function(req, res, next) {
res.status(404);
res.send('404 file not found');
});
app.listen(4040, function() {
console.log("yes: 4040");
});
In the node environment, create a public folder, and put all the files from the dist folder that was created in step 6 into the public folder.
Run the node server with node server.js
Go to localhost:4040. Everything works fine when accessed this way.
Enter this URL directly: http://localhost:4040/heroes
Get the 404 Error.
From the webpack environment if you run npm start, you can go to the URL directly http://localhost:4040/heroes and it works fine.
If you want to see all the code for this, here is the github repo: https://github.com/joshuaforman/heroeswebpack
I've got it figured out. The issue was in the server.js. After more research, I found this: https://expressjs.com/en/starter/static-files.html. Need to add more middleware after the express.static middleware: app.use('/heroes', express.static('public'));. The direct URLs work as needed with this server.js file:
var express = require("express");
var app = express();
app.use(function(req, res, next) {
console.log("Request recieved for:", req.url);
next();
});
app.use(express.static('public'));
app.use('/heroes', express.static('public'));
app.use('/dashboard', express.static('public'));
app.use(function(req, res, next) {
res.status(404);
res.send('404 file not found');
});
app.listen(4040, function() {
console.log("yes: 4040");
});
The app I'm working on also needs to pass params, so if you need to do that, you will need middleware of this format:
app.get('/peopledetails/:uid', function(req, res){
var uid = req.params.uid,
path = req.params[0] ? req.params[0] : 'index.html';
res.sendFile(path, {root: './public'});
});
Thanks to this stack question for the above: Serve Static Files on a Dynamic Route using Express.
Thanks for the help, folks.