DEV Community

Suhavi Sandhu
Suhavi Sandhu

Posted on

Migrating a Nuxt SSR App from Heroku to Vercel

As of December 2022, Heroku has transitioned to a paid plan for hosting server-side apps. This left myself and many others with broken apps, with the option to pay for ‘dynos’ to get our apps running or migrate. If you’re like me and used Heroku for personal use, you probably don’t want to switch to a paid plan for fear of fluctuating hosting expenses and are going to look into alternatives. Most popular hosting services we know of (Netlify, Vercel, Firebase) have out-of-the-box support for static apps but require a bit more involvement when it comes to server-side rendering. Hence, I put together this guide for the very specific use case of apps built with Nuxt 2. I also have a Troubleshooting section for issues I faced that others might run into.

Step 1 - Create a Vercel account

Go to https://vercel.com to create a free account.

Step 2 - Configure your project for Vercel

Vercel supports non-SSR out of the box, but for SSR to work, we need to deploy a serverless function that handles all the server-related functions. For this, we will need to use https://github.com/nuxt/vercel-builder built by the Nuxt community. To use it you need to create a vercel.json in your project’s root directory.

{
  "version": 2,
  "builds": [
    {
      "src": "nuxt.config.js",
      "use": "@nuxtjs/vercel-builder"
    }
  ]
}
Enter fullscreen mode Exit fullscreen mode

Step 3 - Create a new project by importing your repository

Import project

Step 4 - Copy over necessary environment variables from Heroku to Vercel

Environment variables

Step 5 - Fill in the deployment settings

Settings

Choose Nuxt.js as the framework preset and fill in the build commands. The default commands should work but I added the yarn commands just to be sure. The commands are run in the following order.

  1. yarn install will grab all of the dependencies needed for your app to run
  2. yarn generate will compile your client-side and server-side code and package it into minified files that will be saved in your output directory (dist)
  3. yarn start starts the process that will run your app.

These steps are identical to those needed to run your app locally.

Step 6 - Deploy

I was able to migrate my SSR Nuxt.js application from Heroku to Vercel with these steps. If you’re still having issues, look through the troubleshooting section below or reach out to me. For reference, here is the code for my application - https://github.com/gucci-ninja/dotboard which is now running on https://dotboard.vercel.app/. Thanks!

Troubleshooting

Error - This serverless function has crashed/No build files found

Server error

FATAL  No build files found in /var/task/.nuxt/dist/server.
Use either `nuxt build` or `builder.build()` or start nuxt in development mode.
Use either `nuxt build` or `builder.build()` or start nuxt in development mode.
at VueRenderer._ready (node_modules/@nuxt/vue-renderer/dist/vue-renderer.js:4204:13)
at async Server.ready (node_modules/@nuxt/server/dist/server.js:615:5)
at async Nuxt._init (node_modules/@nuxt/core/dist/core.js:703:7)
2023-01-03T00:01:47.485Z    undefined   ERROR   λ Error while initializing nuxt: Error: No build files found in /var/task/.nuxt/dist/server.
Use either `nuxt build` or `builder.build()` or start nuxt in development mode.
    at VueRenderer._ready (/var/task/node_modules/@nuxt/vue-renderer/dist/vue-renderer.js:4204:13)
    at async Server.ready (/var/task/node_modules/@nuxt/server/dist/server.js:615:5)
    at async Nuxt._init (/var/task/node_modules/@nuxt/core/dist/core.js:703:7)
RequestId: 9f4fdef5-a109-4497-95e9-5f5c8f2a905b Error: Runtime exited with error: exit status 1
Runtime.ExitError
Enter fullscreen mode Exit fullscreen mode

Solution

Version lock vercel-builder to 0.23.0 as there is an issue with 0.24.0 not invoking the serverless function.

{
  "version": 2,
  "builds": [
    {
      "src": "nuxt.config.js",
      "use": "@nuxtjs/vercel-builder@0.23.0"
    }
  ]
}
Enter fullscreen mode Exit fullscreen mode

Relevant links

Error - Outdated dependencies

If you’re like me and were not actively developing your app, some of the dependencies might be outdated or need to be upgraded. So a quick test is to run the app locally and see if everything is working as expected. For example, I was getting the following error.

make: Entering directory `/vercel/path0/node_modules/node-sass/build'

gyp ERR! build error 
gyp ERR! stack Error: `make` failed with exit code: 2

Build failed with error code: 1
Error: Command "yarn install" exited with 1
Enter fullscreen mode Exit fullscreen mode

Solution

I removed node-sass from my dependencies as I was not using it. I also needed to downgrade my sass-loader from ^9.0.3 to ^7.1.0

Relevant links

Error - 404 when calling API. Runtime logs on Vercel showing 404 as the response status

Solution

If you have any endpoints or routes in your server code, you need to declare them in the vercel.json. I have a server/ folder which holds all the endpoints that my app serves (/api/auth/login, /api/auth/user) The code to handle all these requests resides in /server/index.js.

{
  "builds": [
    {
        "src": "server/**/*.js", // path to code that handles API requests
        "use": "@vercel/node"
    },
    {
      "src": "nuxt.config.js",
      "use": "@nuxtjs/vercel-builder@0.23.0",
      "config": {}
    }
  ],
  "routes": [
    {
      "src": "/api/auth/login", // endpoint 1
      "dest": "/server/index.js" // code that handles endpoint 1
    },
    {
      "src": "/api/auth/user", // endpoint 2
      "dest": "/server/index.js" // code that handles endpoint 2
    }
  ]
}
Enter fullscreen mode Exit fullscreen mode

Relevant links

Error - Deployment hanging and taking 7+ minutes

NowBuildError: node_modules_prod/rxjs/src/internal/observable/from.ts(116,5): error TS2322: Type 'import("/vercel/path0/node_modules/rxjs/internal/Observable").Observable<T>' is not assignable to type 'import("/vercel/path0/node_modules_prod/rxjs/src/internal/Observable").Observable<T>'.
node_modules_prod/rxjs/src/internal/observable/from.ts(116,29): error TS2345: Argument of type 'import("/vercel/path0/node_modules_prod/rxjs/src/internal/types").SchedulerLike' is not assignable to parameter of type 'import("/vercel/path0/node_modules/rxjs/internal/types").SchedulerLike'.
node_modules_prod/rxjs/src/internal/scheduled/scheduled.ts(31,38): error TS2345: Argument of type 'import("/vercel/path0/node_modules/rxjs/internal/types").SchedulerLike' is not assignable to parameter of type 'import("/vercel/path0/node_modules_prod/rxjs/src/internal/types").SchedulerLike'.
Enter fullscreen mode Exit fullscreen mode

Solution

Not sure what the issue was but retrying the deployment worked.

Latest comments (2)

Collapse
 
kissu profile image
Konstantin BIFERT • Edited

Hey, thanks for the article! 🙏🏻
You don't need the install part in yarn install, yarn by itself is enough.

For SASS, I recommend that you install sass, this one is a better/more modern version of SASS. Check this answer for more details.

Be careful, a Node.js environment like on Heroku and a Serverless rendering function on Vercel are both doing SSR but it's not exactly the same thing (got some advantages and some cons too).
For a truly identical comparison, I recommend checking Render or Railway.
Netlify/Vercel are still aimed at non-Nodejs environments and may behave a bit differently.

As for an SSR (classical) configuration, you usually use ssr: true + target: 'server' + yarn build.
yarn generate is for SSG (target: 'static') usually. But maybe this one is a requirement for the Nuxt module to work properly.

I know that I saw Daniel sharing some shenanigans on that one last time on Discord. May be nice to double-check that it is the way to go so that you can maybe have a faster build on Vercel (SASS being the one slowing things down anyway). 👍🏻

Collapse
 
suhavi profile image
Suhavi Sandhu

Thanks for your comment! +1 to switching to SASS. I was definitely trying to get out the easy way and get my app back up and running. Ideally I want to move to a fully decoupled server/client.

Also, I'm on Nuxt 2 so there may be some differences. ssr: true and target: server are both defaults, but it's good to call them out. That might be why generate works out of the box :P