How do I deploy to Heroku using Vite
Asked Answered
D

7

7

Any and all help will be much appreciated.

I've been trying to deploy to Heroku with all day. I'm using Vite locally to develop, so I figured I'd try to deploy with that too. Everything works locally (of course) and the build is successful when I deploy the repository. However, when I try to view my app, I get the following:

2021-10-05T02:12:13.493958+00:00 heroku[web.1]: Starting process with command `npm start`
2021-10-05T02:12:14.624236+00:00 app[web.1]: [heroku-exec] Starting
2021-10-05T02:12:14.834583+00:00 app[web.1]: 
2021-10-05T02:12:14.834585+00:00 app[web.1]: > [email protected] start /app
2021-10-05T02:12:14.834585+00:00 app[web.1]: > vite
2021-10-05T02:12:14.834585+00:00 app[web.1]: 
2021-10-05T02:12:15.759365+00:00 app[web.1]: Pre-bundling dependencies:
2021-10-05T02:12:15.759384+00:00 app[web.1]:   vue
2021-10-05T02:12:15.759384+00:00 app[web.1]:   vue-chart-3
2021-10-05T02:12:15.759385+00:00 app[web.1]:   axios
2021-10-05T02:12:15.759389+00:00 app[web.1]: (this will be run only when your dependencies or config have changed)
2021-10-05T02:12:16.402419+00:00 app[web.1]: 
2021-10-05T02:12:16.402429+00:00 app[web.1]:   vite v2.5.5 dev server running at:
2021-10-05T02:12:16.402429+00:00 app[web.1]: 
2021-10-05T02:12:16.402543+00:00 app[web.1]:   > Local: http://localhost:3000/
2021-10-05T02:12:16.402578+00:00 app[web.1]:   > Network: use `--host` to expose
2021-10-05T02:12:16.402610+00:00 app[web.1]: 
2021-10-05T02:12:16.402611+00:00 app[web.1]:   ready in 1529ms.
2021-10-05T02:12:16.402611+00:00 app[web.1]: 
2021-10-05T02:12:16.000000+00:00 app[api]: Build succeeded
2021-10-05T02:13:14.120863+00:00 heroku[web.1]: Error R10 (Boot timeout) -> Web process failed to bind to $PORT within 60 seconds of launch
2021-10-05T02:13:14.233876+00:00 heroku[web.1]: Stopping process with SIGKILL
2021-10-05T02:13:14.376928+00:00 heroku[web.1]: Process exited with status 137
2021-10-05T02:13:14.423585+00:00 heroku[web.1]: State changed from starting to crashed
2021-10-05T02:13:15.030060+00:00 heroku[router]: at=error code=H10 desc="App crashed" method=GET path="/" host=indicatorsdashboardfrontend.herokuapp.com request_id=c9ad1cae-2b32-4e54-bab1-7919401af71c fwd="98.209.145.237" dyno= connect= service= status=503 bytes= protocol=https

I read a post here that said that I needed to set some variables so that Vite would install properly and I believe I did that:

       NPM_CONFIG_PRODUCTION=false
       NPM_CONFIG_LOGLEVEL=error
       YARN_PRODUCTION=false
       NODE_VERBOSE=false
       NODE_ENV=production
       NODE_MODULES_CACHE=true

My repository can be found here: https://github.com/kddove85/IndicatorDashboardFrontend

I think the important file is the package.json but I'm not sure. Here that is:

{
  "name": "dashboard-frontend",
  "version": "0.0.0",
  "scripts": {
    "start": "vite",
    "dev": "vite",
    "build": "vite build",
    "serve": "vite preview"
  },
  "dependencies": {
    "@vue/cli": "^4.5.13",
    "axios": "^0.21.4",
    "chart.js": "^2.9.4",
    "lodash": "^4.17.21",
    "vue": "^3.2.6",
    "vue-axios": "^3.3.6",
    "vue-chart-3": "^0.5.8"
  },
  "devDependencies": {
    "@vitejs/plugin-vue": "^1.6.1",
    "@vue/compiler-sfc": "^3.2.6",
    "eslint": "^7.32.0",
    "eslint-plugin-vue": "^7.18.0",
    "vite": "^2.5.4"
  },
  "engines": {
    "node": "14.17.5",
    "npm": "6.14.14"
  }
}

I'm just not sure what I did wrong.

Debt answered 5/10, 2021 at 2:21 Comment(1)
what's the content of your entry file? You're probably setting a PORT value which you should not as heroku dynamically assigns a PORT value on build. – AmΒ‚lie
M
27

Update March 2023

I'm a little late to the party, but I also had to update the build process. I tried a bunch of things, but this is what I did, ymmv.

For one, I really like the simplicity of @Metehan (using vercel's serve package.) Because it takes away from learning nginx or w/e. However, I could not get that to work. My final solution is the same as @Gerald H.

Summarised:

  1. Remove the old buildpack
heroku buildpacks:remove https://github.com/heroku/heroku-buildpack-static.git -a <your-app-name>
  1. Add the nginx Buildpack
heroku buildpacks:add heroku-community/nginx -a <your-app-name>
  1. If you don't have a static.json file yet in the root of your project, add that and paste the following content
{
  "root": "./dist",
  "clean_urls": true,
  "routes": {
    "/**": "index.html"
  }
}
  1. If you don't have a Procfile in the root of your project yet, add it. If you do, update it to contain the following. This makes sure that nginx starts your app.
web: bin/start-nginx-solo
  1. NGINX will create a configuration file for you which you can find in the booted up app. You can find it by going to your project (heroku run bash -a <your-app-name>). Once there, type cd config && cat nginx.conf.erb. This will print out the configuration that was generated. For me, this configuration wasn't completely correct, but it's a good start. Copy the config and go back to your code. Create a folder config and add a file called nginx.conf.erb and paste in the configuration you copied. Making this file in your codebase ensures that the configuration does not get auto generated every time.
  2. The main thing I had to change was the server content. I changed added a line: root /app/dist and I updated the location settings as follows:
location = /index.html {
    add_header Cache-Control "no-store, no-cache";
    try_files $uri $uri/ =404;
}

location / {
    add_header 'Cache-Control' "public, max-age=3600";
    try_files $uri $uri/ /index.html;
}

NB: As Gerald mentioned too, make sure to remove any mentions of mruby. Those were not there for me, but just make sure to check.

  1. You can now remove your static.json file, it is no longer needed.

For reference:

My nginx.conf.erb looks like this now:

daemon off;
# Heroku dynos have at least 4 cores.
worker_processes <%= ENV['NGINX_WORKERS'] || 4 %>;

events {
    use epoll;
    accept_mutex on;
    worker_connections <%= ENV['NGINX_WORKER_CONNECTIONS'] || 1024 %>;
}

http {
    gzip on;
    gzip_comp_level 2;
    gzip_min_length 512;
    gzip_proxied any; # Heroku router sends Via header

    server_tokens off;

    log_format l2met 'measure#nginx.service=$request_time request_id=$http_x_request_id';
    access_log <%= ENV['NGINX_ACCESS_LOG_PATH'] || 'logs/nginx/access.log' %> l2met;
    error_log <%= ENV['NGINX_ERROR_LOG_PATH'] || 'logs/nginx/error.log' %>;

    include mime.types;
    default_type application/octet-stream;
    sendfile on;

    # Must read the body in 5 seconds.
    client_body_timeout 5;

    upstream app_server {
        server unix:/tmp/nginx.socket fail_timeout=0;
    }

    server {
        listen <%= ENV["PORT"] %>;
        server_name _;
        keepalive_timeout 5;
        root /app/dist;

        location = /index.html {
            add_header Cache-Control "no-store, no-cache";
            try_files $uri $uri/ =404;
        }

        location / {
            add_header 'Cache-Control' "public, max-age=3600";
            try_files $uri $uri/ /index.html;
        }
    }
}

Solution using buildpack-static (OLD)

I found this thread and was also struggling with this issue. For those that come here and cannot figure it out, this is what I found and what worked for me.

If you only have a vite project, you should deploy it as a static site. There is some documentation on the Vite website. Basically, it comes down to making sure you have the right buildpacks (at least my problem came down to that).

First, determine how your website is going to be hosted. Are you relying on heroku to also build your dist folder or are you doing that before you push your branch? If you are not relying on heroku to build your site, you can follow along from step 2.

If you want heroku to build your website before serving it, you should have the heroku/nodejs buildpack set as the first buildpack.

  1. You can do this by running the following cli command:
heroku buildpacks:set heroku/nodejs -a <your-app-name>

This will remove any previously set buildpacks and set the heroku/nodejs buildpack as the only buildpack to run.

  1. Then you need to make sure that once your app has been built, it hosts your dist folder as a static site. You do that by adding a second buildpack:
heroku buildpacks:add https://github.com/heroku/heroku-buildpack-static.git -a <your-app-name>

This will make sure that your app is treated as a static page rather than a node js application.

  1. You need to set some configurations in your app to make sure the buildpacks take the correct files. For this, add a file to the root of your Vite project called static.json. Put the following json in there:
{
  "root": "./dist",
  "clean_urls": true,
  "routes": {
    "/**": "index.html"
  }
}
  1. Push your code to your preferred platform and make sure your heroku app deploys it. I have my project on Github and set up automatic deploys from the correct branch.

Other points

A few other points that could be of interest.

  • My heroku app has a NODE_ENV=production environment variable set
  • I didn't need to add any scripts. Just as a reference, this is what my package.json scripts look like:
{
  ...
  "scripts": {
    "dev": "vite",
    "build": "vue-tsc --noEmit && vite build",
    "serve": "vite preview"
  },
  ...
}
Masticate answered 14/12, 2021 at 21:5 Comment(6)
Glad it helped you πŸ‘ŒπŸΌ – Masticate
And I appreciate the time you took to leave a message (: – Masticate
This strategy works well, BUT I got a deprecation message about the static buildpack being replaced with their nginx buildpack with an ERB configuration file. elements.heroku.com/buildpacks/heroku/heroku-buildpack-nginx Also, it didn't build my tailwind correctly. YMMV. – Forelli
Incredible answer. thank you – Actinolite
Aren't steps 3 and 7 mutually annihilating (create static.json and then remove static.json)? – Coition
If I understand it correctly, NGINX uses that under the hood to generate the correct configuration file. That's why it's needed before, but not after. – Masticate
N
6

I tried to use Robin G's solution but the depreciation of that buildpack is at the severe level and causing errors with Heroku 22 (which is the current version).

The readme of heroku/heroku-buildpack-static is telling us to migrate to heroku/heroku-buildpack-nginx but the migration guide relies on buildpack-static to be run before. Because of I can't even run it, I couldn't make use of that migration guide.

Then I tried to set up the project with buildpack-nginx directly but, bumped into issues that I couldn't solve. Even though I have gone through the pain of configuring the path to dist folder in config/nginx.conf.erb as location /dist/, it didn't work. Deploy was successful but I was getting the classic error on visiting the page.

So I decided to go free of relying Heroku's static serving options and installed npm package serve from Vercel. Then I added a start script as follows:

"scripts": {
    "dev": "vite",
    "build": "tsc && vite build",
    "preview": "vite preview",
    "start": "serve dist -s"
},

And fixed! Remove any other buildpack than Node and deploy. It runs without a problem.

Niue answered 21/12, 2022 at 15:3 Comment(5)
Just working on updating this for my app and your solution works mostly well. The only issue I'm running into is the fact that I cannot navigate to subpaths directly, without getting a 404. How do you handle this? With an .htaccess file? If so, can you share what you have there? – Masticate
I didn't need to navigate to subpaths while solving this one. When you run serve with the folder path, without the index.html, it should be working fine on local. Does this only happen on Heroku app? – Niue
"I didn't need to navigate to subpaths while solving this one." are all people answering question these days writing TODO apps? I don't even remember when was the last time I wrote an app that didn't have app router. – Follicle
I flagged your answer as not an answer. It is pretty much useless without proper router configuration. – Follicle
serve dist -s is the proper answer – Follicle
V
2

Recently I went through the same problem as well although the post by Robin G was good, it was not updated. This is what I did to solve the issue. I am using vite + React btw.

As per the Github Repo of heroku-buildpack-static, the buildpack is DECREPRATED, we will need to switch to the buildpack heroku-community/nginx.

# use this command in terminal to add new buildpack
heroku buildpacks:add heroku-community/nginx

We will also need to create a static.json in your app root directory to generate your NGINX config file. Below is a sample of my static.json.

{
  "root": "./dist",
  "routes": {
    "/**": "index.html"
  }
}

Create a Procfile in your app root directory that indicate what command to run when deploying. Below is my Procfile.

web: bin/start-nginx-solo

Afterward deploy your app and go to the shell of your Heroku app.

heroku run bash

When inside the shell, cd ./config and you should be able to see a file call nginx.conf.erb. Copy the content and create and paste it in your app root directory ./config/nginx.conf.erb. Remember to remove any mentions of mruby. Below is my nginx.conf.erb after some changes.

daemon off;
worker_processes auto;

events {
    use epoll;
    accept_mutex on;
    worker_connections 512;
}

http {
    gzip on;
    gzip_comp_level 2;
    gzip_min_length 512;
    gzip_proxied any; # Heroku router sends Via header

    server_tokens off;

    log_format l2met 'measure#nginx.service=$request_time request_id=$http_x_request_id';
    access_log logs/access.log;
    error_log stderr error;

    include mime.types;
    default_type application/octet-stream;
    sendfile on;

    # Must read the body in 5 seconds.
    client_body_timeout 5;

    upstream app_server {
        server unix:/tmp/nginx.socket fail_timeout=0;
    }

    server {
        listen <%= ENV["PORT"] %>;
        server_name _;
        keepalive_timeout 5;
        root /app/dist;

        location = /index.html {
            add_header Cache-Control "no-store, no-cache";
            add_header Strict-Transport-Security "max-age=31536002;";

            try_files $uri $uri/ =404;
        }

        location / {
            add_header 'Cache-Control' "public, max-age=3600";
            try_files $uri $uri/ /index.html;

            # proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            # proxy_set_header Host $http_host;
            # proxy_redirect off;
            # proxy_pass http://app_server;
        }
    }
}

With that pasted, commit your code and try deploying it again! It should work this time. Hope this was able to help solve your issue of deploying vite to heroku.

Note

Remember that the Heroku default app directory is /app not /.

Reference

Valrievalry answered 5/1, 2023 at 13:58 Comment(0)
P
1

Try adding --port $PORT to your start script. It should look like this:

"start": "vite --port $PORT"

I was facing the same issue and that is what worked for me.

This stackoverflow answer helped me figure it out.

I hope it works for you.

Pell answered 28/10, 2021 at 4:51 Comment(0)
I
1

In my case, I was trying to deploy my vite app.

  1. I had to make sure the port was taken from the environment variable
  2. The host was set to 0.0.0.0 instead of localhost
"scripts": {
    "dev": "vite",
    "build": "tsc && vite build",
    "preview": "vite preview --host 0.0.0.0 --port $PORT" // For production
  },

Idomeneus answered 26/10, 2022 at 14:44 Comment(1)
Do not use preview cmd for production, as per documentation: It is important to note that vite preview is intended for previewing the build locally and not meant as a production server. – Scarce
P
0

this https://harrylaou.com/js-ts/vite-heroku/ helped me figure it out since heroku-buildpack-static has been deprecated and doesn't work for latest heroku stack

Plasm answered 14/6, 2023 at 4:51 Comment(0)
L
0

I have a simple solution

Add this to your package script

"heroku-prebuild": "echo "$VITE_ENV" > .env.production",

It save the env content into the .env.production before building. Then the Vite build would load the content.

Lucila answered 5/8, 2024 at 20:8 Comment(0)

© 2022 - 2025 β€” McMap. All rights reserved.