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 : 'git@github.com:repo.git',
//      path : '/var/www/production',
      'post-deploy' : 'cd client && npm run build'
    }
  }
};
Indrajeet Latthe
  • 374
  • 1
  • 8
  • 22
  • 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.json – arjnt Jun 12 '19 at 10:48
  • 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. – Abhishek Singh Jun 13 '19 at 11:34
  • 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. – Muljayan Jun 14 '19 at 08:59

2 Answers2

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"
  }
 ...
} 
PrivateOmega
  • 2,509
  • 1
  • 17
  • 27
  • 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 :P – Indrajeet Latthe Jun 13 '19 at 08:11
  • @IndrajeetLatthe Sure. No worries. – PrivateOmega Jun 13 '19 at 08:18
  • Just one question if I follow this I will get features of pm2? Like what if server get restarted? – Indrajeet Latthe Jun 14 '19 at 17:56
  • 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. – PrivateOmega Jun 14 '19 at 18:05
  • One more question, I also have gitlab enterprise so is it possible that I use that CI feature too? And can automate? – Indrajeet Latthe Jun 14 '19 at 18:18
  • 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? – PrivateOmega Jun 14 '19 at 18:20
  • Seems I'm having few errors, maybe because I used to start server's index using babel-node? – Indrajeet Latthe Jun 14 '19 at 18:28
  • 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. – PrivateOmega Jun 14 '19 at 18:29
  • 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. – Indrajeet Latthe Jun 14 '19 at 18:53
  • 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/public – PrivateOmega Jun 14 '19 at 18:57
  • 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. – Indrajeet Latthe Jun 17 '19 at 10:57
  • @IndrajeetLatthe Which feature of ES6 are you using for you to depend transpilation of the code with babel? – PrivateOmega Jun 17 '19 at 10:59
  • 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... – Indrajeet Latthe Jun 17 '19 at 12:01
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 : 'git@github.com:repo.git',
//      path : '/var/www/production',
      'post-deploy' : 'cd client && npm run build'
    }
  }
}

Tell me if it not solve your problem.

Le Quang
  • 515
  • 4
  • 10