mirror of
https://github.com/kingomarnajjar/flex-template-web.git
synced 2026-07-25 22:37:18 +10:00
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:
parent
5ae25e2e62
commit
6380d7569f
14 changed files with 128 additions and 49 deletions
33
.env-template
Normal file
33
.env-template
Normal 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
|
||||||
|
|
@ -1,2 +1 @@
|
||||||
NODE_ENV=development
|
|
||||||
REACT_APP_ENV=development
|
REACT_APP_ENV=development
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,3 @@
|
||||||
NODE_ENV=test
|
|
||||||
REACT_APP_ENV=test
|
REACT_APP_ENV=test
|
||||||
REACT_APP_SHARETRIBE_MARKETPLACE_CURRENCY=USD
|
REACT_APP_SHARETRIBE_MARKETPLACE_CURRENCY=USD
|
||||||
|
REACT_APP_CANONICAL_ROOT_URL=http://localhost:3000
|
||||||
2
.gitignore
vendored
2
.gitignore
vendored
|
|
@ -13,4 +13,4 @@ build
|
||||||
.DS_Store
|
.DS_Store
|
||||||
.env
|
.env
|
||||||
npm-debug.log
|
npm-debug.log
|
||||||
/.env.development.local
|
yarn-error.log
|
||||||
|
|
|
||||||
|
|
@ -24,13 +24,16 @@ Clone this repository and install dependencies:
|
||||||
|
|
||||||
## Development
|
## 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:
|
To develop the application and to see changes live, start the frontend development server:
|
||||||
|
|
||||||
yarn run dev
|
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:**
|
**Known issues:**
|
||||||
|
|
||||||
* Adding/changing `import`s may not be synced properly with ESLint. You may see an error
|
* Adding/changing `import`s may not be synced properly with ESLint. You may see an error
|
||||||
|
|
|
||||||
47
docs/env.md
47
docs/env.md
|
|
@ -3,27 +3,32 @@
|
||||||
The following configuration variables can be set to control the Starter App behaviour. Most of them
|
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.
|
have defaults that work for development environment. For production deploys most should be set.
|
||||||
|
|
||||||
| Variable | Must be set? | Default | Description |
|
| Variable | Must be set? | Default | Description |
|
||||||
| ----------------------------------------- | ------------ | ----------------------- | ------------------------------------------------------------------------------------------------------- |
|
| ----------------------------------------- | ------------ | --------------------- | ----------------------------------------------------------------------------------------------------------------- |
|
||||||
| REACT_APP_GOOGLE_MAPS_API_KEY | X | - | See: [Google Maps API key](./google-maps.md) |
|
| 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_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_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 Marketplace API. |
|
| 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_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. |
|
| 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 'dev' for development and 'production' for production. |
|
| NODE_ENV | | ? | Node env. Use 'development' for development and 'production' for production. |
|
||||||
| REACT_APP_ENV | | production | TODO Didn't understand NODE_ENV vs this? |
|
| PORT | | 4000 | Port for server to accept connections. |
|
||||||
| REACT_APP_SHARETRIBE_USING_SSL | | false | Redirect HTTP to HTTPS. |
|
| REACT_APP_ENV | | production | Env for client side. Use the same value as with NODE_ENV. |
|
||||||
| SERVER_SHARETRIBE_TRUST_PROXY | | false | Set when running the app behind a reverse proxy. |
|
| REACT_APP_SHARETRIBE_USING_SSL | | false | Redirect HTTP to HTTPS? |
|
||||||
| REACT_APP_PUBLIC_SENTRY_DSN | | - | See: [Error logging with Sentry](./sentry.md) |
|
| SERVER_SHARETRIBE_TRUST_PROXY | | false | Set when running the app behind a reverse proxy, e.g. in Heroku. |
|
||||||
| SERVER_SENTRY_DSN | | - | See: [Error logging with Sentry](./sentry.md) |
|
| REACT_APP_PUBLIC_SENTRY_DSN | | - | See: [Error logging with Sentry](./sentry.md) |
|
||||||
| REACT_APP_CSP | | - | See: [Content Security Policy (CSP)](./content-security-policy.md) |
|
| SERVER_SENTRY_DSN | | - | See: [Error logging with Sentry](./sentry.md) |
|
||||||
| BASIC_AUTH_USERNAME | | - | Set to enable HTTP Basic Auth |
|
| REACT_APP_CSP | | - | See: [Content Security Policy (CSP)](./content-security-policy.md) |
|
||||||
| BASIC_AUTH_PASSWORD | | - | Set to enable HTTP Basic Auth |
|
| BASIC_AUTH_USERNAME | | - | Set to enable HTTP Basic Auth |
|
||||||
| REACT_APP_GOOGLE_ANALYTICS_ID | | - | See: [Google Analytics](./analytics.md) |
|
| BASIC_AUTH_PASSWORD | | - | Set to enable HTTP Basic Auth |
|
||||||
|
| REACT_APP_GOOGLE_ANALYTICS_ID | | - | See: [Google Analytics](./analytics.md) |
|
||||||
|
|
||||||
## Defining the env variables
|
## Defining the env variables
|
||||||
|
|
||||||
When the Starter App is started locally with `yarn run dev` you can set environment variables by
|
When the Starter App is started locally with `yarn run dev` or `yarn run dev-server`, you can set
|
||||||
using the file .env.development.local. However, the server process doesn't currently pick up values
|
environment variables by using the file .env file. The repository contains a template file
|
||||||
from this file. In production it is recommended to set the environment variables on OS level.
|
.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.
|
||||||
|
|
|
||||||
|
|
@ -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
|
## 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
|
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
|
local development, you can add the variable in the Gitignored `.env` file in the project root:
|
||||||
project root:
|
|
||||||
|
|
||||||
```
|
```
|
||||||
REACT_APP_GOOGLE_MAPS_API_KEY=my-key-here
|
REACT_APP_GOOGLE_MAPS_API_KEY=my-key-here
|
||||||
|
|
|
||||||
|
|
@ -66,7 +66,7 @@
|
||||||
"test-ci": "sharetribe-scripts test --env=jsdom --runInBand",
|
"test-ci": "sharetribe-scripts test --env=jsdom --runInBand",
|
||||||
"eject": "sharetribe-scripts eject",
|
"eject": "sharetribe-scripts eject",
|
||||||
"start": "node server/index.js",
|
"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-prebuild": "./heroku-copy-ssh-key-from-env.sh",
|
||||||
"heroku-postbuild": "yarn run build",
|
"heroku-postbuild": "yarn run build",
|
||||||
"audit": "nsp check --preprocessor yarn"
|
"audit": "nsp check --preprocessor yarn"
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,4 @@
|
||||||
const helmet = require('helmet');
|
const helmet = require('helmet');
|
||||||
const { config } = require('./importer');
|
|
||||||
|
|
||||||
const dev = process.env.REACT_APP_ENV === 'development';
|
const dev = process.env.REACT_APP_ENV === 'development';
|
||||||
const googleAnalyticsEnabled = !!process.env.REACT_APP_GOOGLE_ANALYTICS_ID;
|
const googleAnalyticsEnabled = !!process.env.REACT_APP_GOOGLE_ANALYTICS_ID;
|
||||||
|
|
@ -21,7 +20,7 @@ module.exports = (reportUri, enforceSsl, reportOnly) => {
|
||||||
const self = "'self'";
|
const self = "'self'";
|
||||||
const inline = "'unsafe-inline'";
|
const inline = "'unsafe-inline'";
|
||||||
const data = 'data:';
|
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 sharetribeAssets = 'https://assets-sharetribecom.sharetribe.com/';
|
||||||
const imgix = '*.imgix.net/';
|
const imgix = '*.imgix.net/';
|
||||||
const loremPixel = 'https://lorempixel.com/';
|
const loremPixel = 'https://lorempixel.com/';
|
||||||
|
|
|
||||||
41
server/env.js
Normal file
41
server/env.js
Normal 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,
|
||||||
|
};
|
||||||
|
|
@ -17,5 +17,4 @@ module.exports = {
|
||||||
matchPathname: mainJs.matchPathname,
|
matchPathname: mainJs.matchPathname,
|
||||||
configureStore: mainJs.configureStore,
|
configureStore: mainJs.configureStore,
|
||||||
routeConfiguration: mainJs.routeConfiguration,
|
routeConfiguration: mainJs.routeConfiguration,
|
||||||
config: mainJs.config,
|
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,9 @@
|
||||||
// This enables nice stacktraces from the minified production bundle
|
// This enables nice stacktraces from the minified production bundle
|
||||||
require('source-map-support').install();
|
require('source-map-support').install();
|
||||||
|
|
||||||
|
// Configure process.env with .env.* files
|
||||||
|
require('./env').configureEnv();
|
||||||
|
|
||||||
const express = require('express');
|
const express = require('express');
|
||||||
const helmet = require('helmet');
|
const helmet = require('helmet');
|
||||||
const compression = require('compression');
|
const compression = require('compression');
|
||||||
|
|
@ -35,12 +38,11 @@ const { sitemapStructure } = require('./sitemap');
|
||||||
const csp = require('./csp');
|
const csp = require('./csp');
|
||||||
|
|
||||||
const buildPath = path.resolve(__dirname, '..', 'build');
|
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 dev = process.env.REACT_APP_ENV === 'development';
|
||||||
const PORT = process.env.PORT || 4000;
|
const PORT = process.env.PORT;
|
||||||
const CLIENT_ID =
|
const CLIENT_ID = process.env.REACT_APP_SHARETRIBE_SDK_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;
|
||||||
const BASE_URL = process.env.REACT_APP_SHARETRIBE_SDK_BASE_URL || 'http://localhost:8088';
|
|
||||||
const USING_SSL = process.env.REACT_APP_SHARETRIBE_USING_SSL === 'true';
|
const USING_SSL = process.env.REACT_APP_SHARETRIBE_USING_SSL === 'true';
|
||||||
const TRUST_PROXY = process.env.SERVER_SHARETRIBE_TRUST_PROXY || null;
|
const TRUST_PROXY = process.env.SERVER_SHARETRIBE_TRUST_PROXY || null;
|
||||||
const CSP = process.env.REACT_APP_CSP;
|
const CSP = process.env.REACT_APP_CSP;
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,8 @@
|
||||||
const path = require('path');
|
const path = require('path');
|
||||||
const moment = require('moment');
|
const moment = require('moment');
|
||||||
const { config } = require('./importer');
|
|
||||||
|
|
||||||
const buildPath = path.resolve(__dirname, '..', 'build');
|
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';
|
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
|
* Return a structure for sitemap.xml and robots.txt to be used by the
|
||||||
* used by the express-sitemap library. Uses the canonical
|
* express-sitemap library. Uses the canonical URL value from env
|
||||||
* URL value from config for domain and port information.
|
* config for domain and port information.
|
||||||
*/
|
*/
|
||||||
exports.sitemapStructure = () => {
|
exports.sitemapStructure = () => {
|
||||||
const now = moment().format('YYYY-MM-DD');
|
const now = moment().format('YYYY-MM-DD');
|
||||||
|
|
||||||
return {
|
return {
|
||||||
url: domain(config.canonicalRootURL),
|
url: domain(process.env.REACT_APP_CANONICAL_ROOT_URL),
|
||||||
http: USING_SSL ? 'https' : 'http',
|
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'),
|
sitemap: path.join(buildPath, 'static', 'sitemap.xml'),
|
||||||
robots: path.join(buildPath, 'robots.txt'),
|
robots: path.join(buildPath, 'robots.txt'),
|
||||||
sitemapSubmission: '/static/sitemap.xml',
|
sitemapSubmission: '/static/sitemap.xml',
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
import * as custom from './marketplace-custom-config.js';
|
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';
|
const dev = process.env.REACT_APP_ENV === 'development';
|
||||||
|
|
||||||
// If you want to change the language, remember to also change the
|
// 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
|
// react-scripts) require using the REACT_APP_ prefix to avoid
|
||||||
// exposing server secrets to the client side.
|
// exposing server secrets to the client side.
|
||||||
const sdkClientId = process.env.REACT_APP_SHARETRIBE_SDK_CLIENT_ID;
|
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
|
// Sentry DSN (Data Source Name), a client key for authenticating calls to Sentry
|
||||||
const sentryDsn = process.env.REACT_APP_PUBLIC_SENTRY_DSN;
|
const sentryDsn = process.env.REACT_APP_PUBLIC_SENTRY_DSN;
|
||||||
|
|
@ -219,7 +219,7 @@ const postalCode = '00100';
|
||||||
const streetAddress = 'Bulevardi 14';
|
const streetAddress = 'Bulevardi 14';
|
||||||
|
|
||||||
// Canonical root url is needed in social media sharing and SEO optimization purposes.
|
// 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)
|
// Site title is needed in meta tags (bots and social media sharing reads those)
|
||||||
const siteTitle = 'Saunatime';
|
const siteTitle = 'Saunatime';
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue