https://github.com/mars/heroku-js-runtime-env-buildpack
π¬π§ Research towards generalization of "JS Runtime Env" from create-react-app-buildpack
https://github.com/mars/heroku-js-runtime-env-buildpack
Last synced: about 1 year ago
JSON representation
π¬π§ Research towards generalization of "JS Runtime Env" from create-react-app-buildpack
- Host: GitHub
- URL: https://github.com/mars/heroku-js-runtime-env-buildpack
- Owner: mars
- License: mit
- Created: 2018-03-14T17:25:23.000Z (over 8 years ago)
- Default Branch: master
- Last Pushed: 2018-03-15T23:57:57.000Z (over 8 years ago)
- Last Synced: 2025-04-15T04:35:30.460Z (over 1 year ago)
- Language: Ruby
- Homepage:
- Size: 30.3 KB
- Stars: 3
- Watchers: 2
- Forks: 9
- Open Issues: 4
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
Heroku JS Runtime Env Buildpack
===============================
Use runtime environment variables in bundled/minified javascript apps.
[](https://travis-ci.org/mars/heroku-js-runtime-env-buildpack)
[](https://www.npmjs.com/package/@mars/heroku-js-runtime-env)
π¬π§ **This is a reasearch project.** Results so far indicate that it's not generalizing to different JS frameworks as gracefully as one might hope.
Usage
-----
A Heroku app uses this buildpack + an [npm module](https://github.com/mars/heroku-js-runtime-env).
`JS_RUNTIME_TARGET_BUNDLE` must be set to the path glob pattern for the javascript bundle containing the [heroku-js-runtime-env](https://github.com/mars/heroku-js-runtime-env). For example:
* create-react-app: `JS_RUNTIME_TARGET_BUNDLE=/app/build/index.*.js`
* ember-cli ([example](#user-content-with-ember)): `JS_RUNTIME_TARGET_BUNDLE=/app/dist/assets/vendor-*.js`
* vue-cli with webpack ([example](#user-content-with-vue)): `JS_RUNTIME_TARGET_BUNDLE=/app/dist/static/js/vendor.*.js`
`JS_RUNTIME_`-prefixed environment variables will be made available in the running Heroku app via npm module [heroku-js-runtime-env](https://github.com/mars/heroku-js-runtime-env).
### with Vue
[Example Vue app](https://github.com/mars/example-vue-with-heroku-js-runtime-env), created in this experiment.
β οΈ Vue's `npm run dev` mode does not pass arbitrary env vars instead requiring settings in `config/dev.env.js`. So, dev mode seems to be broken. (Help?)
βοΈ *Replace `$APP_NAME` with your app's unique name.*
```bash
npm install -g vue-cli
vue init webpack $APP_NAME
cd $APP_NAME
git init
git add .
git commit -m 'π± create Vue app'
heroku create $APP_NAME
heroku buildpacks:add https://github.com/mars/heroku-js-runtime-env-buildpack
heroku config:set JS_RUNTIME_TARGET_BUNDLE=/app/dist/static/js/vendor.*.js
heroku buildpacks:add heroku/nodejs
heroku buildpacks:add https://github.com/heroku/heroku-buildpack-static
# Serve it with static site buildpack
echo '{ "root": "dist/" }' > static.json
git add static.json
git commit -m 'Serve it with static site buildpack'
```
Add Heroku build hook to `package.json`. Merge the following `"heroku-postbuild"` property into the existing `"scripts"` section:
```json
{
"scripts": {
"heroku-postbuild": "npm run build"
}
}
```
Then, commit this change:
```
git add package.json
git commit -m 'Add Heroku build hook to `package.json`'
```
In the Vue component `src/components/HelloWorld.vue`:
```
import runtimeEnv from '@mars/heroku-js-runtime-env'
export default {
name: 'HelloWorld',
data () {
const env = runtimeEnv()
return {
msg: env.JS_RUNTIME_MESSAGE || 'JS_RUNTIME_MESSAGE is empty. Hereβs a donut instead: π©'
}
}
}
```
Then, install the npm module, commit, and deploy the app:
```bash
npm install @mars/heroku-js-runtime-env --save
git add .
git commit -m 'Implement runtimeEnv() in a component'
git push heroku master
heroku open
```
Once deployed, you can set the `JS_RUNTIME_MESSAGE` var to see the new value take effect immediately after the app restarts:
```bash
heroku config:set JS_RUNTIME_MESSAGE=π
heroku open
```
### with Ember
β οΈ **Not working with Ember.** The bundle file integrity check fails, because this technique changes the bundle:
> Failed to find a valid digest in the 'integrity' attribute for resource 'https://example-ember-runtime-env.herokuapp.com/assets/vendor-05f75ec213143035d715ab3c640a3ff4.js' with computed SHA-256 integrity 'oSQ3RCkKyfwVgWjG0HDlTzDFreoQnTQCUCqJoiOJEMs='. The resource has been blocked.
[Example Ember app](https://github.com/mars/example-ember-with-heroku-js-runtime-env), created in this experiment.
βοΈ *Replace `$APP_NAME` with your app's unique name.*
```bash
npm install -g ember-cli
ember new $APP_NAME
cd $APP_NAME
heroku create $APP_NAME
heroku buildpacks:add https://github.com/mars/heroku-js-runtime-env-buildpack
heroku config:set JS_RUNTIME_TARGET_BUNDLE=/app/dist/assets/vendor-*.js
heroku buildpacks:add heroku/nodejs
heroku buildpacks:add https://github.com/heroku/heroku-buildpack-static
# Serve it with static site buildpack
echo '{ "root": "dist/" }' > static.json
git add static.json
git commit -m 'Serve it with static site buildpack'
```
Add Heroku build hook to `package.json`. Merge the following `"heroku-postbuild"` property into the existing `"scripts"` section:
```json
{
"scripts": {
"heroku-postbuild": "ember build --environment=production"
}
}
```
Then, commit this change:
```
git add package.json
git commit -m 'Add Heroku build hook to `package.json`'
```
Create a component that uses JS Runtime Env:
```bash
npm install --save-dev ember-browserify
npm install --save @mars/heroku-js-runtime-env
ember generate component runtime-env
```
Edit the component `app/components/runtime-env.js` to contain:
```
import Component from '@ember/component';
import { computed } from '@ember/object';
import runtimeEnv from 'npm:@mars/heroku-js-runtime-env';
export default Component.extend({
message: computed(function() {
const env = runtimeEnv();
return env.RUNTIME_JS_MESSAGE || 'RUNTIME_JS_MESSAGE is empty. Hereβs a donut instead: π©';
})
});
```
Edit the component template `app/templates/components/runtime-env.hbs` to contain:
```
{{message}}
{{yield}}
```
Edit the application template `app/templates/components/runtime-env.hbs` to contain:
```
{{runtime-env}}
{{!-- The following component displays Ember's default welcome message. --}}
{{welcome-page}}
{{!-- Feel free to remove this! --}}
{{outlet}}
```
Then, commit and deploy the app:
```bash
git add .
git commit -m 'Implement runtimeEnv() in a component'
git push heroku master
heroku open
```
Once deployed, you would ideally set the `RUNTIME_JS_MESSAGE` var to see the new value take effect immediately after the app restarts:
```bash
heroku config:set JS_RUNTIME_MESSAGE=π
heroku open
```
β οΈ **Not working with Ember.** The bundle file integrity check fails, because this technique changes the bundle:
> Failed to find a valid digest in the 'integrity' attribute for resource 'https://example-ember-runtime-env.herokuapp.com/assets/vendor-05f75ec213143035d715ab3c640a3ff4.js' with computed SHA-256 integrity 'oSQ3RCkKyfwVgWjG0HDlTzDFreoQnTQCUCqJoiOJEMs='. The resource has been blocked.
Background
-----------
Normally javascript apps are compiled into a bundle before being deployed. During this build phase, environment variables may be embedded in the javascript bundle, such as with [Webpack DefinePlugin](https://webpack.github.io/docs/list-of-plugins.html#defineplugin).
When hosting on a [12-factor](https://12factor.net) platform like [Heroku](https://www.heroku.com), these embedded values may go stale when setting new [config vars](https://devcenter.heroku.com/articles/config-vars) or promoting through a [pipeline](https://devcenter.heroku.com/articles/pipelines).
Originally developed as part of [create-react-app-buildpack](https://github.com/mars/create-react-app-buildpack), this buildpack aims to solve this problem in a generalized way.
How Does It Work?
-----------------
When developing a JavaScript app, use the [npm module](https://www.npmjs.com/package/@mars/heroku-js-runtime-env) to access runtime environment variables in client-side code.
Then, each time the app starts-up on Heroku, a [`.profile.d` script](.profile.d/inject_js_runtime_env.sh) (installed from the buildpack) is executed which fills in a [JSON placeholder](https://github.com/mars/heroku-js-runtime-env/blob/master/index.js#L15) (with a `REACT_APP_` legacy name) in the JavaScript bundle with the runtime environment variables. The result is πfresh runtime environment variables in the production javascript bundle without recompiling.
Development
-----------
The program which performs the bundle injection is written in Ruby 2.3.1, the version included in the Heroku-16 stack.
```bash
gem install bundler
bundle install
bundle exec rake
```