From 518de43fd14d0adae5b37a5f17493c39ed14c30a Mon Sep 17 00:00:00 2001
From: Jonas Braathen <jonas.braathen@usit.uio.no>
Date: Tue, 7 Sep 2021 23:08:23 +0200
Subject: [PATCH] Add support for injecting configuration at runtime

---
 frontend/.env                 |  2 ++
 frontend/docker-entrypoint.sh |  7 +++++++
 frontend/package.json         |  5 +++--
 frontend/public/env.js        |  1 +
 frontend/scripts/build-env.js | 17 +++++++++++++++++
 frontend/src/App.tsx          | 20 +++++++++++++++-----
 frontend/src/appConfig.ts     | 22 ++++++++++++++++++++++
 7 files changed, 67 insertions(+), 7 deletions(-)
 create mode 100644 frontend/.env
 create mode 100644 frontend/docker-entrypoint.sh
 create mode 100644 frontend/public/env.js
 create mode 100644 frontend/scripts/build-env.js
 create mode 100644 frontend/src/appConfig.ts

diff --git a/frontend/.env b/frontend/.env
new file mode 100644
index 00000000..60a2d2a2
--- /dev/null
+++ b/frontend/.env
@@ -0,0 +1,2 @@
+REACT_APP_VERSION=$npm_package_version
+REACT_APP_NAME=$npm_package_name
diff --git a/frontend/docker-entrypoint.sh b/frontend/docker-entrypoint.sh
new file mode 100644
index 00000000..6160aaad
--- /dev/null
+++ b/frontend/docker-entrypoint.sh
@@ -0,0 +1,7 @@
+#!/usr/bin/env sh
+set -eu
+
+ENV_JSON=$(env | grep '^REACT_APP_*' | jq -c '. | split("\n") | map(select(. != "")) | map(split("=") | { (.[0]) : .[1] }) | reduce .[] as $item ({}; . * $item)' -R -s)
+echo "window.ENV = $ENV_JSON" > /app/build/env.js
+
+exec "$@"
diff --git a/frontend/package.json b/frontend/package.json
index ce69a4b7..dc174c30 100644
--- a/frontend/package.json
+++ b/frontend/package.json
@@ -17,8 +17,9 @@
     "web-vitals": "^1.1.2"
   },
   "scripts": {
-    "start": "react-scripts start",
-    "build": "react-scripts build",
+    "start": "NODE_ENV=development HOST=0.0.0.0 npm run build:env && react-scripts start",
+    "build": "npm run build:env && react-scripts build",
+    "build:env": "node scripts/build-env.js",
     "clean": "rm -rf node_modules",
     "test": "react-scripts test",
     "eject": "react-scripts eject"
diff --git a/frontend/public/env.js b/frontend/public/env.js
new file mode 100644
index 00000000..3b8657b1
--- /dev/null
+++ b/frontend/public/env.js
@@ -0,0 +1 @@
+window.ENV = {"NODE_ENV":"development","PUBLIC_URL":"","FAST_REFRESH":true,"REACT_APP_VERSION":"0.1.0","REACT_APP_NAME":"greg"}
\ No newline at end of file
diff --git a/frontend/scripts/build-env.js b/frontend/scripts/build-env.js
new file mode 100644
index 00000000..27a9429f
--- /dev/null
+++ b/frontend/scripts/build-env.js
@@ -0,0 +1,17 @@
+const dotenv = require("dotenv");
+dotenv.config();
+const fs = require("fs");
+const clientEnv = require("react-scripts/config/env.js")(
+  process.env.PUBLIC_URL || ""
+);
+
+const outFile = `./public/env.js`;
+const content = `window.ENV = ${JSON.stringify(clientEnv.raw)}`;
+
+try {
+  fs.writeFileSync(outFile, content, "utf8");
+  console.log("Wrote client environment to", outFile);
+} catch (err) {
+  console.error("Error while writing client environment file:", err.message);
+  process.exit(1);
+}
diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx
index a53698aa..de30797d 100644
--- a/frontend/src/App.tsx
+++ b/frontend/src/App.tsx
@@ -1,8 +1,10 @@
-import React from 'react';
-import logo from './logo.svg';
-import './App.css';
+import React from "react";
+import logo from "./logo.svg";
+import "./App.css";
 
-function App() {
+import { appTimezone, appVersion, appTheme } from "./appConfig";
+
+const App = () => {
   return (
     <div className="App">
       <header className="App-header">
@@ -18,9 +20,17 @@ function App() {
         >
           Learn React
         </a>
+        <p>
+          Version {appVersion}
+          <br />
+          Timezone {appTimezone}
+          <br />
+          Theme {appTheme}
+          <br />
+        </p>
       </header>
     </div>
   );
-}
+};
 
 export default App;
diff --git a/frontend/src/appConfig.ts b/frontend/src/appConfig.ts
new file mode 100644
index 00000000..4a5c9505
--- /dev/null
+++ b/frontend/src/appConfig.ts
@@ -0,0 +1,22 @@
+declare global {
+  /* tslint:disable */
+  interface Window {
+    ENV: any;
+  }
+}
+
+/* Locate the client environment */
+const isProduction = process.env.NODE_ENV === "production";
+const env = isProduction ? window.ENV : process.env;
+
+/* General settings */
+export const appTimezone: string = "Europe/Oslo";
+
+/* Version */
+export const appVersion: string = process.env.REACT_APP_VERSION as string;
+export const appName: string = process.env.REACT_APP_NAME as string;
+
+/* Theming */
+export const appTheme: string = env.REACT_APP_THEME
+  ? (env.REACT_APP_THEME as string)
+  : "default";
-- 
GitLab