I had to add this code to my project that has Express as a back end and React as a front end in order to deploy to Heroku (along with some other adjustments like the heroku-postbuild field). I am new to Express/Node and read process.env is the Node environment, but what does it mean to just check if it exists/is set to true? I see people use it to set process.env.NODE_ENV to development or production but am not familiar with this usage.
if (process.env.NODE_ENV) {
app.use(express.static('client/build'));
const path = require('path');
app.get('*', (req, res) => {
res.sendFile(path.resolve(__dirname, 'client', 'build', 'index.html'));
});
}
if condition is there to check if NODE_ENV has been set or not (e.g., "" will evaluate to false).
* inside app.get() is a wildcard that matches any route a user could type in a browser for this server (i.e., http://localhost/*).
So what it does is that if the NODE_ENV is set to something (not necessarily dev or production environment), then for any route (or any web page on the site) requested, you are going to send the client/build/index.html file back - basically render an index (main) page of the website.
This environment variable (i.e., NODE_ENV) is defined, well, as an environment variable in some computer (e.g., VM somewhere on the cloud like Heroku). On a cloud, it would probably have "production" set as a value. On your laptop, it may not have anything as you are just testing it out, playing with it, etc. But production environment is quite important because this is where users of your app can see and use your app.
According to Express.js docs, "Setting NODE_ENV to “production” makes Express cache view templates; cache CSS files generated from CSS extensions; and generate less verbose error messages." Ref: https://expressjs.com/en/advanced/best-practice-performance.html
My guess is that it sends this index.html file while on Heroku, and does something else (depending on defined routes) when it is not.
This link may also help: https://dev.to/flippedcoding/difference-between-development-stage-and-production-d0p
P.S. Natalie noted that Heroku sets Node.js applications to use NODE_ENV=production by default since 2015. Ref: https://devcenter.heroku.com/changelog-items/688
Related
How to host an application React js with node js backend. Couldn't find anything on the internet. Do I need to run the
build
command on the backend? Help me please.
Thanks in advance.
The way I do it:
I build my react project and host it on the server.
As for node js, I run it on it’s own, and use Pm2 to run it on the server ( https://pm2.keymetrics.io/docs/usage/quick-start/ ) but there’s plenty of other ways you can find on google.
I hope I answered your question
I suggest you use Heroku, you get to host your full stack application for free, directly from your GitHub reposity, it takes care of automatic redeploys whenever you push something on your repo.
The only – slight – downside is having to wait ~5 seconds for the server to start up if your app hasn't been visited for a while and becomes idle (if you use a free option that is).
There are plenty of tutorials on how to do so.
As for serving the static version to your app in production — this could be of use:
server.js
/* If in production mode - serve compressed/static react content to server. i.e. what would be otherwise localhost:5000 would display frontend content.
/!\ Do not forget to generate Procfile and script for Heroku to insure proper generation of "build" directory /!\ */
if (process.env.NODE_ENV === "production") {
app.use(express.static(path.join(__dirname, "../frontend/build")));
app.get("*", (req, res) => {
res.sendFile(path.join(__dirname, "../frontend", "build", "index.html"));
});
}
Heroku will take care of it automatically if you tell your server to serve the static version with the code above.
There is also Glitch.com
I have Vue.JS front app with nodeJS backend based on expressJS. ExpressJS also used as web server for statically built Vue.JS app
Front app communicates with express backend via rest and websocket. It uses url host from window.location instance and easily communicates with backend
In production mode, when built application in static expressJS server area, everything work perfect
In dev mode, Vue use it's own web server, and backend urls based on window.location are incorrect because no expresJS on same host and port.
So my question is it possible change some code blocks if running in dev mode ?
Like something this :
if( devmode)
{
const url = "http://somebackendhost/rest"
}
else {
const url = location.host ....
}
}
I will assume you are developing your Vue app using Vue CLI
Changing app behavior depending on environment
In Vue CLI you can use Environment Variables
if(process.env.NODE_ENV === "development")
{
}
This works thanks to Webpack's Define plugin and big advantage is that process.env.NODE_ENV is replaced at build time by the real value. So in production build Webpack will see just if("production" === "development") {} and happily removes the code in optimization phase because it knows this can never be true
Better solution
But I would not use this approach for your problem. Using different API server (not same as the server used for serving Vue SPA) can easily lead to CORS problems
Exactly for this use case, Vue CLI (and Webpack Dev server used under the hood) supports proxying
vue.config.js
module.exports = {
devServer: {
proxy: {
'^/api': {
target: 'http://localhost:58300/',
ws: true, // websockets
changeOrigin: true,
}
}
},
},
This config makes Vue Dev server to proxy any request to /api to other server running at http://localhost:58300/ (your node/express app) and change the origin (so browser thinks response came from the dev server)
All of this can be done without Vue CLI but you will need to set it up by yourself in Webpack config...
The problem
You can't access this information from your browser.
But there are three solutions:
Solution #1
On compilation time create a variable in code which defines devmode (const devmode = true;)
Solution #2
Because your bundler can minify your variable names or changing the scope for security reasons, may be the situation where you can't access it.
So second solution is to define devmode in your localStorage.
Solution #3
Third solution is almost the best.
If you are developing, you are probably accessing your web app via localhost.
location.hostname will return the name of host, so you can make something like:
const devmode = location.hotname == 'localhost';
Best solution
Do not do this. Develop a fully working web app using local REST API and define the URL of REST API in some variable, so when you are preparing your production app, you or compiler just changes the URL adress variable in code of your REST API.
Why is this the best solution?
Because it do not impacts your end-user's performance and they will be loading less code, which is the best practise.
Post Scriptum
Don't forget to remove all devmode codepaths when compiling production version!
I was learning NodeJs advance concepts after going through the basic course.
I am following stepehen grinder course where we would be using his folliwng repo
I was initially walking through the repo where somethings were sort of new to me
My main question evolves around his index.js file in repo
This isn't prime question but first he have done something like this
require('./routes/authRoutes')(app);
require('./routes/blogRoutes')(app);
Is this equivalent to something like this
const auth = require('./routes/auth.js')
const profile = require("./routes/profile.js")
app.use('/auth', auth)
app.use('/profile', profile)
Second, Primary question, In his index.js file he have done something like this
if (['production'].includes(process.env.NODE_ENV)) {
app.use(express.static('client/build'));
const path = require('path');
app.get('*', (req, res) => {
res.sendFile(path.resolve('client', 'build', 'index.html'));
});
}
This does not make sense to me at all, can someone explain me what does the above code do? and an interesting article which can help me comprehend.
Also, Can someone please tell me what does path module do? I went through their do documentation and was able to comprehend that path allows us to access files outside our node project. Is that correct understanding?
Concerning you first question:
It's not the same. app.use(...) defines a middleware that gets executed on all and every routes. Here, both routes files export a function which takes one argument: the application (ExpressJS server) instance.
So, require('./routes/blogRoutes') gives you a function app => {...}, and by adding parenthesis and the app variable as a parameter you immediately execute this function with the current server (application) instance. Which in the end will create all the routes defined in the route file.
Concerning your second question:
The if is testing if the NODE_ENV variable is equal to production. If it is in production mode, app.use(express.static('client/build')); tells ExpressJS to serve static files from the client/build folder.
The rest of the code app.get('*', ...) send the index.html file for calls made to any route except the one defined in the two routes files.
The path.resolve only role is to easily build the absolute path of the index.html file.
this is the api call i want to make
http://localhost:3000/api/getUserName
but i am using it in proxy in package.json. i tried to build the app but then call goes to
http://localhost:5000/api/getUserName
i am serving on 5000 so its taking api call also on 5000. so i want to mention 3000 om build. also i have check on google and it says mention it in .ENV cause proxy is not for production, but can anyone provide me .ENV structure that can show to me how to use it from env?
During development, the practice is to use to two servers; one server for the client side, generally localhost:3000, and a second one for the server, generally localhost:5000. When you build for production, reactjs compiles and builds such that it becomes a static resource for the server and the server serves these files.So, your app will be served, wherever you host your server. The production config will depend on what you folder structure looks like. If you are using CRA for your application, you can use this piece of code:
I am assuming that you have your client directory inside your server directory.
if(process.env.NODE_ENV === 'production'){
app.use(express.static('client/build') //path to your build directory
const path = require('path');
app.get('*', (req, res)=>{
res.sendFile(path.resolve(__dirname, 'build','public','index.html');
}
}
Again, I am assuming that you are using CRA to bootstrap your react application and have your client directory inside your server directory. If you are using webpack, then the config will change to indicate the path of the build directory.
I have an Express.js app for which the production environment name is foo. So I start my app like NODE_ENV=foo node app.js. In general this is a bad idea.
Now my app knows it is in production, but Express doesn't know. Regardless of whether this is a good idea or not in general, is there a way to tell Express that it's running in production?
I think you're misusing the NODE_ENV setting. If you would set the value to production, ie. you're running Node in production enviroment (that you happen to call foo), Express would read it automatically.
You can use app.set('env', 'production'); to set the mode if you really must use NODE_ENV for other purposes. Then you would need a way to tell your app if it is in production mode, eg.
if (process.env.NODE_ENV === 'foo') {
app.set('env', 'production');
}
or introduce another environment variable and use its value: app.set('env', process.env.REAL_NODE_ENV); and then run with NODE_ENV=foo REAL_NODE_ENV=production node app.js
I would still suggest to use another environment variable than NODE_ENV to tell your app it's running on foo.