express server starting react client - node.js

Until now, I have been using create-react-app for my projects, with the express-server and the react client each in their own folders.
However, I am now trying to avoid create-react-app in order to really understand how everything work under the hood. I am reading an Hacker Noon article that explains how to setup react with typescript and webpack. In this article they also have the express server at the root of the client which compiles everything itself:
const path = require('path'),
express = require('express'),
webpack = require('webpack'),
webpackConfig = require('./webpack.config.js'),
app = express(),
port = process.env.PORT || 3000;
app.listen(port, () => { console.log(`App is listening on port ${port}`) });
app.get('/', (req, res) => {
res.sendFile(path.resolve(__dirname, 'dist', 'index.html'));
});
let compiler = webpack(webpackConfig);
app.use(require('webpack-dev-middleware')(compiler, {
noInfo: true, publicPath: webpackConfig.output.publicPath, stats: { colors: true }
}));
app.use(require('webpack-hot-middleware')(compiler));
app.use(express.static(path.resolve(__dirname, 'dist')));
In the end, the start command looks like it:
"start": "npm run build && node server.js"
So I assume the client and the server start on the same port.
Why would you do such a thing? Are there any pros and cons?

It is true that this will allow your development to happen using the same server as express and that web pack will continuously update your dist/index.html file with whatever updates you make to your file. There's not too much of a disadvantage to this as this is just for development. But typically on prod you'll have a single built file that you will serve. And it will not web pack-dev-middleware to be running. Once you've built your server. For the purposes of production it might be possible that you'll only need static assets. But typically, even the server which serves mostly client files will potentially need a server if you want to do server side rendering and/or code splitting.
The command: "npm run build && node server.js" will run the bash/cmd commands into the terminal. npm run build is one step because of the use of && it will if that command succeeds, run the next command which is node server.js which is a strange command I would probably run node ./ (and put the server as index.js) or at least just write node server.
What I'd prefer to see in your package.json:
"start": "yarn build && node ./"
That would be possible if you mv server.js index.js (and npm i -g yarn).
Another thing to note, and look into is what the build step does.
Further Explanation:
The command runs the build step so check what your "build": key runs in your package.json.
This command will probably not exit with the code 1 (any exit code of a terminal process that is above 0 will result in an error and will not pass the &&).
Presumably, the build process described in the package.json will take all the javascript and CSS files and put them into the index.html file which will then be sent to the client side whenever someone access the '/' path.
After that succeeds, it will start the server that you put the code to above.
res.sendFile(path.resolve(__dirname, 'dist', 'index.html'));
will happen if anybody comes across the '/' path.

Related

How to create Node.js Express app serving a Vue.js SPA?

I'm trying to set up a Node.js project that uses Express to provide a few backend APIs and serve a SPA built with Vue.js.
When I use the Vue cli to initialize a project, I get e.g. src/main.ts main file and commands npm run serve to run a dev server and watch for changes and npm run build to build a production release.
When I use the Express application generator to create a project, I get ./app.js main file and npm start to start the server and watch for changes.
How can I combine these into a single project, both served by the same Express server? Preferably so that a single command would watch + update changes to both server and client? I want to use Vue single file components and TypeScript, which (probably?) require a build step.
(I don't need dynamic server-side rendering of Vue templates, just the static SPA app provided. I prefer TypeScript, but JavaScript answers are fine as well.)
These will be different for your dev and prod environments...
For development look into concurrently - it basically allows you to create a single script in your package.json to start both the client and server concurrently and will watch for changes etc...
For production, you would need something like this in your app.js:
if (process.env.NODE_ENV === 'production') {
app.use(express.static('client/build'));
const path = require('path');
app.get('*', (req, res) => {
res.sendFile(path.resolve(__dirname, 'client', 'build', 'index.html'));
});
}
(The code above assumes that your directory structure has a client folder with a build folder after having run npm run build I'm more familiar with React than Vue... but the logic should be the same...)

Starting Angular application as a default of a NodeJS project

I have a NodeJS application and an Angular 6 as a frontend.
The project looks like:
-> Node Project
---> src
---> Client_App (Anuglar)
To run the application, I need to follow those commands and start the server and angular separately, like:
-> node start
-> cd src/Client_App
-> ng serve
I need to start the two application with one single command or to add my dist file of Angular to be run at the start of my NodeJS, which is using Jade right now.
I am still new to NodeJS and still don't know how to configure it.
Anybody can help? Thanks
Edited:
I have tried now to add the dist folder to my views folder and run it within the app.js
app.get('/', function (req, res, next) {
res.sendFile(path.join(__dirname + '/app_server/views/ngapp/index.html'));
});
But I am receiving the error, that my .js and .css folders are not found:
When you build your application with the CLI ng build --prod, you get a dist folder : this folder contains all of your application, bundled into different files (feel free to look at them).
To be able to create a .ZIP file with that, you will need two things :
this dist folder
an http server
You have the first one, but not the second one.
All you need is a very simple server. For instance, http-server on NPM can do that. By installing it as a dev dependency, you could create a command in your package.json file
"deploy-locally": "http-server ./dist"
And now run it with
npm run deploy-locally
Or even better,
"start": "http-server ./dist"
And run with
npm start
If you don't want to use a NPM package (or forced to use NodeJS), simply create a basic http server in a JS file and run it with your command line (sorry, can't help on that, not into nodeJS right now).
You can create a new route and pass in app.route as express.static as below,
var express = require('express');
var path = require('path');
var bodyParser = require('body-parser');
var app = express();
app.use(express.static(path.join(__dirname, 'dist')));
make sure, u have build version of angular application by running this command,
ng build --prod --build-optimizer
You would need express to install in this case. express has amazing ways to handle all this

How to set up dev and API server from create-react-app?

I've started a new app with create-react-app, and ejected from that. I made a small express server as follows:
const express = require('express');
const app = express();
if(process.env.NODE_ENV === 'production') {
app.use(express.static('build'));
}
const port = process.env.PORT || 3000;
app.listen(port, () => {
console.log(`Server started at: http://localhost:${port}/`);
});
In package.json I've added a line, "proxy": http://localhost:3000", as well as switching the commands:
"scripts": {
"run": "npm-run-all -p watch-css start-js",
"start": "node server.js",
},
run used to be start.
However now of course when I run npm start and go to localhost:3000, I get Cannot GET /. I need this server to receive and return local API calls I'll be making from my app, but I also want it to run a hot-reloading dev server just like the old npm start (now npm run) command did. How do I do this?
Some time ago I made a fork of the create-react-app repository adding webpack watch option because of this same reason. It might help you.
Just to add more info, I really invested time looking on how to get webpackdevserver to build the "bundle.js", and found that it is not possible because it loads the bundle into memory but doesn't persist it, so the file is never created. The only way available is the webpack watch option but, I don't understand why the create-react-app team can't add it to the repo, it's a really requested feature, and there are more forks than mine that solves this issue. So, you have three options:
Use the proxy server in package.json (if it works)
Make your own fork and add the watch option, or use an existing one
Don't use create-react-app

Cannot get correct static files after refreshing except index page

When I refresh page on index route (/) and login page (/login), it works fine.
However, my website gets error as I refresh on other routes, for example /user/123456.
Because no matter what the request is, the browser always gets HTML file.
Thus, both of the content in main.css and main.js are HTML, and the browser error.
I have already read the README of create-react-app.
Whether I use serve package ($serve -s build -p 80) or express, it will produce the strange bug.
Following is my server code:
//server.js
const express = require('express');
const path = require('path');
app.use(express.static(path.join(__dirname, 'build')));
app.get('/*', (req, res) => {
res.sendFile(path.join(__dirname, 'build', 'index.html'));
});
const PORT = process.env.PORT || 80;
app.listen(PORT, () => {
console.log(`Production Express server running at localhost:${PORT}`);
});
Edit: I have figured out where caused the problem.
I created a new project, and compared it to mine. The path of static files in the new project is absolute, but in my project is relative.
As a result, I delete "homepage": "." in the package.json.
//package.json
{ ....
dependencies:{....},
....,
- "homepage": "."
}
Everything works as expected now. How am I careless...
I have figured out where caused the problem.
I created a new project, and compared it to mine. The path of static files in the new project is absolute, but in my project is relative.
As a result, I delete "homepage": "." in the package.json.
//package.json
{ ....
dependencies:{....},
....,
- "homepage": "."
}
Everything works as expected now. How am I careless...
If your route /user/** is defined after app.get('/*', ... it might not match because /* gets all the requests and returns you index.html.
Try without the * or declare the other routes before.
First, I thought you misunderstood the server part. In your case, you use serve as your server. This is a static server provided by [serve]. If you want to use your own server.js, you should run node server.js or node server.
I also did the same things with you and have no this issue. The followings are what I did:
create-react-app my-app
npm run build
sudo serve -s build -p 80 (sudo for port under 1024)
And I got the results:
/user/321
I guessed you might forget to build the script. You can try the followings:
remove build/ folder
run npm run build again
Advise: If you want to focus on front-end, you can just use [serve]. It will be easy for you to focus on what you need.

Best way to set a Node/Express app to live or production mode

I'm currently in the process of making my node/express app into a production deployment, and as part of this, I need to make it run in a production friendly mode (e.g. fewer debugs to stdOut, write logs to different places, tell users less when errors occur etc.).
I'm struggling a bit with this, as whenever I set a variable of virtually any kind to invoke a 'production' mode, it doesn't take affect for the program as it runs.
When launched in dev mode, my code runs through Gulp, and runs this script:
#!/usr/bin/env node
var debug = require('debug')('ascema');
var app = require('../app');
app.set('port', process.env.PORT || 3000);
var server = app.listen(app.get('port'), function() {
debug('Express server listening on port ' + server.address().port);
});
Which, as you know, is just the generated launch script from the express generator.
In order to run it in live mode, I created an alternative startup for the server to use (I could hardly use gulp anyway) and live.js runs this:
#!/usr/bin/env node
var app = require('./app.js');
app.set('env', 'production');
console.log('running on Port 3000');
var server = app.listen(3000);
But, when I use app.get('env') anywhere in the app (e.g. in app.js or in it's various dependencies) it still returns 'development' and so none of my production tasks happen.
What am I doing wrong here?
Many thanks.
You have to set the NODE_ENV variable on the command line when you execute your NodeJS application.
For example:
NODE_ENV=production node app.js
Also, NODE_ENV is an environment variable so if set it in the environment on your server, you will not need to provide it every time you execute your application so node app.js will do.
You can set your environment variables in the /etc/environment file. Here are more details on that.
By using NPM you might to be used the follow scripts in the package.json:
"scripts": {
"start": "nodemon ./bin/www",
"dev_win": "set NODE_ENV=development && node ./bin/www >> /romba/log/api.log 2>> /romba/log/error.log",
"prod_win": "set NODE_ENV=production && node ./bin/www >> /romba/log/api.log 2>> /romba/log/error.log"
"prod_nix": "NODE_ENV=production node ./bin/www >> /romba/log/api.log 2>> /romba/log/_error.log"
},...
To start one of the script use the command:
npm run-script prod_win
In the JavaScript code I check the condition:
process.env.NODE_ENV.indexOf('production') > -1
or with Express.js
app.use((err, req, res, next) => {
req.app.get('env') === 'development' ? ...

Resources