{"id":2470,"date":"2022-12-07T14:22:47","date_gmt":"2022-12-07T14:22:47","guid":{"rendered":"https:\/\/jan.schnasse.org\/blog\/?p=2470"},"modified":"2026-09-28T11:37:30","modified_gmt":"2026-09-28T09:37:30","slug":"accessing-container-environment-at-startup-time-with-typescript-react-docker","status":"publish","type":"post","link":"https:\/\/jan.schnasse.org\/blog\/2022\/12\/07\/accessing-container-environment-at-startup-time-with-typescript-react-docker\/","title":{"rendered":"Accessing container environment at startup time with typescript \/ react \/ docker"},"content":{"rendered":"<p>Blogpost for this stackoverflow answer: <a href=\"https:\/\/stackoverflow.com\/a\/74701083\/1485527\">https:\/\/stackoverflow.com\/a\/74701083\/1485527<\/a><\/p>\n<p>Get code <a href=\"https:\/\/github.com\/jschnasse\/read-env-example\">here<\/a><\/p>\n<p><strong>Create example app<\/strong><\/p>\n<pre><code><span class=\"hljs-string\">npx <\/span><span class=\"hljs-built_in\">create-react-app<\/span> <span class=\"hljs-string\">read-env-<\/span><span class=\"hljs-string\">example <\/span><span class=\"hljs-built_in\">--template<\/span> <span class=\"hljs-string\">typescript<\/span>\n<\/code><\/pre>\n<p><strong>Navigate to fresh app<\/strong><\/p>\n<pre><code><span class=\"hljs-built_in\">cd<\/span> <span class=\"hljs-built_in\">read<\/span>-env-example\n<\/code><\/pre>\n<p><strong>Create Dockerfile<\/strong><\/p>\n<pre><code>mkdir -<span class=\"hljs-selector-tag\">p<\/span> docker\/build\n<\/code><\/pre>\n<p><em>docker\/build\/Dockerfile<\/em><\/p>\n<pre><code><span class=\"hljs-comment\"># build environment<\/span>\n<span class=\"hljs-keyword\">FROM<\/span> node:<span class=\"hljs-number\">19<\/span>-alpine3.<span class=\"hljs-number\">15<\/span> as builder\n<span class=\"hljs-keyword\">WORKDIR<\/span><span class=\"bash\"> \/app\n<\/span><span class=\"hljs-keyword\">ENV<\/span> PATH \/app\/node_modules\/.bin:$PATH\n\n<span class=\"hljs-keyword\">COPY<\/span><span class=\"bash\"> package.json .\/\n<\/span><span class=\"hljs-keyword\">COPY<\/span><span class=\"bash\"> package-lock.json .\/\n<\/span><span class=\"hljs-keyword\">RUN<\/span><span class=\"bash\"> npm ci\n<\/span><span class=\"hljs-keyword\">RUN<\/span><span class=\"bash\"> npm install react-scripts@5.0.1 -g\n<\/span><span class=\"hljs-keyword\">COPY<\/span><span class=\"bash\"> . .\/\n<\/span><span class=\"hljs-keyword\">RUN<\/span><span class=\"bash\"> PUBLIC_URL=<span class=\"hljs-string\">\".\"<\/span> npm run build\n<\/span>\n<span class=\"hljs-comment\"># production environment<\/span>\n<span class=\"hljs-keyword\">FROM<\/span> nginx:stable-alpine\n<span class=\"hljs-keyword\">COPY<\/span><span class=\"bash\"> --from=builder \/app\/build \/usr\/share\/nginx\/html\n<\/span><span class=\"hljs-keyword\">EXPOSE<\/span> <span class=\"hljs-number\">80<\/span>\n<span class=\"hljs-keyword\">CMD<\/span><span class=\"bash\"> [<span class=\"hljs-string\">\"nginx\"<\/span>, <span class=\"hljs-string\">\"-g\"<\/span>, <span class=\"hljs-string\">\"daemon off;\"<\/span>]\n<\/span>\n<span class=\"hljs-keyword\">COPY<\/span><span class=\"bash\"> docker\/build\/docker-entrypoint.sh \/\n<\/span><span class=\"hljs-keyword\">RUN<\/span><span class=\"bash\"> chmod +x docker-entrypoint.sh\n<\/span>\n<span class=\"hljs-keyword\">ENTRYPOINT<\/span><span class=\"bash\"> [<span class=\"hljs-string\">\"\/docker-entrypoint.sh\"<\/span>]<\/span>\n<\/code><\/pre>\n<p><strong>Create docker-entrypoint.sh<\/strong><\/p>\n<p>This script will be executed at container start.<br \/>\nIt generates the <code>config.js<\/code> file containing all environment variables starting with &#8218;MYAPP&#8216; under <code>window.extended<\/code>.<\/p>\n<p><em>docker\/build\/docker-entrypoint.sh<\/em><\/p>\n<pre><code><span class=\"hljs-comment\">#!\/bin\/sh -eu<\/span>\n\n\n<span class=\"hljs-keyword\">function<\/span> <span class=\"hljs-function\"><span class=\"hljs-title\">generateConfigJs<\/span><\/span>(){\n    <span class=\"hljs-built_in\">echo<\/span> <span class=\"hljs-string\">\"\/*&lt;![CDATA[*\/\"<\/span>;\n    <span class=\"hljs-built_in\">echo<\/span> <span class=\"hljs-string\">\"window.extended = window.extended || {};\"<\/span>;\n    <span class=\"hljs-keyword\">for<\/span> i <span class=\"hljs-keyword\">in<\/span> `env | grep <span class=\"hljs-string\">'^MYAPP'<\/span>`\n    <span class=\"hljs-keyword\">do<\/span>\n        key=$(<span class=\"hljs-built_in\">echo<\/span> <span class=\"hljs-string\">\"<span class=\"hljs-variable\">$i<\/span>\"<\/span> | cut <span class=\"hljs-_\">-d<\/span><span class=\"hljs-string\">\"=\"<\/span> <span class=\"hljs-_\">-f<\/span>1);\n        val=$(<span class=\"hljs-built_in\">echo<\/span> <span class=\"hljs-string\">\"<span class=\"hljs-variable\">$i<\/span>\"<\/span> | cut <span class=\"hljs-_\">-d<\/span><span class=\"hljs-string\">\"=\"<\/span> <span class=\"hljs-_\">-f<\/span>2);\n        <span class=\"hljs-built_in\">echo<\/span> <span class=\"hljs-string\">\"window.extended.<span class=\"hljs-variable\">${key}<\/span>='<span class=\"hljs-variable\">${val}<\/span>' ;\"<\/span>;\n    <span class=\"hljs-keyword\">done<\/span>\n    <span class=\"hljs-built_in\">echo<\/span> <span class=\"hljs-string\">\"\/*]]&gt;*\/\"<\/span>;\n}\ngenerateConfigJs &gt; \/usr\/share\/nginx\/html\/config.js\n\nnginx -g <span class=\"hljs-string\">\"daemon off;\"<\/span>\n<\/code><\/pre>\n<p><strong>Create docker-compose.yml<\/strong><\/p>\n<pre><code><span class=\"hljs-built_in\">mkdir<\/span> docker\/<span class=\"hljs-built_in\">run<\/span>\n<\/code><\/pre>\n<p><em>docker\/run\/docker-compose.yml<\/em><\/p>\n<pre><code><span class=\"hljs-attribute\">version<\/span>: <span class=\"hljs-string\">\"3.2\"<\/span>\n<span class=\"hljs-attribute\">services<\/span>:\n\n  <span class=\"hljs-attribute\">read-env-example<\/span>:\n    <span class=\"hljs-attribute\">image<\/span>: <span class=\"hljs-attribute\">read-env-example<\/span>:<span class=\"hljs-number\">0.1<\/span>.<span class=\"hljs-number\">0<\/span>\n    <span class=\"hljs-attribute\">ports<\/span>:\n      - <span class=\"hljs-number\">80<\/span>:<span class=\"hljs-number\">80<\/span>\n    <span class=\"hljs-attribute\">env_file<\/span>:\n      - myapp.env\n<\/code><\/pre>\n<p><strong>Create runtime config for your app<\/strong><\/p>\n<p><em>docker\/run\/myapp.env<\/em><\/p>\n<pre><code><span class=\"hljs-attr\">MYAPP_API_ENDPOINT<\/span>=<span class=\"hljs-string\">'http:\/\/elasticsearch:9200'<\/span>\n<\/code><\/pre>\n<p><strong>Create config.js<\/strong> &lt;&#8211; this is where .env will be injected.<\/p>\n<p><em>public\/config.js<\/em><\/p>\n<pre><code><span class=\"xml\">\/*&lt;![CDATA[*\/\nwindow.extended = window.extended || <\/span><span class=\"hljs-template-variable\">{}<\/span><span class=\"xml\">;\nwindow.extended.MYAPP_API_ENDPOINT='http:\/\/localhost:9200';\n\/*]]&gt;*\/<\/span>\n<\/code><\/pre>\n<p>Note: This file will be completely overwritten by the <code>docker-entrypoint.sh<\/code>. For development purposes you can set it to any value that is appropriate, e.g. when used together with <code>npm start<\/code>.<\/p>\n<p><strong>Include config.js in index.html<\/strong><\/p>\n<p><em>public\/index.html<\/em><\/p>\n<pre><code>   <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">head<\/span>&gt;<\/span>\n     ...\n    <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">script<\/span> <span class=\"hljs-attr\">type<\/span>=<span class=\"hljs-string\">\"text\/javascript\"<\/span> <span class=\"hljs-attr\">src<\/span>=<span class=\"hljs-string\">\"%PUBLIC_URL%\/config.js\"<\/span> &gt;<\/span><span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">script<\/span>&gt;<\/span>\n     ...\n   <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">head<\/span>&gt;<\/span>\n   <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">body<\/span>&gt;<\/span>\n<\/code><\/pre>\n<p><strong>Make use of your environment variable<\/strong><\/p>\n<p><em>src\/App.tsx<\/em><\/p>\n<pre><code>declare global {\n    interface Window { <span class=\"hljs-attr\">extended<\/span>: any; }\n}\n<span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span> <span class=\"hljs-title\">App<\/span>() <\/span>{\n  <span class=\"hljs-keyword\">return<\/span> (\n    <span class=\"xml\"><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span> <span class=\"hljs-attr\">className<\/span>=<span class=\"hljs-string\">\"App\"<\/span>&gt;<\/span>\n      <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">header<\/span> <span class=\"hljs-attr\">className<\/span>=<span class=\"hljs-string\">\"App-header\"<\/span>&gt;<\/span>\n\n          You have configured {window.extended.MYAPP_API_ENDPOINT}\n\n      <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">header<\/span>&gt;<\/span>\n    <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span><\/span>\n  );\n}\n<\/code><\/pre>\n<p><strong>Build<\/strong><\/p>\n<pre><code>npm <span class=\"hljs-keyword\">install<\/span>\n<\/code><\/pre>\n<p><strong>Create docker image<\/strong><\/p>\n<pre><code><span class=\"hljs-symbol\">docker<\/span> <span class=\"hljs-keyword\">build <\/span>-f docker\/<span class=\"hljs-keyword\">build\/Dockerfile <\/span>-t read-env-example:<span class=\"hljs-number\">0<\/span>.<span class=\"hljs-number\">1<\/span>.<span class=\"hljs-number\">0<\/span> .\n<\/code><\/pre>\n<p><strong>Run container<\/strong><\/p>\n<pre><code>docker-compose -f .\/docker\/<span class=\"hljs-keyword\">run<\/span><span class=\"bash\">\/docker-compose.yml up<\/span>\n<\/code><\/pre>\n<p><strong>Navigate to your app<\/strong><\/p>\n<p>Open <a href=\"http:\/\/localhost\">http:\/\/localhost<\/a> in your browser.<br \/>\nYou will see the content of <code>MYAPP_API_ENDPOINT<\/code> like\u00a0 provided in your <code>docker\/run\/myapp.env<\/code>.<\/p>\n<p><strong>Further usage<\/strong><\/p>\n<p>You can provide additional variables starting with <code>MYAPP<\/code>. The <code>docker-entrypoint.sh<\/code> script will search for all variables starting with <code>MYAPP<\/code> and make them available through the <code>windows<\/code> object.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Blogpost for this stackoverflow answer: https:\/\/stackoverflow.com\/a\/74701083\/1485527 Get code here Create example app npx create-react-app read-env-example &#8211;template typescript Navigate to fresh app cd read-env-example Create Dockerfile mkdir -p docker\/build docker\/build\/Dockerfile # build environment FROM node:19-alpine3.15 as builder WORKDIR \/app ENV PATH \/app\/node_modules\/.bin:$PATH COPY package.json .\/ COPY package-lock.json .\/ RUN npm ci RUN npm install react-scripts@5.0.1 -g [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[6],"tags":[],"class_list":["post-2470","post","type-post","status-publish","format-standard","hentry","category-development"],"_links":{"self":[{"href":"https:\/\/jan.schnasse.org\/blog\/wp-json\/wp\/v2\/posts\/2470","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/jan.schnasse.org\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/jan.schnasse.org\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/jan.schnasse.org\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/jan.schnasse.org\/blog\/wp-json\/wp\/v2\/comments?post=2470"}],"version-history":[{"count":1,"href":"https:\/\/jan.schnasse.org\/blog\/wp-json\/wp\/v2\/posts\/2470\/revisions"}],"predecessor-version":[{"id":3816,"href":"https:\/\/jan.schnasse.org\/blog\/wp-json\/wp\/v2\/posts\/2470\/revisions\/3816"}],"wp:attachment":[{"href":"https:\/\/jan.schnasse.org\/blog\/wp-json\/wp\/v2\/media?parent=2470"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/jan.schnasse.org\/blog\/wp-json\/wp\/v2\/categories?post=2470"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/jan.schnasse.org\/blog\/wp-json\/wp\/v2\/tags?post=2470"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}