Deploying an Express app with Swagger UI

I’ve been trying to get my express application to deploy successfully for quite some time. I’m running the “vercel” command locally to deploy and triage issues.

When I do this, either my build script isn’t run on the server, or the logs from it are suppressed. Here is my package.json build script: "build": "npm run clean && tsc && tsc-alias && node copyopenapi.cjs",
where the copyopenapi.cjs file looks like this:

console.log("Starting copy...");

const fs = require("fs");
const path = require("path");

const source = path.join(__dirname, "openapi.yaml");
const destination = path.join(__dirname, "dist", "openapi.yaml");

console.log(`Copying file from ${source} to ${destination}.`);

fs.copyFile(source, destination, (err) => {
  if (err) {
    console.error("Error copying file:", err);
    process.exit(1);
  }
  console.log("openapi.yaml was copied to dist/");
});

When I attempt to start my application, I get an error that my middleware can’t find my openapi.yaml file:

Error: ENOENT: no such file or directory, open ‘/var/task/dist/openapi.yaml’ at Object.readFileSync (node:fs:441:20) at loadSwaggerMiddleware (file:///var/task/dist/src/middleware/loadswaggermiddleware.js:19:42) at file:///var/task/dist/src/index.js:26:22 at ModuleJob.run (node:internal/modules/esm/module_job:268:25) at async onImport.tracePromise.proto (node:internal/modules/esm/loader:543:26) at async d (/opt/rust/nodejs.js:8:18858) { errno: -2, code: ‘ENOENT’, syscall: ‘open’, path: ‘/var/task/dist/openapi.yaml’ } Node.js process exited with exit status: 1. The logs above can help with debugging the issue.

I’ve added various logs to print out the contents of the /var/task/dist directory, but all it reports is a src directory within it. My guess is that my copy script isn’t being run during the build.

Here is my vercel.json file (which the v0 AI suggested I create):

{
  "version": 2,
  "builds": [
    {
      "src": "package.json",
      "use": "@vercel/node",
      "config": {
        "buildCommand": "npm run build"
      }
    }
  ],
  "routes": [
    {
      "src": "/(.*)",
      "dest": "dist/src/index.js"
    }
  ]
}

but that doesn’t really seem to solve the issue. Here is the output of the vercel --debug command (with env variables redacted)

C:\git\gacha-build-planner-api>vercel --debug

[debug] [2024-12-03T02:11:14.580Z] Found config in file “C:\git\gacha-build-planner-api\vercel.json”
Vercel CLI 37.14.0
[debug] [2024-12-03T02:11:14.588Z] user supplied no target, defaulting to deploy
[debug] [2024-12-03T02:11:14.722Z] Found “.git\config” - detected “C:\git\gacha-build-planner-api” as repo root
[debug] [2024-12-03T02:11:14.767Z] Spinner invoked (Retrieving project…) with a 1000ms delay
[debug] [2024-12-03T02:11:14.778Z] #1 → GET https://api.vercel.com/teams/team_yfVOtbBZGAraFUX7SJ4ur1qk?teamId=team_yfVOtbBZGAraFUX7SJ4ur1qk
[debug] [2024-12-03T02:11:14.781Z] #2 → GET https://api.vercel.com/v9/projects/prj_6Tj1YUBsgyv8XMyMlEDpUah8u38O?teamId=team_yfVOtbBZGAraFUX7SJ4ur1qk
[debug] [2024-12-03T02:11:15.148Z] #2 ← 200 OK: sfo1::rf5ks-1733191874780-919689d9cb0a [367ms]
[debug] [2024-12-03T02:11:15.164Z] #1 ← 200 OK: sfo1::klwbh-1733191874785-1a153fa0d401 [386ms]
[debug] [2024-12-03T02:11:15.377Z] Spinner invoked (Deploying afrassos-projects/gacha-build-planner-api) with a 0ms delay
[client-debug] 2024-12-03T02:11:15.378Z Creating deployment…
[client-debug] 2024-12-03T02:11:15.379Z Provided ‘path’ is a directory.
[client-debug] 2024-12-03T02:11:15.382Z Found 24 rules in .vercelignore
[client-debug] 2024-12-03T02:11:15.382Z Building file tree…
[client-debug] 2024-12-03T02:11:15.392Z Found 82 files in the specified directory
[client-debug] 2024-12-03T02:11:15.401Z Yielding a ‘hashes-calculated’ event with 81 hashes
[client-debug] 2024-12-03T02:11:15.402Z Using provided API URL: https://api.vercel.com
[client-debug] 2024-12-03T02:11:15.402Z Using provided user agent: vercel 37.14.0 node-v20.17.0 win32 (x64)
[client-debug] 2024-12-03T02:11:15.402Z Setting platform version to harcoded value 2
[client-debug] 2024-12-03T02:11:15.403Z Creating the deployment and starting upload…
[client-debug] 2024-12-03T02:11:15.404Z Determining necessary files for upload…
[client-debug] 2024-12-03T02:11:15.404Z Creating deployment
[client-debug] 2024-12-03T02:11:15.405Z Sending deployment creation API request
[client-debug] 2024-12-03T02:11:15.828Z Deployment response: {“error”:{“code”:“missing_files”,“message”:“Missing files”,“missing”:[“ad8f2adb2825c9cd74573047753bbf29d87195e2”]}}
[client-debug] 2024-12-03T02:11:15.829Z Error: Deployment request status is 400
[client-debug] 2024-12-03T02:11:15.832Z 1 files are required to upload
[client-debug] 2024-12-03T02:11:15.835Z Yielding a ‘file-count’ event
[debug] [2024-12-03T02:11:15.836Z] Total files 81, 1 changed
[debug] [2024-12-03T02:11:15.839Z] Spinner invoked (Uploading [--------------------] (0.0B/279B)) with a 0ms delay
[client-debug] 2024-12-03T02:11:15.840Z Building an upload list…
[client-debug] 2024-12-03T02:11:15.844Z Starting upload
[client-debug] 2024-12-03T02:11:15.845Z POST https://api.vercel.com/v2/files?teamId=team_yfVOtbBZGAraFUX7SJ4ur1qk
[debug] [2024-12-03T02:11:15.849Z] Spinner invoked (Uploading [====================] (279.0B/279B)) with a 0ms delay
[client-debug] 2024-12-03T02:11:16.284Z DONE in 437ms: POST https://api.vercel.com/v2/files?teamId=team_yfVOtbBZGAraFUX7SJ4ur1qk
[client-debug] 2024-12-03T02:11:16.285Z File ad8f2adb2825c9cd74573047753bbf29d87195e2 (C:\git\gacha-build-planner-api\vercel.json) uploaded
[client-debug] 2024-12-03T02:11:16.286Z Yielding a ‘file-uploaded’ event
[debug] [2024-12-03T02:11:16.287Z] Uploaded: C:\git\gacha-build-planner-api\vercel.json (279B)
[client-debug] 2024-12-03T02:11:16.287Z All files uploaded
[client-debug] 2024-12-03T02:11:16.288Z Yielding a ‘all-files-uploaded’ event
[client-debug] 2024-12-03T02:11:16.288Z Starting deployment creation
[client-debug] 2024-12-03T02:11:16.289Z Creating deployment
[client-debug] 2024-12-03T02:11:16.291Z Sending deployment creation API request
[client-debug] 2024-12-03T02:11:18.660Z Deployment response:
[client-debug] 2024-12-03T02:11:18.669Z Deployment created with a notice: To deploy to production (gacha-build-planner-api.vercel.app), run vercel --prod
[client-debug] 2024-12-03T02:11:18.680Z Yielding a ‘notice’ event
[client-debug] 2024-12-03T02:11:18.683Z Deployment created with a warning: Due to builds existing in your configuration file, the Build and Development Settings defined in your Project Settings will not apply. Learn More: Error List
[client-debug] 2024-12-03T02:11:18.686Z Yielding a ‘warning’ event
[client-debug] 2024-12-03T02:11:18.688Z Deployment created
[client-debug] 2024-12-03T02:11:18.690Z Yielding a ‘created’ event
[debug] [2024-12-03T02:11:18.830Z] Found “.git\config” - detected “C:\git\gacha-build-planner-api” as repo root
:mag: Inspect: gacha-build-planner-api – Deployment Overview – Vercel [3s]
:white_check_mark: Preview: https://gacha-build-planner-re59px4cl-afrassos-projects.vercel.app [3s]
[debug] [2024-12-03T02:11:18.840Z] Spinner invoked (Queued) with a 0ms delay
[client-debug] 2024-12-03T02:11:18.841Z Waiting for deployment to be ready…
[client-debug] 2024-12-03T02:11:18.842Z Waiting for builds and the deployment to complete…
[client-debug] 2024-12-03T02:11:21.327Z Deployment state changed to BUILDING
[client-debug] 2024-12-03T02:11:21.328Z Yielding a ‘building’ event
[debug] [2024-12-03T02:11:21.330Z] Spinner invoked (Building) with a 0ms delay
[client-debug] 2024-12-03T02:11:33.004Z Deployment state changed to READY
[client-debug] 2024-12-03T02:11:33.005Z Yielding a ‘ready’ event
[debug] [2024-12-03T02:11:33.007Z] Spinner invoked (Completing) with a 0ms delay
[client-debug] 2024-12-03T02:11:34.186Z Deployment alias assigned
[client-debug] 2024-12-03T02:11:34.186Z Deployment is ready
[client-debug] 2024-12-03T02:11:34.189Z Yielding a ‘alias-assigned’ event
[debug] [2024-12-03T02:11:34.190Z] #3 → GET https://api.vercel.com/v13/deployments/dpl_D3fWm9CuYLAMYTdj2ryC2JzwBkud?teamId=team_yfVOtbBZGAraFUX7SJ4ur1qk
[debug] [2024-12-03T02:11:34.344Z] #3 ← 200 OK: sfo1::klwbh-1733191893961-9c96811a90f4 [154ms]
:memo: To deploy to production (gacha-build-planner-api.vercel.app), run vercel --prod
:exclamation: Due to builds existing in your configuration file, the Build and Development Settings defined in your Project Settings will not apply. Learn More: Error List
[debug] [2024-12-03T02:11:34.348Z] Spawning C:\Users\antho\AppData\Roaming\npm\node_modules\vercel\dist\get-latest-worker.js
'[debug] [2024-12-03T02:11:34.421Z] Notifying parent we’re ready
'[debug] [2024-12-03T02:11:34.429Z] Received message from parent: {
cacheFile: ‘C:\Users\antho\AppData\Local\com.vercel.cli\Cache\package-updates\vercel-latest.json’,
distTag: ‘latest’,
name: ‘vercel’,
updateCheckInterval: 86400000
}
'[debug] [2024-12-03T02:11:34.429Z] Disconnecting from parent
'[debug] [2024-12-03T02:11:34.431Z] Checking lock file: C:\Users\antho\AppData\Local\com.vercel.cli\Cache\package-updates\vercel-latest.lock
'[debug] [2024-12-03T02:11:34.433Z] Found lock file with pid: 41824
'[debug] [2024-12-03T02:11:34.434Z] Resetting lock file: Error: kill ESRCH
'[debug] [2024-12-03T02:11:34.434Z] Initializing lock file with pid 30916
'[debug] [2024-12-03T02:11:34.436Z] Fetching https://registry.npmjs.org/-/package/vercel/dist-tags

Any ideas? My project is at: Login – Vercel

If you’re having trouble deploying an Express app, this guide can help.

You can also ask v0 for suggestions tailored to your own project setup.

In addition to the Express deployment guide linked above, I would recommend double checking the project’s build and development settings and override the build command if needed. Please give that a try and let us know how it goes!

1 Like

Thanks for the note. I had actually figured it out by the time you replied through the process of repeated trial and error, and realized I was making several errors that were exacerbated by some pretty important misunderstandings on my part.

The biggest issue was that when I was running vercel locally, it (obviously) had access to all of my local files, including the dist directory on my local machine. Because of that, when vercel didn’t run my build actual build command and instead ran vercel build during deployment, I think it just executed whatever files were there. This wouldn’t have been a problem, except my local package.json’s main pointed at dist/index.js, whereas my actual main should have been dist/src/index.js. So vercel was running a fairly old version of my index file, which did do something but not what I expected and was why none of my changes were being deployed as I would have expected.

When I finally figured this out, and did a clean build locally, deployment broke completely, which led me to realize that the build I thought it was running (“npm run build”) was instead “vercel build”. I thought I was overriding this in my vercel.json file (as shown in the builds array above), but that seems to have not been the case. I went hunting down through the documentation and realized this particular field shouldn’t be used. I then updated both my vercel deployment configuration to run npm run build and updated my vercel.json as follows:

{
  "version": 2,
  "buildCommand": "npm run build",
  "functions": {
    "api/index.js": {
      "includeFiles": "{dist/openapi.yaml,node_modules/swagger-ui-dist/**}"
    }
  },
  "routes": [
    {
      "src": "/(.*)",
      "dest": "api/index.js"
    }
  ]
}

which mostly, kinda, solved the issue.

The one final thing I had to figure out is that vercel seems to really want serverless functions to exist in an “api” directory which I didn’t have at first. To solve this, I created a new index.js file in api that simply called the dist/src/index.js file, and all of a sudden things seem to be working as expected. I’m going to check everything in tonight, and hopefully a build from the branch will work as expected.

So to summarize:

  1. When deploying locally, you’re at risk of providing vercel access to files it shouldn’t normally have (e.g., the dist directory) which if there’s weird behavior during the build, could result in some unexpected behavior.
  2. Manually override your build in your vercel configuration; don’t rely on vercel automagically figuring it out like I hoped it would.
  3. Don’t use “builds” in your vercel.json.
  4. Make the starting point of your serverless function something in an api directory.

If any of these conclusions are wrong, please let me know!

1 Like

It looks like you found a good solution. Thanks for coming back to share it!

In case it helps, you can exclude Files from Deployments with .vercelignore

This topic was automatically closed 7 days after the last reply. New replies are no longer allowed.