@ethical-jobs/dynamic-env
Version:
Helper scripts and documentation for creating Javascript apps with a dynamically deployed environment.
277 lines (196 loc) • 7.87 kB
Markdown
# JavaScript Dynamic Environment Helper Package
## Purpose
This package helps to generate dynamic environment based on the current deployment environment instead of relying on a
statically built system that requires a new build for each stage of the dev process. This allows for building once
and deploying everywhere.
> NOTE: This package will not help you build a dynamic environment for static files deployed on a CDN!
> HINT: It's not really dynamic - it's just dynamically generating an environment at boot time for the app to use. So if
you change your `env` you'll need to restart your dev or docker container, etc to reinitialise your app's environment.
## Further reading
More info can be found here https://github.com/facebook/create-react-app/issues/2353
## Kudos
This package is based on the post Krunoslav Banovac (@kunokdev) wrote which can be found here
https://medium.freecodecamp.org/how-to-implement-runtime-environment-variables-with-create-react-app-docker-and-nginx-7f9d42a91d70
## How it works
This package provides shell scripts that can be incorporated into any javascript project that requires a dynamically
set runtime environment at the time of deployment. To achieve this we need to integrate the scripts in this package with
the tooling in our apps.
There are 2 scripts which run on the `bash` shell.
### `env-add`
Creates an environment variable and sets it's default. It is an interactive script which saves the variable
in `.env.example` in the root of you application.
### `env-gen`
Generates the application's environment when required. The default location of the generated file is `public/env.js`.
The resulting code is something like the following.
```javascript
/**
* WARNING: This file is generated by env-gen.sh
* Do not modify this file directly!
*/
window._env_ = {
"APP_DEBUG": "true",
"APP_ENV": "local",
};
```
## Prerequisites
The following command line tools are required to run the scripts and must be installed on deployment hosts.
##### `jq`
This tool is used to verify and format JSON documents. Please refer to https://stedolan.github.io/jq/ for downloads and
installation instructions for your system.
##### `dotenv-to-json`
This tool converts `.env` files to JSON representation. It can be installed globally using the following command, for
more information refer to https://www.npmjs.com/package/dotenv-to-json.
```bash
yarn global add dotenv-to-json
```
## Installation
This package will be required in your production environment so should be installed in the `requirements` section of
`package.json`
###### NPM
```bash
npm require @ethical-jobs/dynamic-env
```
###### Yarn
```bash
yarn add @ethical-jobs/dynamic-env
```
## Integrating into your application
### Adding variables to `.env.example`
This file has 2 functions.
- The first is to be an example of the env required by the application.
- The second is to act as a whitelist of which variables are allowed to be exposed in the application.
> NOTE: if a variable is not defined in this file it will not appear in your application environment.
To add variables to `.env.example` you can use the script in this package `env-add`. This script is interactive
and supports base64 encoding if needed.
You are free to manually add variables to `.env.example` and they will not be overwritten.
```bash
$ env-add
Name of variable: APP_ENV
Default value for variable 'APP_ENV': production
Would you like to base64 encode the value?
1) Yes
2) No
#? 2
Should value be quoted?
1) Yes
2) No
#? 2
APP_ENV=production
```
Once you have set up your variables in `.env.example` you are ready to publish your dynamic env.
### Modify `index.html` to access your variables.
In the `<head>` section of your app add the following script to allow access to your dynamic variables.
```html
<script src="%PUBLIC_URL%/env.js"></script>
```
This is an example of a `create-react-app` setup. Modify for your application's public folder.
### Publishing your dynamic environment
The script `env-gen` is used to publish your environment when you require it in your app. To do so just run `env-gen` in
your app's root directory and it will generate `env.js` for you.
### Accessing environment variables in your app
To access your environment variables in your app you can now do so with the following syntax.
> HINT: this replaces process.env.ENV_VAR
```javascript
const appEnv = window._env_.ENV_VAR;
```
#### Use in development environments
To utilise your dynamic variables in a development environment you need to modify your `package.json` scripts section
that starts your dev server. An example would be for the `create-react-app` but you can use this in any JavaScript
project.
```json
{
"scripts": {
"dev": "gen-env && react-scripts start"
}
}
```
Then you can run your development server as per normal.
```bash
yarn dev
```
#### Use in Docker container
Using Docker for your deployments is where this is really useful. It is also very easy to setup and configure to your
own requirements. Below is an example of how you could setup a Dockerfile.
```dockerfile
# => Build container
FROM node:alpine as builder
WORKDIR /app
COPY package.json .
COPY yarn.lock .
RUN yarn
COPY . .
RUN yarn build
# => Run container
FROM nginx:alpine
# install node and jq
RUN apk add --no-cache nodejs-current yarn jq
# install global node scripts
RUN yarn global add dotenv-to-json @ethical-jobs/dynamic-env
# Nginx config
RUN rm -rf /etc/nginx/conf.d
COPY conf /etc/nginx
# Static build
COPY --from=builder /app/build /usr/share/nginx/html/
COPY --from=builder /app/.env.example /usr/share/nginx/html/.env.example
# Default port exposure
EXPOSE 80
# Copy .env file and shell script to container
WORKDIR /usr/share/nginx/html
# Add bash
RUN apk add --no-cache bash
ENV ENV_DEST=/usr/share/nginx/html
# Start Nginx server
CMD ["/bin/bash", "-c", "env-gen && nginx -g \"daemon off;\""]
```
The important sections of this `Dockerfile` are:
Install the dependencies.
```dockerfile
# install node and jq
RUN apk add --no-cache nodejs-current yarn jq
# install global node scripts
RUN yarn global add dotenv-to-json @ethical-jobs/dynamic-env
```
Set a different destination folder. In this case our install folder (where our built scripts go).
```dockerfile
ENV ENV_DEST=/usr/share/nginx/html
```
Add `env-gen` to your runtime command so when the container starts it generates your environment file.
```dockerfile
CMD ["/bin/bash", "-c", "env-gen && nginx -g \"daemon off;\""]
```
You should modify your config to whatever setup you need.
### Use with Docker Compose
An example Docker Compose for local development purposes. Used with the `Dockerfile` example above.
```yaml
version: "3.2"
services:
app:
build:
context: .
image: dynamicenvtest
ports:
- "5000:80"
env_file:
- .env.example
- .env
environment:
- "ENV_DEST=/usr/share/nginx/html/"
```
#### Use in Kubernetes
You need to allow Kubernetes to pull in any environment variables you have set in `.env.example`. Refer to your host
documentation on how to do this.
### `.gitignore`
Make sure to update your Git ignore with the following.
```
public/env.js
env.js
.env
.env.generated
```
### `env-gen` overridable variables
Set these in your env or as ENV in your Dockerfile or anywhere you need to override the script defaults.
- `BASE_DIR` sets the base directory of your app. This defaults to `.` or current directory
- `ENV_DEST` set the `env.js` final destination. This defaults to `public/` and should be set to wherever your public
directory is situated
- `WHITELIST_FILE` set the name of your whitelist file if different to your example env. This defaults to `.env.example`
- `ENV_JS` set this to change the name of your generated `env.js` file. This defaults to `env.js`