{"id":15750423,"url":"https://github.com/wei/heroku-buildpack-static","last_synced_at":"2025-03-31T07:16:08.264Z","repository":{"id":83391428,"uuid":"204334463","full_name":"wei/heroku-buildpack-static","owner":"wei","description":"Fork of heroku/heroku-buildpack-static","archived":false,"fork":false,"pushed_at":"2019-08-25T18:33:17.000Z","size":171,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":4,"default_branch":"master","last_synced_at":"2025-02-06T11:55:58.938Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Ruby","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/wei.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2019-08-25T18:33:07.000Z","updated_at":"2020-07-12T07:41:08.000Z","dependencies_parsed_at":null,"dependency_job_id":"8e4c7c84-5fd3-463f-a365-ed887a787e76","html_url":"https://github.com/wei/heroku-buildpack-static","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wei%2Fheroku-buildpack-static","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wei%2Fheroku-buildpack-static/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wei%2Fheroku-buildpack-static/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wei%2Fheroku-buildpack-static/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/wei","download_url":"https://codeload.github.com/wei/heroku-buildpack-static/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":246429493,"owners_count":20775808,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-10-04T06:40:42.627Z","updated_at":"2025-03-31T07:16:08.244Z","avatar_url":"https://github.com/wei.png","language":"Ruby","funding_links":[],"categories":[],"sub_categories":[],"readme":"# heroku-buildpack-static\n**NOTE**: This buildpack is in an experimental OSS project.\n\nThis is a buildpack for handling static sites and single page web apps.\n\nFor a guide, read the [Getting Started with Single Page Apps on Heroku](https://gist.github.com/hone/24b06869b4c1eca701f9).\n\n## Features\n* serving static assets\n* gzip on by default\n* error/access logs support in `heroku logs`\n* custom [configuration](#configuration)\n\n## Deploying\nThe `static.json` file is required to use this buildpack. This file handles all the configuration described below.\n\n1. Set the app to this buildpack: `$ heroku buildpacks:set https://github.com/heroku/heroku-buildpack-static.git`.\n2. Deploy: `$ git push heroku master`\n\n### Configuration\nYou can configure different options for your static application by writing a `static.json` in the root folder of your application.\n\n#### Root\nThis allows you to specify a different asset root for the directory of your application. For instance, if you're using ember-cli, it naturally builds a `dist/` directory, so you might want to use that intsead.\n\n```json\n{\n  \"root\": \"dist/\"\n}\n\n```\n\nBy default this is set to `public_html/`\n\n#### Canonical Host\nThis allows you to perform 301 redirects to a specific hostname, which can be useful for redirecting www to non-www (or vice versa).\n\n```json\n{\n  \"canonical_host\": \"www.example.com\"\n}\n```\n\nYou can use environment variables as well:\n\n```json\n{\n  \"canonical_host\": \"${HOST}\"\n}\n```\n\n#### Default Character Set\nThis allows you to specify a character set for your text assets (HTML, Javascript, CSS, and so on). For most apps, this should be the default value of \"UTF-8\", but you can override it by setting `encoding`:\n\n```json\n{\n    \"encoding\": \"US-ASCII\"\n}\n```\n\n#### Clean URLs\nFor SEO purposes, you can drop the `.html` extension from URLs for say a blog site. This means users could go to `/foo` instead of `/foo.html`.\n\n\n```json\n{\n  \"clean_urls\": true\n}\n```\n\nBy default this is set to `false`.\n\n\n#### Logging\nYou can disable the access log and change the severity level for the error log.\n\n```json\n{\n  \"logging\": {\n    \"access\": false,\n    \"error\": \"warn\"\n  }\n}\n```\n\nBy default `access` is set to `true` and `error` is set to `error`.\n\nThe environment variable `STATIC_DEBUG` can be set, to override the `error` log level to `error`.\n\n\n#### Custom Routes\nYou can define custom routes that combine to a single file. This allows you to preserve routing for a single page web application. The following operators are supported:\n\n* `*` supports a single path segment in the URL. In the configuration below, `/baz.html` would match but `/bar/baz.html` would not.\n* `**` supports any length in the URL.  In the configuration below, both `/route/foo` would work and `/route/foo/bar/baz`.\n\n```json\n{\n  \"routes\": {\n    \"/*.html\": \"index.html\",\n    \"/route/**\": \"bar/baz.html\"\n  }\n}\n```\n\n##### Browser history and asset files\nWhen serving a single page app, it's useful to support wildcard URLs that serves the index.html file, while also continuing to serve JS and CSS files correctly. Route ordering allows you to do both:\n\n```json\n{\n  \"routes\": {\n    \"/assets/*\": \"/assets/\",\n    \"/**\": \"index.html\"\n  }\n}\n```\n\n#### Custom Redirects\nWith custom redirects, you can move pages to new routes but still preserve the old routes for SEO purposes. By default, we return a `301` status code, but you can specify the status code you want.\n\n```json\n{\n  \"redirects\": {\n    \"/old/gone/\": {\n      \"url\": \"/\",\n      \"status\": 302\n    }\n  }\n}\n```\n\n##### Interpolating Env Var Values\nIt's common to want to be able to test the frontend against various backends. The `url` key supports environment variable substitution using `${ENV_VAR_NAME}`. For instance, if there was a staging and production Heroku app for your API, you could setup the config above like the following:\n\n```json\n{\n  \"redirects\": {\n    \"/old/gone/\": {\n      \"url\": \"${NEW_SITE_DOMAIN}/new/here/\"\n    }\n  }\n}\n```\n\nThen using the [config vars](https://devcenter.heroku.com/articles/config-vars), you can point the frontend app to the appropriate backend. To match the original proxy setup:\n\n```bash\n$ heroku config:set NEW_SITE_DOMAIN=\"https://example.herokapp.com\"\n```\n\n#### Custom Error Pages\nYou can replace the default nginx 404 and 500 error pages by defining the path to one in your config.\n\n```json\n{\n  \"error_page\": \"errors/error.html\"\n}\n```\n\n#### HTTPS Only\n\nYou can redirect all HTTP requests to HTTPS.\n\n```\n{\n  \"https_only\": true\n}\n```\n\n#### Basic Authentication\n\nYou can enable Basic Authentication so all requests require authentication.\n\n```\n{\n  \"basic_auth\": true\n}\n```\n\nThis will generate `.htpasswd` using environment variables `BASIC_AUTH_USERNAME` and `BASIC_AUTH_PASSWORD` if they are present. Otherwise it will use a standard `.htpasswd` file present in the `app` directory.\n\nPasswords set via `BASIC_AUTH_PASSWORD` can be generated using OpenSSL or Apache Utils. For instance: `openssl passwd -apr1`.\n\n#### Proxy Backends\nFor single page web applications like Ember, it's common to back the application with another app that's hosted on Heroku. The down side of separating out these two applications is that now you have to deal with CORS. To get around this (but at the cost of some latency) you can have the static buildpack proxy apps to your backend at a mountpoint. For instance, we can have all the api requests live at `/api/` which actually are just requests to our API server.\n\n```json\n{\n  \"proxies\": {\n    \"/api/\": {\n      \"origin\": \"https://hone-ember-todo-rails.herokuapp.com/\"\n    }\n  }\n}\n```\n\n##### Interpolating Env Var Values\nIt's common to want to be able to test the frontend against various backends. The `origin` key supports environment variable substitution using `${ENV_VAR_NAME}`. For instance, if there was a staging and production Heroku app for your API, you could setup the config above like the following:\n\n```json\n{\n  \"proxies\": {\n    \"/api/\": {\n      \"origin\": \"https://${API_APP_NAME}.herokuapp.com/\"\n    }\n  }\n}\n```\n\nThen using the [config vars](https://devcenter.heroku.com/articles/config-vars), you can point the frontend app to the appropriate backend. To match the original proxy setup:\n\n```bash\n$ heroku config:set API_APP_NAME=\"hone-ember-todo-rails\"\n```\n\n#### Custom Headers\nUsing the headers key, you can set custom response headers. It uses the same operators for pathing as [Custom Routes](#custom-routes).\n\n```json\n{\n  \"headers\": {\n    \"/\": {\n      \"Cache-Control\": \"no-store, no-cache\"\n    },\n    \"/assets/**\": {\n      \"Cache-Control\": \"public, max-age=512000\"\n    },\n    \"/assets/webfonts/*\": {\n      \"Access-Control-Allow-Origin\": \"*\"\n    }\n  }\n}\n```\n\nFor example, to enable CORS for all resources, you just need to enable it for all routes like this:\n\n```json\n{\n  \"headers\": {\n    \"/**\": {\n      \"Access-Control-Allow-Origin\": \"*\"\n    }\n  }\n}\n```\n\n##### Precedence\nWhen there are header conflicts, the last header definition always wins. The headers do not get appended. For example,\n\n```json\n{\n  \"headers\": {\n    \"/**\": {\n      \"X-Foo\": \"bar\",\n      \"X-Bar\": \"baz\"\n    },\n    \"/foo\": {\n      \"X-Foo\": \"foo\"\n    }\n  }\n}\n```\n\nwhen accessing `/foo`, `X-Foo` will have the value `\"foo\"` and `X-Bar` will not be present.\n\n### Route Ordering\n\n* HTTPS redirect\n* Root Files\n* Clean URLs\n* Proxies\n* Redirects\n* Custom Routes\n* 404\n\n### Procfile / multiple buildpacks\n\nIn case you have multiple buildpacks for the application you can ensure static rendering in `Procfile` with `web: bin/boot`.\n\n## Testing\nFor testing we use Docker to replicate Heroku locally. You'll need to have [it setup locally](https://docs.docker.com/installation/). We're also using rspec for testing with Ruby. You'll need to have those setup and install those deps:\n\n```sh\n$ bundle install\n```\n\nTo run the test suite just execute:\n\n```sh\n$ bundle exec rspec\n```\n\n### Structure\nTo add a new test, add another example inside `spec/simple_spec.rb` or create a new file based off of `spec/simple_spec.rb`. All the example apps live in `spec/fixtures`.\n\nWhen writing a test, `BuildpackBuilder` creates the docker container we need that represents the heroku cedar-14 stack. `AppRunner.new` takes the name of a fixture and mounts it in the container built by `BuildpackBuilder` to run tests against. The `AppRunner` instance provides convenience methods like `get` that just wrap `net/http` for analyzing the response.\n\n### Boot2docker\n\nIf you are running docker with boot2docker, the buildpack will automatically send tests to the right ip address.\nYou need to forward the docker's port 3000 to the virtual machine's port though.\n\n```\nVBoxManage modifyvm \"boot2docker-vm\" --natpf1 \"tcp-port3000,tcp,,3000,,3000\";\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fwei%2Fheroku-buildpack-static","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fwei%2Fheroku-buildpack-static","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fwei%2Fheroku-buildpack-static/lists"}