react express pm2 deployment
Asked Answered
R

2

9

Scenario

I've made react app as well as a express server for API and both are separate. I've not included react folder in express app. I'm looking forward to deploy it using pre/post scripts using PM2 but I'm having hard time achieving exactly what is in my mind.

Goal

  1. I want to run npm install for both client and server as I might remove/add package if needed later.
  2. I'm thinking like after npm install I want to build react app and then move that folder for serving to express( I don't know if it's possible to give directory path which is out of parent for express static contents).
  3. Then I want to start the express server which will eventually serve react build files.

For now my directory structure is

.
├── client
├── ecosystem.config.js
└── server

I'm mostly confused as I don't came across any resource where this is achieved. Also I'm not sure if this is even possible with pm2 deploy scripts or I need to write my own bash script which will do some stuff then pm2 will only start server.

This is only what I did which seems totally wrong

ecosystem.config.js

module.exports = {
  apps : [{
    name: 'API',
    cwd: 'server',
    script: 'server.js',
    args: 'one two',
    instances: 1,
    autorestart: true,
    watch: false,
    max_memory_restart: '1G',
    env_production: {
      NODE_ENV: 'production'
    }
  }],

  deploy : {
    production : {
      user : 'node',
//      host : '212.83.163.1',
//      ref  : 'origin/master',
//      repo : '[email protected]:repo.git',
//      path : '/var/www/production',
      'post-deploy' : 'cd client && npm run build'
    }
  }
};
Rosenblast answered 9/6, 2019 at 10:42 Comment(3)
Can you add in your directory structure where you have placed package.json relative to client and server? As well as post the highlights of your package.jsonLotta
You can use a task runner ( grunt or gulp) in order to achieve this. And create the respective deployment scripts for the same and order them accordingly.Cervelat
Why dont you write a bashscript to automate the dependancy installation, getting build file and then moving the build files into server. You'd have more controll that way.Papageno
G
2

Since you have both server and client together, I am assuming it is being developed in a monorepo.

For these kind of purposes I would suggest to go with yarn workspaces as it satisfies your first requirement on its own(npm install for both client and server).

To enable workspaces in yarn versions prior to 1.0, execute to enable it.

yarn config set workspaces-experimental true

Then add a package.json in the folder(workspace root) outside server and client folders along with whatever other package.json keys you require. Also install common dependencies directly here instead of installing them individually in both of the package.json files inside server and client. (Don't forget to delete node_modules folder inside them as a new one would be created in workspace root with all dependencies installed together during yarn install).

{
  "private": true,
  "workspaces": ["server", "client"]
}

Add the following to your server index.js file.

app.use(express.static(path.join(__dirname, 'public')));
app.get('*', (req,res) =>{
    res.sendFile(path.join(__dirname+'/public/index.html'));
});

And add npm script to the package.json in workspace root.

{
 ...
 "scripts": {
       "start": "yarn --cwd client react-scripts build && mv ./client/build ./server/public && node ./server/index.js"
  }
 ...
} 
Geest answered 12/6, 2019 at 11:6 Comment(13)
Very sorry I didn't get to work on this, I'm still little busy as I've other tasks, I just commented on this just people don't assume I'm not looking into this. Will tell you if this works out or not :PRosenblast
@IndrajeetLatthe Sure. No worries.Geest
Just one question if I follow this I will get features of pm2? Like what if server get restarted?Rosenblast
Well pm2 is an application manager, so instead of node ./server/index.js you need to type in pm2 start ./server/index.js in the start script of last package.json.Geest
One more question, I also have gitlab enterprise so is it possible that I use that CI feature too? And can automate?Rosenblast
Yes ofcourse, continuous integration is independent of whatever you do in the code, btw just curious, why do you have CI for? Running any tests or any automation that you are gonna do?Geest
Seems I'm having few errors, maybe because I used to start server's index using babel-node?Rosenblast
I am not sure. It sounds like an entirely new question altogether. Btw it would be helpful for others if you marker either of the 2 answers as correct.Geest
mv: cannot move './client/build' to './server/public/build': Directory not empty I tried both removing build and public folder but I'm still getting this error.Rosenblast
Ok that means you already have a folder at Destination with same name I guess and don't want to merge the folders. Can you try cp -r ./client/build ./server/publicGeest
This works perfect if my server index is not with ES6 code and I think I should've cleared it before that I'm using babel-node at server side. For now I'm deciding to build/transpile server side code too before running server. I'm having problem for that too. Seems I've to create one more ticket just for that.Rosenblast
@IndrajeetLatthe Which feature of ES6 are you using for you to depend transpilation of the code with babel?Geest
I'm having problem for import statements, I don't know why. Also I tried installing @babel/cli and tried to generate/transpie code but it just outputs same code...Rosenblast
R
0

My idea for your problem :

  1. You can combine package.json of both client and server.

  2. I have some confuse with your question .

  3. You can config as :
module.exports = {
  apps : [{
    name: 'API',
    cwd: 'server',
    script: 'npm run react && npm run express', //you must config npm run react && npm run express before use them  
    args: 'one two',
    instances: 1,
    autorestart: true,
    watch: false,
    max_memory_restart: '1G',
    env_production: {
      NODE_ENV: 'production'
    }
  }],

  deploy : {
    production : {
      user : 'node',
//      host : '212.83.163.1',
//      ref  : 'origin/master',
//      repo : '[email protected]:repo.git',
//      path : '/var/www/production',
      'post-deploy' : 'cd client && npm run build'
    }
  }
}

Tell me if it not solve your problem.

Radman answered 12/6, 2019 at 10:36 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.