Skip to content

Commit

Permalink
feat: add new runtime config and modify current runtime config (#5)
Browse files Browse the repository at this point in the history
* chore: add file to act as remote config

* feat: add environment runtime config

* chore: remove file
  • Loading branch information
kleyow authored Oct 7, 2021
1 parent 28cba0f commit cf8e156
Show file tree
Hide file tree
Showing 19 changed files with 152 additions and 46 deletions.
2 changes: 1 addition & 1 deletion .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,7 @@ jobs:
name: Build Docker local image
command: |
echo "Building Docker image: local"
docker build -t $DOCKER_ORG/$CIRCLE_PROJECT_REPONAME:local .
docker build -t $DOCKER_ORG/$CIRCLE_PROJECT_REPONAME:local . --build-arg REACT_APP_VERSION=`npm run version --silent` --build-arg REACT_APP_COMMIT=`git rev-parse HEAD` --build-arg PUBLIC_PATH=https://localhost:8080/
- run:
name: Save docker image to workspace
command: docker save -o /tmp/docker-image.tar $DOCKER_ORG/$CIRCLE_PROJECT_REPONAME:local
Expand Down
6 changes: 4 additions & 2 deletions .env
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
REACT_APP_API_BASE_URL=/api
REACT_APP_AUTH_ENABLED=true
REACT_APP_MOCK_API=true
REACT_APP_AUTH_API_BASE_URL=/api
REACT_APP_AUTH_MOCK_API=true
REACT_APP_REMOTE_API_BASE_URL=/remote
REACT_APP_REMOTE_MOCK_API=true
REMOTE_1_URL=http://localhost:3012
REMOTE_2_URL=http://localhost:3013
DEV_PORT=3010
Expand Down
33 changes: 20 additions & 13 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -20,15 +20,6 @@ ENV REACT_APP_COMMIT=$REACT_APP_COMMIT
ARG PUBLIC_PATH
ENV PUBLIC_PATH=$PUBLIC_PATH

# TODO: hard coding these for now since there is no api that
# handles the microfrontend remote locations
ARG REMOTE_1_URL
ENV REMOTE_1_URL=$REMOTE_1_URL

ARG REMOTE_2_URL
ENV REMOTE_2_URL=$REMOTE_2_URL


RUN yarn build

# Second part, create a config at boostrap via entrypoint and and serve it
Expand All @@ -41,13 +32,26 @@ COPY --from=0 dist/ .
COPY docker/Caddyfile /srv/Caddyfile
COPY docker/entrypoint.sh /entrypoint.sh
COPY docker/createJSONConfig.sh /createJSONConfig.sh
COPY docker/createRemoteConfig.sh /createRemoteConfig.sh
COPY docker/loadRuntimeConfig.sh /loadRuntimeConfig.sh

RUN chmod +x /entrypoint.sh
RUN chmod +x /createJSONConfig.sh
RUN chmod +x /createRemoteConfig.sh
RUN chmod +x /loadRuntimeConfig.sh

# Provide environment variables for setting endpoints dynamically
ARG API_BASE_URL
ENV API_BASE_URL=$API_BASE_URL
ARG REMOTE_API_BASE_URL
ENV REMOTE_API_BASE_URL=$REMOTE_API_BASE_URL

ARG REMOTE_MOCK_API
ENV REMOTE_MOCK_API=$REMOTE_MOCK_API

ARG AUTH_API_BASE_URL
ENV AUTH_API_BASE_URL=$AUTH_API_BASE_URL

ARG AUTH_MOCK_API
ENV AUTH_MOCK_API=$AUTH_MOCK_API

ARG AUTH_ENABLED
ENV AUTH_ENABLED=$AUTH_ENABLED
Expand All @@ -58,8 +62,11 @@ ENV LOGIN_URL=$LOGIN_URL
ARG LOGOUT_URL
ENV LOGOUT_URL=$LOGOUT_URL

ARG MOCK_API
ENV MOCK_API=$MOCK_API
ARG REMOTE_1_URL
ENV REMOTE_1_URL=$REMOTE_1_URL

ARG REMOTE_2_URL
ENV REMOTE_2_URL=$REMOTE_2_URL

EXPOSE 8080

Expand Down
10 changes: 6 additions & 4 deletions docker-compose.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,16 @@ services:
- mojaloop/reporting-hub-bop-shell
args:
- PUBLIC_PATH=https://localhost:8080/
- REMOTE_1_URL=https://localhost:8081
- REMOTE_2_URL=https://localhost:8082
environment:
- API_BASE_URL=/api
- AUTH_API_BASE_URL=/
- AUTH_MOCK_API=true
- REMOTE_API_BASE_URL=/
- REMOTE_MOCK_API=false
- LOGIN_URL=https://your-login-url
- LOGOUT_URL=https://your-logout-url
- AUTH_ENABLED=true
- MOCK_API=true
- REMOTE_1_URL=https://localhost:8081
- REMOTE_2_URL=https://localhost:8082
ports:
- "8080:8080"
networks:
Expand Down
10 changes: 6 additions & 4 deletions docker/createJSONConfig.sh
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,14 @@

# Creates the JSON config based on environment variables
echo "{
\"API_BASE_URL\": \"${API_BASE_URL}\",
\"AUTH_API_BASE_URL\": \"${AUTH_API_BASE_URL}\",
\"AUTH_MOCK_API\": \"${AUTH_MOCK_API}\",
\"REMOTE_API_BASE_URL\": \"${REMOTE_API_BASE_URL}\",
\"REMOTE_MOCK_API\": \"${REMOTE_MOCK_API}\",
\"AUTH_ENABLED\": \"${AUTH_ENABLED}\",
\"LOGIN_URL\": \"${LOGIN_URL}\",
\"LOGOUT_URL\": \"${LOGOUT_URL}\",
\"MOCK_API\": \"${MOCK_API}\"
\"LOGOUT_URL\": \"${LOGOUT_URL}\"
}" | jq '.' > config.json

# This will exec the CMD from your Dockerfile, i.e. "npm start"
exec "$@"
exec "$@"
24 changes: 24 additions & 0 deletions docker/createRemoteConfig.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
#!/bin/sh

# Creates the Remotes config based on environment variables
echo "[
{
\"path\": \"/iam\",
\"label\": \"Roles Microfrontend\",
\"menuComponent\": \"Menu\",
\"appComponent\": \"App\",
\"url\": \"${REMOTE_1_URL}/app.js\",
\"appName\": \"reporting_hub_bop_role_ui\"
},
{
\"path\": \"/transfers\",
\"label\": \"Transfers Microfrontend\",
\"menuComponent\": \"Menu\",
\"appComponent\": \"App\",
\"url\": \"${REMOTE_2_URL}/app.js\",
\"appName\": \"reporting_hub_bop_trx_ui\"
}
]" | jq '.' > remotes.json

# This will exec the CMD from your Dockerfile, i.e. "npm start"
exec "$@"
4 changes: 3 additions & 1 deletion docker/entrypoint.sh
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

# Run the script before starting the server
sh /createJSONConfig.sh
sh /createRemoteConfig.sh
sh /loadRuntimeConfig.sh

# This will exec the CMD from your Dockerfile, i.e. "npm start"
exec "$@"
exec "$@"
5 changes: 5 additions & 0 deletions docker/loadRuntimeConfig.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
#!/bin/bash
sed -i 's#__REMOTE_1_URL__#'"$REMOTE_1_URL"'#g' runtime-env.js
sed -i 's#__REMOTE_1_URL__#'"$REMOTE_1_URL"'#g' index.html

exec "$@"
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@
"bootstrap-icons": "^1.5.0",
"classnames": "^2.2.6",
"connected-react-router": "^6.8.0",
"copy-webpack-plugin": "^9.0.1",
"css-loader": "4.2.1",
"dotenv": "^10.0.0",
"dotenv-webpack": "^7.0.3",
Expand Down
2 changes: 2 additions & 0 deletions public/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
<head>
<link href="https://fonts.googleapis.com/css?family=Fira+Sans:400,700" rel="stylesheet">
<link href="https://fonts.googleapis.com/css?family=Ubuntu:400,700" rel="stylesheet">
<script src="/runtime-env.js"></script>
<script src="__REMOTE_1_URL__/runtime-env.js"></script>
</head>
<body>
<div id="root" />
Expand Down
5 changes: 5 additions & 0 deletions public/runtime-env.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
// public/env.js
// https://medium.com/@hasniarif/how-to-handle-runtime-environment-variables-with-react-ec809cb07831
window.env = {
REMOTE_1_URL: '__REMOTE_1_URL__',
};
1 change: 0 additions & 1 deletion src/App/sagas.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import { actions } from './slice';
function* requestRemotes() {
try {
const { status, data } = yield call(apis.remotes.read, {});

if (is200(status)) {
yield put(actions.requestRemotesSuccess(data));
} else {
Expand Down
34 changes: 25 additions & 9 deletions src/Config/build.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,30 +8,46 @@ export default async (): Promise<AppConfig & AuthConfig & ApiConfig> => {
loginEndpoint: `${baseUrl}/auth/auth/login`,
logoutEndpoint: `${baseUrl}/kratos/self-service/browser/flows/logout`,
tokenEndpoint: `${baseUrl}/kratos/sessions/whoami`,
apiBaseUrl: `${process.env.REACT_APP_API_BASE_URL}`,
isAuthEnabled: process.env.REACT_APP_AUTH_ENABLED !== 'false',
basename: baseUrl,
mockApi: process.env.REACT_APP_MOCK_API === 'true',
authApiBaseUrl: `${process.env.REACT_APP_AUTH_API_BASE_URL}`,
authMockApi: process.env.REACT_APP_AUTH_MOCK_API === 'true',
remoteApiBaseUrl: `${process.env.REACT_APP_REMOTE_API_BASE_URL}`,
remoteMockApi: process.env.REACT_APP_REMOTE_MOCK_API === 'true',
};

const config = { ...defaults };

try {
const { API_BASE_URL, AUTH_ENABLED, LOGIN_URL, LOGOUT_URL, MOCK_API } = await fetch(
`${baseUrl}/config.json`,
).then((response) => response.json());
const {
AUTH_API_BASE_URL,
AUTH_MOCK_API,
REMOTE_API_BASE_URL,
REMOTE_MOCK_API,
AUTH_ENABLED,
LOGIN_URL,
LOGOUT_URL,
} = await fetch(`${baseUrl}/config.json`).then((response) => response.json());

if (LOGIN_URL !== undefined) {
config.loginEndpoint = LOGIN_URL;
}
if (LOGOUT_URL !== undefined) {
config.logoutEndpoint = LOGOUT_URL;
}
if (API_BASE_URL !== undefined) {
config.apiBaseUrl = API_BASE_URL;
if (AUTH_API_BASE_URL !== undefined) {
config.authApiBaseUrl = AUTH_API_BASE_URL;
}
if (MOCK_API !== undefined) {
config.mockApi = MOCK_API === 'true';
if (AUTH_MOCK_API !== undefined) {
config.authMockApi = AUTH_MOCK_API === 'true';
}
if (REMOTE_API_BASE_URL !== undefined) {
// NOTE: instead of an actual api, using local json file to store
// remote microfrontend config
config.remoteApiBaseUrl = baseUrl;
}
if (REMOTE_MOCK_API !== undefined) {
config.remoteMockApi = REMOTE_MOCK_API === 'true';
}
if (AUTH_ENABLED !== undefined) {
config.isAuthEnabled = AUTH_ENABLED !== 'false';
Expand Down
6 changes: 4 additions & 2 deletions src/Config/slice.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,10 @@ export const initialState: ConfigState = {
basename: '',
},
api: {
apiBaseUrl: '',
mockApi: false,
authApiBaseUrl: '',
authMockApi: false,
remoteApiBaseUrl: '',
remoteMockApi: false,
},
auth: {
tokenEndpoint: '',
Expand Down
6 changes: 4 additions & 2 deletions src/Config/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,10 @@ export type AppConfig = {
};

export type ApiConfig = {
apiBaseUrl: string;
mockApi: boolean;
authApiBaseUrl: string;
authMockApi: boolean;
remoteApiBaseUrl: string;
remoteMockApi: boolean;
};

export interface AuthConfig {
Expand Down
6 changes: 4 additions & 2 deletions src/bootstrap.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,10 @@ async function boot() {
basename: config.basename,
},
api: {
apiBaseUrl: config.apiBaseUrl,
mockApi: config.mockApi,
authApiBaseUrl: config.authApiBaseUrl,
authMockApi: config.authMockApi,
remoteApiBaseUrl: config.remoteApiBaseUrl,
remoteMockApi: config.remoteMockApi,
},
auth: {
loginEndpoint: config.loginEndpoint,
Expand Down
12 changes: 7 additions & 5 deletions src/utils/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,12 @@ import buildApis, { buildEndpointBuilder } from '@modusbox/redux-utils/lib/api';

const services = {
kratos: {
baseUrl: '',
mock: (state: State) => state.config.api.mockApi,
baseUrl: (state: State) => state.config.api.authApiBaseUrl,
mock: (state: State) => state.config.api.authMockApi,
},
mainApi: {
baseUrl: (state: State) => state.config.api.apiBaseUrl,
mock: (state: State) => state.config.api.mockApi,
baseUrl: (state: State) => state.config.api.remoteApiBaseUrl,
mock: (state: State) => state.config.api.remoteMockApi,
},
};

Expand All @@ -22,9 +22,11 @@ export default buildApis({
url: (state: State) => state.config.auth.tokenEndpoint,
mock: authMock,
}),
// NOTE: instead of an actual api, using local json file to store
// remote microfrontend config
remotes: builder({
service: services.mainApi,
url: '/remotes',
url: '/remotes.json',
mock: remotesMock,
}),
});
4 changes: 4 additions & 0 deletions webpack.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ const ForkTsCheckerWebpackPlugin = require('fork-ts-checker-webpack-plugin');
const { ModuleFederationPlugin } = require('webpack').container;
const DotenvPlugin = require('dotenv-webpack');
const path = require('path');
const CopyPlugin = require('copy-webpack-plugin');

require('dotenv').config({
path: './.env',
Expand Down Expand Up @@ -121,6 +122,9 @@ module.exports = {
],
},
plugins: [
new CopyPlugin({
patterns: [{ from: 'public/runtime-env.js', to: 'runtime-env.js' }],
}),
new EslintWebpackPlugin({
extensions: ['ts', 'js', 'tsx', 'jsx'],
exclude: [`/node_modules/`],
Expand Down
27 changes: 27 additions & 0 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -3688,6 +3688,19 @@ copy-descriptor@^0.1.0:
resolved "https://registry.yarnpkg.com/copy-descriptor/-/copy-descriptor-0.1.1.tgz#676f6eb3c39997c2ee1ac3a924fd6124748f578d"
integrity sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=

copy-webpack-plugin@^9.0.1:
version "9.0.1"
resolved "https://registry.yarnpkg.com/copy-webpack-plugin/-/copy-webpack-plugin-9.0.1.tgz#b71d21991599f61a4ee00ba79087b8ba279bbb59"
integrity sha512-14gHKKdYIxF84jCEgPgYXCPpldbwpxxLbCmA7LReY7gvbaT555DgeBWBgBZM116tv/fO6RRJrsivBqRyRlukhw==
dependencies:
fast-glob "^3.2.5"
glob-parent "^6.0.0"
globby "^11.0.3"
normalize-path "^3.0.0"
p-limit "^3.1.0"
schema-utils "^3.0.0"
serialize-javascript "^6.0.0"

core-js-compat@^3.14.0, core-js-compat@^3.16.0:
version "3.17.2"
resolved "https://registry.yarnpkg.com/core-js-compat/-/core-js-compat-3.17.2.tgz#f461ab950c0a0ffedfc327debf28b7e518950936"
Expand Down Expand Up @@ -5517,6 +5530,13 @@ glob-parent@^5.0.0, glob-parent@^5.1.2, glob-parent@~5.1.2:
dependencies:
is-glob "^4.0.1"

glob-parent@^6.0.0:
version "6.0.2"
resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-6.0.2.tgz#6d237d99083950c79290f24c7642a3de9a28f9e3"
integrity sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==
dependencies:
is-glob "^4.0.3"

glob-to-regexp@^0.4.1:
version "0.4.1"
resolved "https://registry.yarnpkg.com/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz#c75297087c851b9a578bd217dd59a92f59fe546e"
Expand Down Expand Up @@ -6315,6 +6335,13 @@ is-glob@^4.0.1, is-glob@~4.0.1:
dependencies:
is-extglob "^2.1.1"

is-glob@^4.0.3:
version "4.0.3"
resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.3.tgz#64f61e42cbbb2eec2071a9dac0b28ba1e65d5084"
integrity sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==
dependencies:
is-extglob "^2.1.1"

is-hexadecimal@^1.0.0:
version "1.0.4"
resolved "https://registry.yarnpkg.com/is-hexadecimal/-/is-hexadecimal-1.0.4.tgz#cc35c97588da4bd49a8eedd6bc4082d44dcb23a7"
Expand Down

0 comments on commit cf8e156

Please sign in to comment.