Harmonize client & server env handling

* Remove defaults from multiple places in code. Put them to .env-template instead
* Do not use imported config.js in server. Access process.env directly instead
* Instruct using .env for local development, not .env.development.local
This commit is contained in:
Olli Vanhapiha 2018-03-15 13:15:14 +02:00
parent 5ae25e2e62
commit 6380d7569f
14 changed files with 128 additions and 49 deletions

33
.env-template Normal file
View file

@ -0,0 +1,33 @@
# Mandatory configuration
#
REACT_APP_SHARETRIBE_SDK_CLIENT_ID=
REACT_APP_GOOGLE_MAPS_API_KEY=
REACT_APP_STRIPE_PUBLISHABLE_KEY=
# Defaults
#
REACT_APP_SHARETRIBE_SDK_BASE_URL=http://localhost:8088
REACT_APP_SHARETRIBE_MARKETPLACE_CURRENCY=USD
REACT_APP_CANONICAL_ROOT_URL=http://localhost:3000
PORT=4000
# This is overwritten by configuration in .env.development and
# .env.test. In production deployments use env variable and set it to
# 'production'
REACT_APP_ENV=production
# Options. Uncomment and set to test.
#
# REACT_APP_SHARETRIBE_USING_SSL=true
# SERVER_SHARETRIBE_TRUST_PROXY=true
# REACT_APP_PUBLIC_SENTRY_DSN=change-me
# SERVER_SENTRY_DSN=change-me
# REACT_APP_CSP=report
# BASIC_AUTH_USERNAME=sharetribe
# BASIC_AUTH_PASSWORD=secret
# REACT_APP_GOOGLE_ANALYTICS_ID=change-me

View file

@ -1,2 +1 @@
NODE_ENV=development
REACT_APP_ENV=development

View file

@ -1,3 +1,3 @@
NODE_ENV=test
REACT_APP_ENV=test
REACT_APP_SHARETRIBE_MARKETPLACE_CURRENCY=USD
REACT_APP_CANONICAL_ROOT_URL=http://localhost:3000

2
.gitignore vendored
View file

@ -13,4 +13,4 @@ build
.DS_Store
.env
npm-debug.log
/.env.development.local
yarn-error.log

View file

@ -24,13 +24,16 @@ Clone this repository and install dependencies:
## Development
**First, you need to configure Client Id, Google Maps API key and
Stripe publishable API key via [environment
variables](./docs/env.md).** The quickest way to do this is to copy
.env-template -> .env, and edit the file to add the three mandatory
configuration values.
To develop the application and to see changes live, start the frontend development server:
yarn run dev
**You need to configure Client Id, Google Maps API key and Stripe
publishable API key via [environment variables](./docs/env.md).**
**Known issues:**
* Adding/changing `import`s may not be synced properly with ESLint. You may see an error

View file

@ -3,27 +3,32 @@
The following configuration variables can be set to control the Starter App behaviour. Most of them
have defaults that work for development environment. For production deploys most should be set.
| Variable | Must be set? | Default | Description |
| ----------------------------------------- | ------------ | ----------------------- | ------------------------------------------------------------------------------------------------------- |
| REACT_APP_GOOGLE_MAPS_API_KEY | X | - | See: [Google Maps API key](./google-maps.md) |
| REACT_APP_SHARETRIBE_SDK_CLIENT_ID | X | - | Client ID (API key). You will get this from the Sharetribe team. |
| REACT_APP_STRIPE_PUBLISHABLE_KEY | X | - | Stripe publishable API key for generating tokens with Stripe API. |
| REACT_APP_SHARETRIBE_SDK_BASE_URL | | `http://localhost:8088` | The base url to access the Marketplace API. |
| REACT_APP_SHARETRIBE_MARKETPLACE_CURRENCY | | USD | The currency used in the Marketplace as ISO 4217 currency code. For example: USD, EUR, CAD, AUD, etc. |
| REACT_APP_CANONICAL_ROOT_URL | | `http://localhost:3000` | Canonical root url of the marketplace is running. Needed for social media sharing and SEO optimization. |
| NODE_ENV | | ? | Node env. Use 'dev' for development and 'production' for production. |
| REACT_APP_ENV | | production | TODO Didn't understand NODE_ENV vs this? |
| REACT_APP_SHARETRIBE_USING_SSL | | false | Redirect HTTP to HTTPS. |
| SERVER_SHARETRIBE_TRUST_PROXY | | false | Set when running the app behind a reverse proxy. |
| REACT_APP_PUBLIC_SENTRY_DSN | | - | See: [Error logging with Sentry](./sentry.md) |
| SERVER_SENTRY_DSN | | - | See: [Error logging with Sentry](./sentry.md) |
| REACT_APP_CSP | | - | See: [Content Security Policy (CSP)](./content-security-policy.md) |
| BASIC_AUTH_USERNAME | | - | Set to enable HTTP Basic Auth |
| BASIC_AUTH_PASSWORD | | - | Set to enable HTTP Basic Auth |
| REACT_APP_GOOGLE_ANALYTICS_ID | | - | See: [Google Analytics](./analytics.md) |
| Variable | Must be set? | Default | Description |
| ----------------------------------------- | ------------ | --------------------- | ----------------------------------------------------------------------------------------------------------------- |
| REACT_APP_GOOGLE_MAPS_API_KEY | X | - | See: [Google Maps API key](./google-maps.md) |
| REACT_APP_SHARETRIBE_SDK_CLIENT_ID | X | - | Client ID (API key). You will get this from the Sharetribe team. |
| REACT_APP_STRIPE_PUBLISHABLE_KEY | X | - | Stripe publishable API key for generating tokens with Stripe API. Use test key (prefix pk*test*) for development. |
| REACT_APP_SHARETRIBE_SDK_BASE_URL | | http://localhost:8088 | The base url to access the Sharetribe Flex Marketplace API. |
| REACT_APP_SHARETRIBE_MARKETPLACE_CURRENCY | | USD | The currency used in the Marketplace as ISO 4217 currency code. For example: USD, EUR, CAD, AUD, etc. |
| REACT_APP_CANONICAL_ROOT_URL | | http://localhost:3000 | Canonical root url of the marketplace. Needed for social media sharing and SEO optimization. |
| NODE_ENV | | ? | Node env. Use 'development' for development and 'production' for production. |
| PORT | | 4000 | Port for server to accept connections. |
| REACT_APP_ENV | | production | Env for client side. Use the same value as with NODE_ENV. |
| REACT_APP_SHARETRIBE_USING_SSL | | false | Redirect HTTP to HTTPS? |
| SERVER_SHARETRIBE_TRUST_PROXY | | false | Set when running the app behind a reverse proxy, e.g. in Heroku. |
| REACT_APP_PUBLIC_SENTRY_DSN | | - | See: [Error logging with Sentry](./sentry.md) |
| SERVER_SENTRY_DSN | | - | See: [Error logging with Sentry](./sentry.md) |
| REACT_APP_CSP | | - | See: [Content Security Policy (CSP)](./content-security-policy.md) |
| BASIC_AUTH_USERNAME | | - | Set to enable HTTP Basic Auth |
| BASIC_AUTH_PASSWORD | | - | Set to enable HTTP Basic Auth |
| REACT_APP_GOOGLE_ANALYTICS_ID | | - | See: [Google Analytics](./analytics.md) |
## Defining the env variables
When the Starter App is started locally with `yarn run dev` you can set environment variables by
using the file .env.development.local. However, the server process doesn't currently pick up values
from this file. In production it is recommended to set the environment variables on OS level.
When the Starter App is started locally with `yarn run dev` or `yarn run dev-server`, you can set
environment variables by using the file .env file. The repository contains a template file
.env-template. Just copy that as .env and edit as necessary.
In production, it's recommended that you set the configuration via env variables and do not deploy
an .env file. The client application will only be packaged with env variables that start with
REACT_APP. This way server secrets don't end up in client bundles.

View file

@ -20,8 +20,7 @@ section of the Places library documentation to enable using the Google Places AP
## Setup the application to use the API key
The application uses the `REACT_APP_GOOGLE_MAPS_API_KEY` environment variable for the key value. For
local development, you can add the variable in the Gitignored `.env.development.local` file in the
project root:
local development, you can add the variable in the Gitignored `.env` file in the project root:
```
REACT_APP_GOOGLE_MAPS_API_KEY=my-key-here

View file

@ -66,7 +66,7 @@
"test-ci": "sharetribe-scripts test --env=jsdom --runInBand",
"eject": "sharetribe-scripts eject",
"start": "node server/index.js",
"dev-server": "export REACT_APP_ENV=development REACT_APP_CANONICAL_ROOT_URL=http://localhost:4000&&yarn run build&&nodemon --watch server server/index.js",
"dev-server": "export NODE_ENV=development REACT_APP_CANONICAL_ROOT_URL=http://localhost:4000&&yarn run build&&nodemon --watch server server/index.js",
"heroku-prebuild": "./heroku-copy-ssh-key-from-env.sh",
"heroku-postbuild": "yarn run build",
"audit": "nsp check --preprocessor yarn"

View file

@ -1,5 +1,4 @@
const helmet = require('helmet');
const { config } = require('./importer');
const dev = process.env.REACT_APP_ENV === 'development';
const googleAnalyticsEnabled = !!process.env.REACT_APP_GOOGLE_ANALYTICS_ID;
@ -21,7 +20,7 @@ module.exports = (reportUri, enforceSsl, reportOnly) => {
const self = "'self'";
const inline = "'unsafe-inline'";
const data = 'data:';
const sharetribeApi = config.sdk.baseUrl;
const sharetribeApi = process.env.REACT_APP_SHARETRIBE_SDK_BASE_URL;
const sharetribeAssets = 'https://assets-sharetribecom.sharetribe.com/';
const imgix = '*.imgix.net/';
const loremPixel = 'https://lorempixel.com/';

41
server/env.js Normal file
View file

@ -0,0 +1,41 @@
/**
Implements .env file loading that mimicks the way create-react-app
does it. We want this to get consistent configuration handling
between client and node server.
*/
const fs = require('fs');
const NODE_ENV = process.env.NODE_ENV;
if (!NODE_ENV) {
throw new Error('The NODE_ENV environment variable is required but was not specified.');
}
// https://github.com/bkeepers/dotenv#what-other-env-files-can-i-use
var dotenvFiles = [
`.env.${NODE_ENV}.local`,
`.env.${NODE_ENV}`,
// Don't include `.env.local` for `test` environment
// since normally you expect tests to produce the same
// results for everyone
NODE_ENV !== 'test' && `env.local`,
'.env',
].filter(Boolean);
const configureEnv = () => {
// Load environment variables from .env* files. Suppress warnings using silent
// if this file is missing. dotenv will never modify any environment variables
// that have already been set.
// https://github.com/motdotla/dotenv
dotenvFiles.forEach(dotenvFile => {
if (fs.existsSync(dotenvFile)) {
console.log('Loading env from file:' + dotenvFile);
require('dotenv').config({ path: dotenvFile });
}
});
};
module.exports = {
configureEnv: configureEnv,
};

View file

@ -17,5 +17,4 @@ module.exports = {
matchPathname: mainJs.matchPathname,
configureStore: mainJs.configureStore,
routeConfiguration: mainJs.routeConfiguration,
config: mainJs.config,
};

View file

@ -16,6 +16,9 @@
// This enables nice stacktraces from the minified production bundle
require('source-map-support').install();
// Configure process.env with .env.* files
require('./env').configureEnv();
const express = require('express');
const helmet = require('helmet');
const compression = require('compression');
@ -35,12 +38,11 @@ const { sitemapStructure } = require('./sitemap');
const csp = require('./csp');
const buildPath = path.resolve(__dirname, '..', 'build');
const env = process.env.REACT_APP_ENV || 'production';
const env = process.env.REACT_APP_ENV;
const dev = process.env.REACT_APP_ENV === 'development';
const PORT = process.env.PORT || 4000;
const CLIENT_ID =
process.env.REACT_APP_SHARETRIBE_SDK_CLIENT_ID || '08ec69f6-d37e-414d-83eb-324e94afddf0';
const BASE_URL = process.env.REACT_APP_SHARETRIBE_SDK_BASE_URL || 'http://localhost:8088';
const PORT = process.env.PORT;
const CLIENT_ID = process.env.REACT_APP_SHARETRIBE_SDK_CLIENT_ID;
const BASE_URL = process.env.REACT_APP_SHARETRIBE_SDK_BASE_URL;
const USING_SSL = process.env.REACT_APP_SHARETRIBE_USING_SSL === 'true';
const TRUST_PROXY = process.env.SERVER_SHARETRIBE_TRUST_PROXY || null;
const CSP = process.env.REACT_APP_CSP;

View file

@ -1,9 +1,8 @@
const path = require('path');
const moment = require('moment');
const { config } = require('./importer');
const buildPath = path.resolve(__dirname, '..', 'build');
const PORT = process.env.PORT || 4000;
const PORT = process.env.PORT;
const USING_SSL = process.env.REACT_APP_SHARETRIBE_USING_SSL === 'true';
/**
@ -44,17 +43,17 @@ const port = rootURL => {
};
/**
* Return a structure for sitemap.xml and robots.txt to be
* used by the express-sitemap library. Uses the canonical
* URL value from config for domain and port information.
* Return a structure for sitemap.xml and robots.txt to be used by the
* express-sitemap library. Uses the canonical URL value from env
* config for domain and port information.
*/
exports.sitemapStructure = () => {
const now = moment().format('YYYY-MM-DD');
return {
url: domain(config.canonicalRootURL),
url: domain(process.env.REACT_APP_CANONICAL_ROOT_URL),
http: USING_SSL ? 'https' : 'http',
port: port(config.canonicalRootURL),
port: port(process.env.REACT_APP_CANONICAL_ROOT_URL),
sitemap: path.join(buildPath, 'static', 'sitemap.xml'),
robots: path.join(buildPath, 'robots.txt'),
sitemapSubmission: '/static/sitemap.xml',

View file

@ -1,6 +1,6 @@
import * as custom from './marketplace-custom-config.js';
const env = process.env.REACT_APP_ENV || 'production';
const env = process.env.REACT_APP_ENV;
const dev = process.env.REACT_APP_ENV === 'development';
// If you want to change the language, remember to also change the
@ -33,9 +33,9 @@ const bookingUnitType = 'line-item/night';
// react-scripts) require using the REACT_APP_ prefix to avoid
// exposing server secrets to the client side.
const sdkClientId = process.env.REACT_APP_SHARETRIBE_SDK_CLIENT_ID;
const sdkBaseUrl = process.env.REACT_APP_SHARETRIBE_SDK_BASE_URL || 'http://localhost:8088';
const sdkBaseUrl = process.env.REACT_APP_SHARETRIBE_SDK_BASE_URL;
const currency = process.env.REACT_APP_SHARETRIBE_MARKETPLACE_CURRENCY || 'USD';
const currency = process.env.REACT_APP_SHARETRIBE_MARKETPLACE_CURRENCY;
// Sentry DSN (Data Source Name), a client key for authenticating calls to Sentry
const sentryDsn = process.env.REACT_APP_PUBLIC_SENTRY_DSN;
@ -219,7 +219,7 @@ const postalCode = '00100';
const streetAddress = 'Bulevardi 14';
// Canonical root url is needed in social media sharing and SEO optimization purposes.
const canonicalRootURL = process.env.REACT_APP_CANONICAL_ROOT_URL || 'http://localhost:3000';
const canonicalRootURL = process.env.REACT_APP_CANONICAL_ROOT_URL;
// Site title is needed in meta tags (bots and social media sharing reads those)
const siteTitle = 'Saunatime';