So I’ve had a heroku free-tier dyno running for a while now with a version of my api-forward project. The idea behind it is to allow me to obfuscate API calls from fiddles and pens to external APIs. This way my API keys are not revealed in the pens or fiddles themselves. It’s a pretty simple application, but I tried to over-complicate it and stick it into a mono-repo with some other tools I’ve been developing. Now I want to redeploy the new version from the original repo. So it’s back to the drawing board.

The monorepo tooling I was using is called nx from nrwl. It’s a great tool that makes writing TypeScript code a lot easier, however, it also magicks away some of the complexities of managing a large software project. Yes, I can easily just run the cli command to test my app like so: nx test <project>. However, ejecting the project from nx has proven to be difficult since I now have to re-magick all the stuff that nx was doing for me under the covers.

The first issue I ran into was heroku trying to use my dev script to run the server in production. This was easily fixed by moving the start script to a dev script.

{
    // "start": "ts-node src/main.ts "
    // becomes
    "dev": "ts-node src/main.ts ",
    "start": "node ./build/index.js",
}

The above script will run my post-build typescript code under NodeJS. Cool, now I have to make sure the build is working, because nx had a monorepo-wide tsconfig that I now have to rewrite for my purposes in this single project.

So let’s compare what was there before, and take only what we need to spit out the compiled code into a build folder. There were multiple files in the nx repository, but I was able to cobble them together to get this:

// tsconfig.json
{
    "compileOnSave": false,
    "compilerOptions": {
        "rootDir": ".",
        "sourceMap": true,
        "declaration": false,
        "moduleResolution": "node",
        "emitDecoratorMetadata": true,
        "experimentalDecorators": true,
        "importHelpers": true,
        "target": "es2015",
        "module": "esnext",
        "lib": [
            "es2017",
            "dom"
        ],
        "skipLibCheck": true,
        "skipDefaultLibCheck": true,
        "baseUrl": ".",
        "paths": {},
        "outDir": "./dist",
        "types": [
            "node",
            "express",
            "axios"
        ]
    },
    "exclude": [
        "node_modules",
        "tmp"
    ]
}

This configuration should allow me to spit out a dist folder and run the process from the main.js file that is generated. I’ve since tried to run it, however, and I am unable to do it because of the module resolution scheme I picked to use in the typescript files. Fortuneately, all I had to do to fix the issue was to change the module resolution compiler option:

{ "module": "esnext" }
// becomes  -> 
{ "module": "commonjs" }

I’m interested to see how nx handles this issue in their compile/run process, but not enough to dig into it right now. So I can build and then run the application, now I need to tell heroku how to do that. We can use the default buildpack or we can write our own.

Writing our own buildpack would require a lot of effort and bash scripting (not my favorite), but we can use some npm hooks to customize the default npm build steps that heroku expects.

At this point, though I thought my configuration was good enough and decided to deploy the app again. The app built fine, the logs looked good, but I got a timeout error on heroku when trying to hit it via the browser. This is bcause of the default port not being picked up by heroku. A quick change to the casing of the env var in main.ts and a CLI command heroku config:set -a apiforward PORT=80 later and we get a 200 response back from the default handler!

Heroku is a really great way to get backend REST APIs up and running quickly. I can’t wait to start using my api-forward project to start calling APIs what require keys from my codepens and fiddles.