Deploying Apollo Server with TypeScript Path Aliases to Vercel
Tags: typescript, graphql, node, webpack
Published: 2020-06-23 11:39:03

In [my previous post](https://dev.to/ozanbolel/what-have-i-learned-from-my-recent-tech-stack-4l3h), I mentioned I had some difficulties with deploying my backend. In this post, I'll be talking about what those difficulties were, and how you can deploy your **Apollo Server** with **TypeScript** using **path aliases** without going through all the hassle I experienced. I hear you asking why did I choose [Vercel](https://vercel.com)? I'm a simple man; I see good UI, I deploy... You might be also wondering what's up with that cover image? Don't worry, I don't know how my mind works either. Let's start with explaining what path aliases are and explaining the problem, then we'll continue [with the setup](https://www.youtube.com/watch?v=N3zf9q8mbWs).

###**Path Alias**

A path alias is a representation of a certain path that you don't want to hardcode everytime you import something. So, instead of this:

```javascript
import { normalizeString } from "../../../../../../../../tools";
```

You can do this:

```javascript
import { normalizeString } from "tools";
```

Aliases are very handy for keeping your project sane. The problem with my setup though; you have to specify your aliases for both **TypeScript** and **webpack**.

###**The Problem**

At first, I tried both Vercel and Heroku. Both were unable to run TypeScript directly. Since I like its UI, I decided on Vercel for going forward. When I tried to deploy the project again by compiling it to JavaScript first, the output file didn't work. The reason for that is I used path aliases in the project, but TypeScript doesn't convert them into real paths when compiling. For that, I used webpack with **ts-loader** to compile the project into JavaScript. I also configured my path aliases in webpack config too. Now the build file was working on localhost. Once again, I tried to deploy it to Vercel, but again, it didn't work. Turns out, you shouldn't be containing your **app.listen()** function inside another function. And I was doing that, because I was using **TypeORM** at that time. And TypeORM requires you to wrap your app.listen() function inside its initialization function so that you can establish your database connection before your API starts running. So I switched to **Mongoose** and it was a better choice to be honest since I was using a NoSQL database anyway. And I tried to deploy the project, again. Well.. It didn't work, again. I figured that I had to specify my API route in **vercel.json**, so I tried again. This time, it worked! Everything was flawless after that. Now I deploy the project with **npm run deploy** without any problems. However, enough stories. Now we'll talk about how you can do that too.

###**1. Configure TypeScript**

Here is how my **tsconfig.json** looks like:

```json
{
  "compilerOptions": {
    "target": "es5",
    "lib": ["dom", "dom.iterable", "esnext"],
    "allowJs": true,
    "module": "commonjs",
    "moduleResolution": "node",
    "outDir": "dist",
    "removeComments": true,
    "strict": true,
    "strictPropertyInitialization": false,
    "esModuleInterop": true,
    "resolveJsonModule": true,
    "emitDecoratorMetadata": true,
    "experimentalDecorators": true,
    "baseUrl": "./",
    "paths": {
      "config": ["config"],
      "interfaces": ["interfaces"],
      "services": ["services"],
      "entities": ["entities"],
      "resolvers": ["resolvers"]
    }
  },
  "include": ["**/*.ts"],
  "exclude": ["node_modules"]
}
```

As you can see I have 5 path aliases named **config**, **interfaces**, **services**, **entities** and **resolvers**. They all located at the root of the project, so the **baseUrl** is **"./"**. Don't forget to specify that.

###**2. Install and Configure Webpack**

First let's install webpack and other dependencies we need:

```
npm i --save-dev webpack
npm i --save-dev webpack-cli
npm i --save-dev webpack-node-externals
npm i --save-dev ts-loader
```

Now we need to create a config file named **webpack.config.js**. Create that in your root folder. You can copypasta and edit mine:

```javascript
const nodeExternals = require("webpack-node-externals");
const path = require("path");

module.exports = {
  entry: "./src/app.ts",
  target: "node",
  externals: [nodeExternals()],
  mode: "production",
  module: {
    rules: [
      {
        test: /\.tsx?$/,
        use: "ts-loader",
        exclude: /node_modules/
      }
    ]
  },
  resolve: {
    alias: {
      config: path.resolve(__dirname, "config"),
      interfaces: path.resolve(__dirname, "interfaces"),
      services: path.resolve(__dirname, "services"),
      entities: path.resolve(__dirname, "entities"),
      resolvers: path.resolve(__dirname, "resolvers")
    },
    modules: ["src"],
    extensions: [".ts", ".js"]
  },
  output: {
    filename: "app.js",
    path: path.resolve(__dirname, "dist")
  }
};
```

There are some important fields here. **entry** is of course the starting point of your app. In **alias**, you have to specify all the path aliases you also configured in your **tsconfig.json**. In **output**, **filename** is the file name of the output file webpack builds for us. And the **path** is the location where you want webpack to put it. In my case, it's the **"dist"** folder.

###**3. Compile Your Project with Webpack**

Open the command line in your root folder and run:

```
npx webpack
```

If you configured your **webpack.config.js** same as mine, your output file should be located at the **dist** folder. This is what we will be deploying to Vercel.

###**4. Install Vercel CLI and Login**

To install:

```
npm i -g vercel
```

And to login:

```
vercel login
```

It'll send you an email, don't forget to check your junks folder.

---

If you use Windows and you are getting an security error in the command line, launch command line again as administrator and type:

```
Set-ExecutionPolicy RemoteSigned
```

Press **A** and enter. Then run the login command again.

---

###**5. Configure Your Vercel Deployment**

Create a **vercel.json** file at the root folder of your project. And again, just copypasta mine and edit if you need to:

```json
{
  "version": 2,
  "builds": [{ "src": "dist/app.js", "use": "@now/node" }],
  "routes": [{ "src": "/", "dest": "dist/app.js" }]
}
```

This tells Vercel to run your API on the root directory with **node runtime**. Here is the important part; the path you specified in **vercel.json** must match with the path you specified in Apollo's **applyMiddleware()** function. This is what I'm talking about:

```javascript
server.applyMiddleware({
  app,
  path: "/"
});
```

This is a simplified version of my usage of **applyMiddleware()** function. If I wanted to run my API in the **"/api"** directory, the **vercel.json** would look like this:

```json
{
  "version": 2,
  "builds": [{ "src": "dist/app.js", "use": "@now/node" }],
  "routes": [{ "src": "/api", "dest": "dist/app.js" }]
}
```

And my **applyMiddleware()** function would look like this:

```javascript
server.applyMiddleware({
  app,
  path: "/api"
});
```

With that, we're done with the setup.

###**6. Deploy Your App to Vercel**

This is the hardest part. I'm kidding, just run this on command line:

```
vercel --prod
```

In your first deployment, it'll ask you some properties to create your project on Vercel. After your deployment is done, it'll show you the link and it'll automatically copy that link to your clipboard. You can also add these lines in the **scripts** field of your **package.json** file for easing future deployments:

```json
"build": "npx webpack",
"deploy": "npm run build && vercel --prod"
``` 

###**Conclusion**

I wanted to post this because the first few steps are the same for every platform. However, I think Vercel is more intended to be used with **serverless functions**. And as far as I know it doesn't support web sockets in serverside, so be aware of that. Considering those, you might want to rethink your architecture according to your needs. Although in my case, my project -which I talked about [in this post](https://dev.to/ozanbolel/what-have-i-learned-from-my-recent-tech-stack-4l3h)- was a small scaled personal one. You might want to go with Heroku, AWS or Netlify, but in my opinion this is also a good option for hobbyists.

---

I hope this was useful, you can also follow me on Twitter for future content:

[twitter.com/oznbll](https://twitter.com/oznbll)