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");
});
Related
When I save changes to the app nodemon says 'restarting due to changes'.
But when I refresh my localhost it does not apply the changes.
Everytime I have to run nodemon app.js to see the changes in my app. Why is it happening so?
Below is the app.js code:
const express = require('express')
// create express app
const app = express();
//register view engine
app.set('view engine','ejs');
//listen for requests
app.listen(3000);
app.use((req,res)=>{
console.log('new request made');
console.log('Host:',req.hostname);
console.log('Path:',req.path);
console.log('Method:',req.method);
});
//multiple get request handlers for diff webpages
app.get('/',(req,res)=>{
const blogs = [
{title: 'Yoshi finds eggs', snippet: 'Lorem ipsum dolor sit amet consectetur'},
{title: 'Mario finds stars', snippet: 'Lorem ipsum dolor sit amet consectetur'},
{title: 'How to defeat bowser', snippet: 'Lorem ipsum dolor sit amet consectetur'},
];
res.render('index',{title:'Home',blogs:blogs}); //the path for html webpage is always relative unless provided absolute. the root dir name of the path should be specified.
});
app.get('/about',(req,res)=>{
res.render('about',{title:'About'});
});
app.get('/blogs/create',(req,res)=>{
res.render('create',{title:'Create blog'});
});
app.get('/featured',(req,res)=>{
res.send('<p>Featured page</p>');
});
//redirects
app.get('/about-us',(req,res)=>{
res.redirect('/about'); //express send this response to the browser and automatically set status code to 301.
});
//setup 404 page(this functionality always at last beacuse this displays 404 page when any of the above urls is not found)
app.use((req,res) => {
res.status(404).render('404',{title:'Error 404'});
});
package.json code:
{
"dependencies": {
"ejs": "^3.1.6",
"express": "^4.17.2"
}
}
Versions:
nodemon 2.0.15,
node v16.13.2,
npm 8.1.2
Restarting server is one thing, refreshing browser is another thing. For server watching I use nodemon. Nodemon can see when changes occur in any types of files. But nodemon cannot refresh browser page. For this We may use two additional packages - connect-livereload,livereload.
npm install connect-livereload livereload
Below example:
Folder & File structure :
app.js
const path = require("path");
const livereload = require("livereload");
const connectLivereload = require("connect-livereload");
const express = require("express");
const port = 3000;
const liveReloadServer = livereload.createServer();
liveReloadServer.watch(path.join(__dirname, "views"));
liveReloadServer.server.once("connection", () => {
setTimeout(() => {
liveReloadServer.refresh("/");
}, 50);
});
const app = express();
app.use(connectLivereload());
app.set("view engine", "ejs");
app.get("/", (req, res) => {
res.render("index");
});
app.get("/about", (req, res) => {
res.render("about", { title: "About" });
});
//listen for requests
app.listen(port, () => {
console.log(`Server is listening at http://localhost:${port}`);
});
index.ejs
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>ejs & express</title>
</head>
<body>
<main>
<div>
<h1>This is great and it works perfectly!</h1>
<p>Welcome to using EJS with nodemon and livereload</p>
</div>
</main>
</body>
</html>
about.ejs
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>ejs & express</title>
</head>
<body>
<main>
<div>
<h1>This is great and it works perfectly!</h1>
<p>Welcome to About Page !</p>
</div>
</main>
</body>
</html>
package.json
{
"name": "test",
"version": "1.0.0",
"description": "",
"main": "app.js",
"scripts": {
"start": "nodemon app.js -e ejs",
"watch": "nodemon --ext ejs",
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC",
"dependencies": {
"connect-livereload": "^0.6.1",
"ejs": "^3.1.6",
"express": "^4.17.2",
"livereload": "^0.9.3"
},
"devDependencies": {
"nodemon": "^2.0.15"
}
}
npm run watch
We run app.js with command npm run watch
Now it works like a charm !
Output :
I think that I am doing something wrong with my React router. I am a beginner to React/Redux so any help is really appreciated. It could also be how I configured webpack, but my front end is showing nothing, but I am not getting any errors at all. I'm not sure what the problem is, but my server starts, is able to populate mock data, and webpack compiles, so I think the backend works.
I'm so sorry for the wall of code but I really have no idea where I'm going wrong and I am a huge newbie to setup on this. This is definitely the longest post I've ever written so I appreciate anyone taking a look at it.
My client/src/routes:
import React from 'react'
import {
BrowserRouter as Router,
Route,
Link
} from 'react-router-dom'
import HomePage from './components/home/HomePage';
import { Layout } from './components/Layout';
export const App = () => (
<Layout>
<Switch>
<Route exact path="/" component={HomePage} />
</Switch>
</Layout>
);
export default App;
client/src/Homepage.js:
import React from 'react';
import { Link } from 'react-router-dom';
class HomePage extends React.Component {
render() {
return (
<div id="main">
<h1>Hello</h1>
<p>World</p>
</div>
);
}
}
export default HomePage;
client/src/Layout.js:
import React from 'react';
import { Link } from 'react-router-dom';
export const Layout = props => (
<div className="app-container">
<header>
<Link to="/">
</Link>
</header>
<div className="app-content">{props.children}</div>
<footer>
</footer>
</div>
);
export default Layout;
client/src/App.jsx:
import React from 'react';
import { Provider } from 'react-redux';
import configureStore from '../store/Store';
import { syncHistoryWithStore } from 'react-router-redux';
import routes from '../routes';
import { BrowserRouter as Router } from 'react-router-dom'
const store = configureStore();
export default class AppRoutes extends React.Component {
render() {
return (
<Provider store={store}>
<Router routes={routes} />
</Provider>
);
}
}
client/src/index.js:
import React from 'react';
import ReactDOM from 'react-dom';
import { BrowserRouter as Router } from 'react-router-dom';
import AppRoutes from './startup/App';
ReactDOM.render(
<Router>
<AppRoutes />
</Router>,
document.getElementById('main')
);
server/views/index.ejs:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Buddie!</title>
<link rel="stylesheet" href="/css/style.css">
</head>
<body>
<div id="main"><%- markup -%></div>
<script src="/js/bundle.js"></script>
</body>
</html>
server/app.js:
/* eslint no-console: "off"*/
import path from 'path';
import { Server } from 'http';
import Express from 'express';
import React from 'react';
import { renderToString } from 'react-dom/server';
import { StaticRouter as Router } from 'react-router-dom';
import { App } from '../client/src/startup/App';
const app = new Express();
const server = new Server(app);
const routes = require('../server/routes/index');
// use ejs templates
app.set('view engine', 'ejs');
app.set('views', path.join(__dirname, 'views'));
// define the folder that will be used for static assets
app.use(Express.static(path.join(__dirname, 'static')));
app.use('/api/v1', routes)
// universal routing and rendering
app.get('*', (req, res) => {
let markup = '';
let status = 200;
if (process.env.UNIVERSAL) {
const context = {};
markup = renderToString(
<Router location={req.url} context={context}>
<App />
</Router>,
);
// context.url will contain the URL to redirect to if a <Redirect> was used
if (context.url) {
return res.redirect(302, context.url);
}
if (context.is404) {
status = 404;
}
}
return res.status(status).render('index', { markup });
});
// start the server
const port = process.env.PORT || 3000;
const env = process.env.NODE_ENV || 'production';
server.listen(port, (err) => {
if (err) {
return console.error(err);
}
return console.info(
`
Server running on http://localhost:${port} [${env}]
Universal rendering: ${process.env.UNIVERSAL ? 'enabled' : 'disabled'}
`);
});
webpack config:
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const webpack = require('webpack');
module.exports = {
entry: './client/src/index.js',
output: {
path: path.join(__dirname, 'server', 'static', 'js'),
filename: 'bundle.js'
},
resolve: {
extensions: ['.js', '.jsx', '.json']
},
devServer: {
historyApiFallback: true
},
module: {
rules: [
{
test: /\.jsx?$/,
exclude: /node_modules/,
use: [ 'babel-loader' ],
}
]
},
plugins: [
new HtmlWebpackPlugin({
inject: 'body',
filename: 'index.html'
}),
new webpack.optimize.OccurrenceOrderPlugin(),
new webpack.HotModuleReplacementPlugin(),
new webpack.NoEmitOnErrorsPlugin(),
new webpack.DefinePlugin({
'process.env.NODE_ENV': JSON.stringify('development')
})
]
};
package.json scripts:
"scripts": {
"start": "npm run build:dev && babel-node server/app.js",
"start:dev": "export NODE_ENV=development && npm run build:dev && nodemon --exec babel-node -- src/server.js",
"start:universal": "export UNIVERSAL=true && npm run start",
"start:dev:universal": "export NODE_ENV=development && export UNIVERSAL=true && npm run start:dev",
"build": "NODE_ENV=production webpack -p",
"build:dev": "webpack -d",
"build:dev:watch": "webpack -d --watch"
},
"dependencies": {
"axios": "^0.16.2",
"babel-polyfill": "^6.23.0",
"babel-preset-node6": "^11.0.0",
"babel-preset-react-hmre": "^1.1.1",
"babel-preset-stage-0": "^6.24.1",
"body-parser": "^1.17.2",
"chalk": "^1.1.3",
"classnames": "^2.2.5",
"concurrently": "^3.4.0",
"debug": "^2.6.8",
"ejs": "^2.5.6",
"express": "^4.15.3",
"immutable": "^3.8.1",
"jsx-loader": "^0.13.2",
"morgan": "^1.8.2",
"node-jsx": "^0.13.3",
"nodemon": "^1.11.0",
"normalizr": "^3.2.3",
"pg": "^6.2.4",
"react": "^15.6.1",
"react-addons-test-utils": "15.0.2",
"react-dom": "^15.6.1",
"react-hot-loader": "^3.0.0-beta.7",
"react-redux": "^5.0.5",
"react-router-dom": "^4.1.1",
"react-router-redux": "^4.0.8",
"react-scripts": "^1.0.7",
"react-slick": "^0.14.11",
"redux": "^3.7.0",
"redux-logger": "^3.0.6",
"redux-mock-store": "1.0.2",
"redux-thunk": "^2.2.0",
"sequelize": "^4.1.0",
"sequelize-cli": "^2.7.0",
"webpack": "^3.0.0",
"webpack-dev-server": "^2.4.5",
"yargs": "^8.0.2"
},
"proxy": "http://localhost:8000"
In your src/client/App.js file, I noticed you're importing syncHistoryWithStore from react-router-redux. I'm fairly confident RR4 and the old version of react-router-redux are not compatible with one another. The new version installed with #next does not contain syncHistoryWithStore.
This might be your issue.
Just noticed something in this code block
if (process.env.UNIVERSAL) {
const context = {};
markup = renderToString(
<Router location={req.url} context={context}>
<App />
</Router>,
);
// context.url will contain the URL to redirect to if a <Redirect> was used
if (context.url) {
return res.redirect(302, context.url);
}
if (context.is404) {
status = 404;
}
}
You are assigning an empty object to context, passing an empty context to your<Router />and then checking for context.url and context.is404, which are both going to be undefinedeverytime you check them! Maybe you meant context = {...context} ? Really unsure whether this affects rendering (pretty sure it does not) but it's worth mentioning.
If you are not running this code as universal, then it will never update the markup and it will always be empty hence will not print anything.
One small correction in your code: in index.ejs
remove last '-' in markup tag it should be <%- markup %>
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.
So i have an Angular 2 app that runs locally without problems. When deploying my app using heroku i get following errors:
>SyntaxError: expected expression, got '<'
><!DOCTYPE html>
>shim.min.js (Zeile 1)
>
>SyntaxError: expected expression, got '<'
><!DOCTYPE html>
>zone.js (Zeile 1)
>
>SyntaxError: expected expression, got '<'
><!DOCTYPE html>
>Reflect.js (Zeile 1)
>
>SyntaxError: expected expression, got '<'
><!DOCTYPE html>
>system.src.js (Zeile 1)
>
>ReferenceError: System is not defined
>systemj...nfig.js (Zeile 6, Spalte 3)
>
>ReferenceError: System is not defined
>mean1nv...app.com (Zeile 24, Spalte 7)
There are similar posts that suggest all kind of changes but i dont know where it breaks in my code. I feel kind of blind, i deployed a similar app before without problems and I cant find the difference.
server.js
var express = require('express');
var path = require('path');
var bodyParser = require('body-parser');
var items = require('./routes/items');
var app = express();
app.set('port', (process.env.PORT || 3000));
app.use(express.static(path.join(__dirname,'client')));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({extended: false}));
app.use('/api', items);
app.all('/*', function(req, res, next) {
// Just send the index.html for other files to support HTML5Mode
res.sendFile(path.join(__dirname, './client', 'index.html'));
});
app.listen(app.get('port'), function() {
console.log('Node app is running on port', app.get('port'));
});
package.json (server side)
{
"name": "namex",
"version": "1.0.0",
"description": "descx",
"main": "server.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC",
"dependencies": {
"body-parser": "^1.15.2",
"ejs": "^2.5.5",
"express": "^4.14.0",
"mongojs": "^2.4.0",
"ng2-pagination": "^1.0.1"
}
}
systemjs.config.js
(function (global) {
System.config({
paths: {
// paths serve as alias
'npm:': 'node_modules/'
},
// map tells the System loader where to look for things
map: {
// our app is within the app folder
app: 'app',
// angular bundles
'#angular/core': 'npm:#angular/core/bundles/core.umd.js',
'#angular/common': 'npm:#angular/common/bundles/common.umd.js',
'#angular/compiler': 'npm:#angular/compiler/bundles/compiler.umd.js',
'#angular/platform-browser': 'npm:#angular/platform-browser/bundles/platform-browser.umd.js',
'#angular/platform-browser-dynamic': 'npm:#angular/platform-browser-dynamic/bundles/platform-browser-dynamic.umd.js',
'#angular/http': 'npm:#angular/http/bundles/http.umd.js',
'#angular/router': 'npm:#angular/router/bundles/router.umd.js',
'#angular/forms': 'npm:#angular/forms/bundles/forms.umd.js',
// other libraries
'ng2-pagination': 'npm:ng2-pagination/dist/',
'rxjs': 'npm:rxjs',
'angular-in-memory-web-api': 'npm:angular-in-memory-web-api/bundles/in-memory-web-api.umd.js',
'angular2-jwt': 'node_modules/angular2-jwt/angular2-jwt.js'
},
// packages tells the System loader how to load when no filename and/or no extension
packages: {
app: {
main: './main.js',
defaultExtension: 'js'
},
'angular2-jwt': {
"defaultExtension":'js'
},
rxjs: {
defaultExtension: 'js'
},
'ng2-pagination': {
defaultExtension: 'js', main: 'ng2-pagination.js'
}
}
});
})(this);
index.html
<!DOCTYPE html>
<html>
<head>
<title>ngAuth0 App</title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="bower_components/bootstrap/dist/css/bootstrap.css">
<link rel="stylesheet" href="styles.css">
<link href="https://fonts.googleapis.com/css?family=Philosopher" rel="stylesheet" type="text/css">
<script src="https://cdn.auth0.com/js/lock/10.6/lock.min.js"></script>
<!-- Polyfill(s) for older browsers -->
<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>
<body>
<base href="/">
<my-app>Loading ...</my-app>
</body>
</html>
You should copy polyfills with the app when deployed node_modules is not available.
if you copy them to the same folder where systemjs.config.js
<script src="shim.min.js"></script>
<script src="zone.js"></script>
<script src="Reflect.js"></script>
<script src="system.src.js"></script>
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.