Search code examples
reactjsexpresspm2

react express pm2 deployment


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'
    }
  }
};

Solution

  • 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"
      }
     ...
    }