Vercel is a platform to host frontend applications and static sites but you can also host an express app using serverless functions. I've been using it for quite some time (mainly for frontend stuff) but it can also deploy your Expressjs backend! We will see how to create a Bridge app and deploy it to Vercel.
About Bridge.
Bridge is a Typescript Nodejs framework that focuses on type-safety and developer experience. It aims to provide the best developer experience by simplifying the process of developing and integrating APIs.
This is done by heavily using the Typescript inference between elements from the backend such as data validation, routes and middlewares.
Prerequisites
Having Nodejs and Vercel CLI installed on your machine.
1. Create your Bridge app
The easiest way it to use the create-bridge-app npm package.
You can do that by using:
bash
npx create-bridge-app@latest
bash
npx create-bridge-app@latest
Then, enter your project name when prompted and select the "minimal-express" template. Once the app is created, navigate to the project directory and install the dependencies with the following command:
cd project-name && npm i
cd project-name && npm i
Step 2: Prepare your app for deployment
By default, a Bridge app is not compatible with Vercel's serverless functions. To make it work, you need to make some changes to the app.
- Create a vercel.json file
- Edit the index.ts file
- Edit the tsconfig.json file
- Edit the package.json file
vercel.json
Create a "vercel.json" file at the root of your project with the following content:
json
{"rewrites": [{"source": "/api/:path+","destination": "/api"}],"redirects": [{"source": "/","destination": "/api"}]}
json
{"rewrites": [{"source": "/api/:path+","destination": "/api"}],"redirects": [{"source": "/","destination": "/api"}]}
This file configures Vercel to redirect all requests to the "/api" route.
index.ts
To make it work, we'll also need to update our index.ts file and initBridge on the /api route. We additionnaly add a new route GET "/api/hello".
ts
import { initBridge, handler, method } from 'bridge';import express from 'express';const app = express();app.get('/api', (req, res) => res.send(`Welcome on Bridge API`));const heyHandler = handler({resolve: () => {return 'Hey you!';},});const routes = {hey: method({ GET: heyHandler }),};app.use('/api', initBridge({ routes }).expressMiddleware());app.listen(3000, () => {console.log(`Listening on port 3000`);});module.exports = app;
ts
import { initBridge, handler, method } from 'bridge';import express from 'express';const app = express();app.get('/api', (req, res) => res.send(`Welcome on Bridge API`));const heyHandler = handler({resolve: () => {return 'Hey you!';},});const routes = {hey: method({ GET: heyHandler }),};app.use('/api', initBridge({ routes }).expressMiddleware());app.listen(3000, () => {console.log(`Listening on port 3000`);});module.exports = app;
Don't forget to add the module.exports = app at the end of your file.
package.json
Update your "package.json" file with the following.
json
{"name": "bridge-vercel","version": "1.0.0","dependencies": {"bridge": "^2.0.45","express": "^4.18.2","ts-node": "^10.9.1"},"scripts": {"deploy": "tsc && vercel","deploy-prod": "tsc && vercel --prod","dev": "ts-node index.ts"},"devDependencies": {"@types/express": "^4.17.15","@types/node": "^18.11.16","typescript": "^4.9.4"}}
json
{"name": "bridge-vercel","version": "1.0.0","dependencies": {"bridge": "^2.0.45","express": "^4.18.2","ts-node": "^10.9.1"},"scripts": {"deploy": "tsc && vercel","deploy-prod": "tsc && vercel --prod","dev": "ts-node index.ts"},"devDependencies": {"@types/express": "^4.17.15","@types/node": "^18.11.16","typescript": "^4.9.4"}}
- npm run dev will run our development server on port 8080.
- npm run vercel builds and deploys our app to vercel in preview
- npm run deploy-prod build and deploys our app to vercel in production
tsconfig.json
Finally, update your "tsconfig.json" file with the following content:
json
{"compilerOptions": {"target": "es2016" /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */,"module": "commonjs" /* Specify what module code is generated. */,"outDir": "api" /* Specify an output folder for all emitted files. */,"esModuleInterop": true /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */,"forceConsistentCasingInFileNames": true /* Ensure that casing is correct in imports. */,"strict": true /* Enable all strict type-checking options. */,"skipLibCheck": true /* Skip type checking all .d.ts files. */}}
json
{"compilerOptions": {"target": "es2016" /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */,"module": "commonjs" /* Specify what module code is generated. */,"outDir": "api" /* Specify an output folder for all emitted files. */,"esModuleInterop": true /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */,"forceConsistentCasingInFileNames": true /* Ensure that casing is correct in imports. */,"strict": true /* Enable all strict type-checking options. */,"skipLibCheck": true /* Skip type checking all .d.ts files. */}}
Now everything should be ready for the deployment.
npm run deploy
npm run deploy
Now you should have a fully working Bridge app deployed to Vercel. With Bridge, you can create complex APIs with a very good developer experience while using TypeScript and its type system to its fullest extent.
To read more about Bridge, check out the documentation.