How to deploy a Parcel build to Heroku


This article goes over how to deploy a Parcel build to Heroku.

Parcel

Given you have a Parcel app:

In your package.json, make sure there’s a build script:

{
  "scripts": {
    "build": "parcel build"
  }
}

Heroku runs the build script if it exists during deploy.

Serve

Install serve to serve the static site:

npm install serve

Create a start script in package.json:

{
  "scripts": {
    "build": "parcel build",
    "start": "serve"
  },
  "dependencies": {
    "serve": "latest"
  }
}

Or create a Procfile to serve your project directory:

echo 'web: npx serve' > Procfile

Heroku determines how to start your app by looking for a Procfile or start script.

Then create serve.json so the static site and routes are served correctly:

touch serve.json
{
  "public": "dist",
  "rewrites": [{ "source": "**", "destination": "/index.html" }],
  "headers": [
    {
      "source": "**",
      "headers": [
        {
          "key": "Cache-Control",
          "value": "public, max-age=0, must-revalidate"
        }
      ]
    },
    {
      "source": "**/*.@(css|ico|jpg|jpeg|js|gif|png)",
      "headers": [
        {
          "key": "Cache-Control",
          "value": "public, max-age=31536000, immutable"
        }
      ]
    }
  ]
}

Commit and push your repository.

Deprecated

Add the Heroku buildpacks in order:

  1. heroku/nodejs
  2. heroku-buildpack-static (deprecated)

The Node.js buildpack must come before the static buildpack since the site has to be built before it can be served.

The buildpacks can be added via the Heroku CLI:

heroku buildpacks:set heroku/nodejs --app <MY_APP_NAME>
heroku buildpacks:add https://github.com/heroku/heroku-buildpack-static.git --app <MY_APP_NAME>

Replace <MY_APP_NAME> with your Heroku app name.

Or they can be added with app.json:

{
  "buildpacks": [
    {
      "url": "heroku/nodejs"
    },
    {
      "url": "https://github.com/heroku/heroku-buildpack-static"
    }
  ]
}

Create a static.json:

touch static.json

And configure the options for your static application:

{
  "root": "dist/",
  "routes": {
    "**": "index.html"
  },
  "https_only": true,
  "error_page": "index.html",
  "headers": {
    "/**": {
      "Cache-Control": "public, max-age=0, must-revalidate"
    },
    "/**.css": {
      "Cache-Control": "public, max-age=31536000, immutable"
    },
    "/**.ico": {
      "Cache-Control": "public, max-age=31536000, immutable"
    },
    "/**.jpg": {
      "Cache-Control": "public, max-age=31536000, immutable"
    },
    "/**.jpeg": {
      "Cache-Control": "public, max-age=31536000, immutable"
    },
    "/**.js": {
      "Cache-Control": "public, max-age=31536000, immutable"
    },
    "/**.png": {
      "Cache-Control": "public, max-age=31536000, immutable"
    }
  }
}

Push and deploy the Heroku app. The build log should look like:

-----> Building on the Heroku-20 stack
-----> Using buildpacks:
       1. heroku/nodejs
       2. https://github.com/heroku/heroku-buildpack-static
-----> Node.js app detected
-----> Creating runtime environment
-----> Installing binaries
-----> Restoring cache
-----> Installing dependencies
-----> Build
-----> Pruning devDependencies
-----> Caching build
-----> Build succeeded!
-----> Static HTML app detected
-----> Installed nginx 1.19.0 to /app/bin
-----> Discovering process types
       Procfile declares types     -> (none)
       Default types for buildpack -> web
-----> Compressing...
-----> Launching...
       Released v1
       https://myappname.herokuapp.com/ deployed to Heroku

There’s no need for a Procfile since Heroku automatically creates a dyno for your static app:

web bin/boot


Please support this site and join our Discord!