Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Config from server #899

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 1 addition & 13 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -20,19 +20,7 @@ ARG mdb_rest_api_url

WORKDIR /app

ENV REACT_APP_ENV=production \
REACT_APP_API_BACKEND=/backend/ \
REACT_APP_ASSETS_BACKEND=/assets/ \
REACT_APP_IMAGINARY_URL=/imaginary/ \
REACT_APP_IMAGINARY_INTERNAL_HOST=nginx \
REACT_APP_LOCALES_BACKEND=/ \
REACT_APP_CDN_URL=${cdn_url} \
REACT_APP_PUBLIC_BASE=${public_base} \
REACT_APP_FEED=${feed_api_url} \
REACT_APP_PERSONAL_API_BACKEND=${personal_api_url} \
REACT_APP_CHRONICLES_BACKEND=${chronicles_url} \
REACT_APP_FILE_TRIMMER_API=${file_trimmer_api_url} \
REACT_APP_MDB_REST_API_URL=${mdb_rest_api_url}
ENV REACT_APP_ENV=production

COPY . .

Expand Down
17 changes: 17 additions & 0 deletions server/renderer.js
Original file line number Diff line number Diff line change
Expand Up @@ -223,10 +223,27 @@ export default function serverRender(req, res, next, htmlData) {
}
);

const appConfig = serialize({
'node_env': 'production',
'public_base': process.env.REACT_APP_PUBLIC_BASE,
'cdn_url': process.env.REACT_APP_CDN_URL,
'api_backend': '/backend/',
'cms_backend': '/backend/cms/',
'assets_backend': '/assets/',
'imaginary_url': '/imaginary/',
'imaginary_internal_host': process.env.REACT_APP_IMAGINARY_INTERNAL_HOST,
'api_feed': process.env.REACT_APP_FEED,
'personal_api_backend': process.env.REACT_APP_PERSONAL_API_BACKEND,
'chronicles_backend': process.env.REACT_APP_CHRONICLES_BACKEND,
'file_trimmer_api': process.env.REACT_APP_FILE_TRIMMER_API,
'mdb_rest_api_url': process.env.REACT_APP_MDB_REST_API_URL,
})

const rootDiv = `<div id="root" class="${direction}" style="direction: ${direction}">${markup}</div>
<script>
window.__data = ${storeData};
window.__i18n = ${i18nData};
window.__config = ${appConfig};
</script>`;

const html = htmlData
Expand Down
10 changes: 5 additions & 5 deletions src/components/shared/FallbackImage.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ import React, { useState, useEffect } from 'react';
import PropTypes from 'prop-types';
import { Image } from 'semantic-ui-react';

import config from '../../helpers/config';
import { knownFallbackImages, NoneFallbackImage, SectionThumbnailFallback } from '../../helpers/images';
import { IMAGINARY_URL } from '../../helpers/Api';

// An adaptation of https://github.com/socialtables/react-image-fallback
// for react semantic-ui
Expand Down Expand Up @@ -31,14 +31,14 @@ const buildImage = (src, fallbacks, onError, onLoad) => {
};

const handleLoaded = image => {
if (image.includes(IMAGINARY_URL))
if (image.includes(config.imaginaryApi()))
imaginaryCalls--;

onLoad(image);
};

const handleError = () => {
if (displayImage.src.includes(IMAGINARY_URL))
if (displayImage.src.includes(config.imaginaryApi()))
imaginaryCalls--;

if (typeof fallbacks[0] === 'string') {
Expand Down Expand Up @@ -67,13 +67,13 @@ const buildImage = (src, fallbacks, onError, onLoad) => {
return;
}

if (image.includes(IMAGINARY_URL) && imaginaryCalls >= MAX_IMAGINARY_CALLS) {
if (image.includes(config.imaginaryApi()) && imaginaryCalls >= MAX_IMAGINARY_CALLS) {
setTimeout(() => setDisplayImage(image, fallbacks), 300);
return;
}

if (typeof image === 'string') {
if (image.includes(IMAGINARY_URL)) imaginaryCalls++;
if (image.includes(config.imaginaryApi())) imaginaryCalls++;
displayImage.src = image;
} else {
onLoad(image);
Expand Down
44 changes: 18 additions & 26 deletions src/helpers/Api.js
Original file line number Diff line number Diff line change
@@ -1,24 +1,15 @@
import axios from 'axios';

import config from './config';
import { MY_NAMESPACE_LABELS, MY_NAMESPACE_PLAYLIST_EDIT, MY_NAMESPACE_PLAYLISTS } from './consts';

const API_BACKEND = process.env.REACT_APP_API_BACKEND;
const ASSETS_BACKEND = process.env.REACT_APP_ASSETS_BACKEND;
const CMS_BACKEND = process.env.REACT_APP_CMS_BACKEND || `${API_BACKEND}cms/`;
export const IMAGINARY_URL = process.env.REACT_APP_IMAGINARY_URL;
const IMAGINARY_INTERNAL_HOST = process.env.REACT_APP_IMAGINARY_INTERNAL_HOST || 'localhost';
const API_FEED = process.env.REACT_APP_FEED;
const CHRONICLES_BACKEND = process.env.REACT_APP_CHRONICLES_BACKEND;
const PERSONAL_API_BACKEND = process.env.REACT_APP_PERSONAL_API_BACKEND;
const FILE_TRIMMER_API = process.env.REACT_APP_FILE_TRIMMER_API;
const MDB_REST_API_URL = process.env.REACT_APP_MDB_REST_API_URL || `${API_BACKEND}mdb-api/`;

export const backendUrl = path => `${API_BACKEND}${path}`;
export const assetUrl = path => `${ASSETS_BACKEND}${path}`;
export const cmsUrl = path => `${CMS_BACKEND}${path}`;
export const imaginaryUrl = path => `${IMAGINARY_URL}${path}`;
export const feedUrl = path => `${API_FEED}${path}`;
export const chroniclesUrl = path => `${CHRONICLES_BACKEND}${path}`;
export const chroniclesBackendEnabled = CHRONICLES_BACKEND !== undefined;
export const backendUrl = path => `${config.backendApi()}${path}`;
export const assetUrl = path => `${config.assetsApi()}${path}`;
export const cmsUrl = path => `${config.cmsApi()}${path}`;
export const feedUrl = path => `${config.feedApi()}${path}`;
export const personalUrl = path => `${config.personalApi()}${path}`;
export const fileTrimmerUrl = path => `${config.fileTrimmerApi()}${path}`;
export const mdbRestUrl = path => `${config.mdbRestApi()}${path}`;

export class Requests {
static get = path => axios(backendUrl(path));
Expand Down Expand Up @@ -78,10 +69,10 @@ export class Requests {

static imaginary = (action, params) => {
if (!params.url.startsWith('http')) {
params.url = `http://${IMAGINARY_INTERNAL_HOST}${params.url}`;
params.url = `http://${config.imaginaryInternalHost()}${params.url}`;
}

return `${imaginaryUrl('thumbnail')}?${Requests.makeParams(params)}`;
return `${config.imaginaryApi()}thumbnail?${Requests.makeParams(params)}`;
};

static encode = encodeURIComponent;
Expand Down Expand Up @@ -225,8 +216,9 @@ class Api {

static my = (namespace, params, token, method = 'GET') => {
let urlParam = namespace;
if (namespace === MY_NAMESPACE_PLAYLIST_EDIT)
if (namespace === MY_NAMESPACE_PLAYLIST_EDIT) {
urlParam = MY_NAMESPACE_PLAYLISTS;
}

if (params.id) {
urlParam = `${urlParam}/${params.id}`;
Expand Down Expand Up @@ -258,26 +250,26 @@ class Api {
isNotREST = true;
}

const url = `${PERSONAL_API_BACKEND}${isNotREST ? '' : 'rest/'}${urlParam}`;
const url = `${personalUrl(isNotREST ? '' : 'rest/')}${urlParam}`;
return Requests.auth(params, url, token, method);
};

static reactionsCount = params => {
const url = `${PERSONAL_API_BACKEND}reaction_count?${Requests.makeParams(params)}`;
const url = `${personalUrl('reaction_count')}?${Requests.makeParams(params)}`;
const config = { url, method: 'GET' };
return axios(config);
};

static trimFile = params => {
const url = `${FILE_TRIMMER_API}?${Requests.makeParams(params)}`;
const url = `${fileTrimmerUrl('')}?${Requests.makeParams(params)}`;
const config = { url, method: 'GET' };
return axios(config);
};

static mdbCreateLabel = (params, token) => {
const url = `${MDB_REST_API_URL}labels/`;
const url = mdbRestUrl('labels/');
const headers = { 'Content-Type': 'application/json', 'Authorization': `bearer ${token}` };
const config = { url, headers, method: 'POST', data: JSON.stringify(params) };
const config = { url, headers, method: 'POST', data: JSON.stringify(params) };
return axios(config);
};
}
Expand Down
10 changes: 6 additions & 4 deletions src/helpers/clientChronicles.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,15 @@ import { useContext, useEffect } from 'react';
import { useSelector } from 'react-redux';
import axios from 'axios';
import { ulid } from 'ulid';
import { chroniclesUrl, chroniclesBackendEnabled } from './Api';
import { noop, partialAssign } from './utils';

import { actions } from '../redux/modules/chronicles';
import { selectors as settings } from '../redux/modules/settings';
import { types as recommendedTypes } from '../redux/modules/recommended';
import { types as searchTypes } from '../redux/modules/search';
import { types as authTypes } from '../redux/modules/auth';
import { ClientChroniclesContext } from './app-contexts';
import config from './config';
import { noop, partialAssign } from './utils';

// An array of DOM events that should be interpreted as user activity.
const ACTIVITY_EVENTS = ['mousedown', 'mousemove', 'keydown', 'scroll', 'touchstart'];
Expand Down Expand Up @@ -45,10 +45,12 @@ const SUBFLOWS = new Map(Object.entries(FLOWS.reduce((acc, flow) => {
const MAX_INACTIVITY_MS = 60 * 1000; // Minute in milliseconds.
const APPENDS_FLUSH_MS = 60 * 1000; // Minute in milliseconds.

const chroniclesUrl = path => `${config.chroniclesApi()}${path}`;

export default class ClientChronicles {
constructor(history, store) {
// If chronicles backend not defined in env.
if (!chroniclesBackendEnabled) {
if (!config.chroniclesEnabled()) {
this.append = noop;
return;
}
Expand Down Expand Up @@ -143,7 +145,7 @@ export default class ClientChronicles {
}

setAbTesting(abTesting) {
if (!chroniclesBackendEnabled) {
if (!config.chroniclesEnabled()) {
return;
}

Expand Down
54 changes: 54 additions & 0 deletions src/helpers/config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
class AppConfig {

constructor() {
this.kvmap = {};
}

cdnBase = () => this.kvmap['cdn_url'];
publicBase = () => this.kvmap['public_base'];
backendApi = () => this.kvmap['api_backend'];
assetsApi = () => this.kvmap['assets_backend'];
cmsApi = () => this.kvmap['cms_backend'];
imaginaryApi = () => this.kvmap['imaginary_url'];
imaginaryInternalHost = () => this.kvmap['imaginary_internal_host'];
feedApi = () => this.kvmap['api_feed'];
chroniclesApi = () => this.kvmap['chronicles_backend'];
personalApi = () => this.kvmap['personal_api_backend'];
fileTrimmerApi = () => this.kvmap['file_trimmer_api'];
mdbRestApi = () => this.kvmap['mdb_rest_api_url'];

chroniclesEnabled = () => this.chroniclesApi() !== undefined;
isProductionBuild = () => this.kvmap['node_env'] === 'production';
isBrowser = () => this.kvmap['is_browser'];

load = kv => {
this.kvmap = {
...kv,
...this.fromEnv(),
'is_browser': (typeof window !== 'undefined' && window.document),
};
};

// in local dev environments this is populated by react-scripts from .env files (or env vars)
fromEnv = () => ({
'cdn_url': process.env.REACT_APP_CDN_URL,
'public_base': process.env.REACT_APP_PUBLIC_BASE,
'api_backend': process.env.REACT_APP_API_BACKEND,
'assets_backend': process.env.REACT_APP_ASSETS_BACKEND,
'cms_backend': process.env.REACT_APP_CMS_BACKEND || `${process.env.REACT_APP_API_BACKEND}cms/`,
'imaginary_url': process.env.REACT_APP_IMAGINARY_URL,
'imaginary_internal_host': process.env.REACT_APP_IMAGINARY_INTERNAL_HOST || 'localhost',
'api_feed': process.env.REACT_APP_FEED,
'chronicles_backend': process.env.REACT_APP_CHRONICLES_BACKEND,
'personal_api_backend': process.env.REACT_APP_PERSONAL_API_BACKEND,
'file_trimmer_api': process.env.REACT_APP_FILE_TRIMMER_API,
'mdb_rest_api_url': process.env.REACT_APP_MDB_REST_API_URL || `${process.env.REACT_APP_API_BACKEND}mdb-api/`,
'node_env': process.env.NODE_ENV
});

dump = () => {
console.log('AppConfig', this.kvmap);
};
}

export default new AppConfig();
4 changes: 1 addition & 3 deletions src/helpers/i18nnext.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,6 @@ import 'moment/locale/cs';

import { DEFAULT_LANGUAGE } from './consts';

const LOCALES_BACKEND = process.env.REACT_APP_LOCALES_BACKEND;

export const options = {
load: 'languageOnly',
fallbackLng: DEFAULT_LANGUAGE,
Expand All @@ -39,7 +37,7 @@ i18n
.init({
...options,
backend: {
loadPath: `${LOCALES_BACKEND}locales/{{lng}}/{{ns}}.json`,
loadPath: '/locales/{{lng}}/{{ns}}.json',
crossDomain: true
},

Expand Down
Loading