Home > Software design >  How to handle deploying and building a Typescript Node.js project with pm2 post-deploy
How to handle deploying and building a Typescript Node.js project with pm2 post-deploy

Time:04-08

My project is a Node.js Express server written in Typescript using ESM.

Currently, my deployment process is as follows:

  • Run deploy script on my local machine using pm2
  • Pull in latest changes from git repo onto Ubuntu server
  • Server runs npm install and builds Typescript Node.js project
  • Runs starter script in build/dist directory

I have to build the app on my server because I do not push my /dist folder to my git repo, and the process is dependent on deleting and cloning the newest version of my repo.

But since I am deploying with the production flag, it only installs my dependencies (not my devDependencies). I've had to move dependencies over from devDependencies just so my app can build on the server without any complaints.

For example, I currently want to setup babel with my project because I'm having trouble unit testing ES Modules (a story for another time). But because of my current setup, I need to install all my babel dependencies as regular dependencies and not devDependencies. This upsets me. I can't seem to find the right solution for my use case.

Am I just supposed to push my build folder to my git repo so that I can just run the starter file without having to build? I don't really like the idea of pushing my build folder.

Do I just continue putting some devDependencies as regular dependencies so that I can build properly on my server? I would really like a layer of separation between my dev/regular dependencies. Right now it's getting garbled.

Here are some relevant config files:

package.json

"scripts": {
        "build": "rimraf dist && tsc",
        "test": "c8 --all -r html -r text mocha",
        "test-watch": "npm run test -- -w",
        "dev": "concurrently --kill-others \"tsc -w\" \"pm2-dev start ecosystem.config.cjs\"",
        "deploy": "pm2 deploy ecosystem.config.cjs production"
    }

ecosystem.config.cjs

apps: [
        {
            name: 'brobot',
            script: 'dist/src/index.js',
            node_args: '--experimental-specifier-resolution=node',
            env: {
                NODE_ENV: 'development'
            }
        }
    ],
    deploy: {
        production: {
            user: process.env.AWS_USER,
            host: process.env.AWS_PUBLIC_IP,
            key: process.env.AWS_SSH_KEY,
            ref: 'origin/main',
            repo: '[email protected]:somegitrepo',
            path: process.env.AWS_EC2_PATH,
            node_args: '--experimental-specifier-resolution=node',
            env: {
                NODE_ENV: 'production'
            },
            'post-deploy': 'npm install && npm run build && pm2 startOrRestart ecosystem.config.cjs --env production'
        }
    }

tsconfig.json

{
    "compilerOptions": {
        "target": "ES6" /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', 'ES2021', or 'ESNEXT'. */,
        "module": "ESNext" /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', 'es2020', or 'ESNext'. */,
        "sourceMap": true /* Generates corresponding '.map' file. */,
        "outDir": "dist" /* Redirect output structure to the directory. */,
        /* Strict Type-Checking Options */
        "strict": true /* Enable all strict type-checking options. */,
        /* Module Resolution Options */
        "moduleResolution": "node" /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */,
        "esModuleInterop": true /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */,
        "skipLibCheck": true /* Skip type checking of declaration files. */,
        "forceConsistentCasingInFileNames": true /* Disallow inconsistently-cased references to the same file. */
    },
    "exclude": ["node_modules"]
}

I really want to keep pm2 in my project, it has been very useful. I'm definitely overlooking something but I'm not sure how to best handle this post-deploy setup.

CodePudding user response:

It happens because you are running npm install with NODE_ENV=production. Try to install your dependencies using npm install --production=false, it should force to install dev dependencies even in production environment

  • Related