{"id":7105,"date":"2019-08-01T22:39:16","date_gmt":"2019-08-01T22:39:16","guid":{"rendered":"https:\/\/ormuco.com\/?p=7105"},"modified":"2019-11-12T15:50:28","modified_gmt":"2019-11-12T15:50:28","slug":"blog-react-app-reverse-proxy-env-aware","status":"publish","type":"post","link":"https:\/\/ormuco.com\/fr\/blog\/react-app-reverse-proxy-env-aware","title":{"rendered":"Making a React application with reverse proxy and environment-awareness"},"content":{"rendered":"<p>A little introduction to what I would like to achieve. I have been working on the frontend for quite some time. I upgrade all my React dependencies to the latest stable versions (it\u2019s all about hooks!) and use Webpack to optimize my build to the maximum (tree-shaking, compression, chunk splitting, etc.). Now I have two problems:<\/p>\n<ol>\n<li>How do I serve my minimized and compressed JavaScript and CSS bundles as a microservice?<\/li>\n<li>How do I switch my gateway endpoint from the development environment to the staging\/production environment? For example, in the development environment, all the API calls should go to https:\/\/dev.gateway.io and in the production environment, they should go to https:\/\/gateway.io without my having to rebuild the whole project.<\/li>\n<\/ol>\n<p>In the next sections, I will explain how I tackled these two problems.<\/p>\n<h2>How to serve minimized and compressed JS and CSS bundles as a microservice?<\/h2>\n<p>I\u2019m using <a href=\"https:\/\/www.npmjs.com\/package\/compression-webpack-plugin#compression-webpack-plugin\">compression-webpack-plugin<\/a> as a result, I have my bundles like <strong>app.bundle.83b334b1c8ef06b0b956.js.gz<\/strong> and <strong>app.83b334b1c8ef06b0b956.css.gz<\/strong>.<\/p>\n<p>I need a static server to host these bundles and also be able to serve compressed files. What will be the best candidate? It doesn\u2019t require much research to come to the conclusion: <strong class=\"iq jw\">Nginx<\/strong>.<\/p>\n<p>Here is my Dockerfile:<\/p>\n<pre class=\"ib ic id ie if gd dp jx\"><span id=\"98ab\" class=\"jy jz er bg ka b de kb kc l kd\" data-selectable-paragraph=\"\"># Node image\r\nFROM node:10 as builder\r\n\r\n<\/span><span id=\"5669\" class=\"jy jz er bg ka b de ke kf kg kh ki kc l kd\" data-selectable-paragraph=\"\"># set working directory\r\nRUN mkdir \/usr\/src\/app\r\nWORKDIR \/usr\/src\/app\r\n\r\n<\/span><span id=\"58d1\" class=\"jy jz er bg ka b de ke kf kg kh ki kc l kd\" data-selectable-paragraph=\"\"># copy source code\r\nCOPY . \/usr\/src\/app\/\r\n\r\n<\/span><span id=\"ed46\" class=\"jy jz er bg ka b de ke kf kg kh ki kc l kd\" data-selectable-paragraph=\"\"># install app dependencies\r\nRUN npm install\r\n\r\n<\/span><span id=\"5fef\" class=\"jy jz er bg ka b de ke kf kg kh ki kc l kd\" data-selectable-paragraph=\"\"># run production build\r\nRUN npm run production\r\n\r\n<\/span><span id=\"2394\" class=\"jy jz er bg ka b de ke kf kg kh ki kc l kd\" data-selectable-paragraph=\"\"># Nginx\r\nFROM nginx:1.15\r\nRUN rm -rf \/etc\/nginx\/conf.d\r\nCOPY conf \/etc\/nginx\r\nCOPY \u2014 from=builder \/usr\/src\/app\/app-build \/usr\/share\/nginx\/html\r\nEXPOSE 80 \r\nCMD [\u201cnginx\u201d, \u201c-g\u201d, \u201cdaemon off;\u201d]<\/span><\/pre>\n<p class=\"ib ic id ie if gd dp jx\"><span id=\"2394\" class=\"jy jz er bg ka b de ke kf kg kh ki kc l kd\" data-selectable-paragraph=\"\">Here is my Nginx conf.d. I enabled the gzip with gzip_static on:<br \/>\n<\/span><\/p>\n<pre>server {\r\n  listen 80;\r\n  location \/ {\r\n    gzip_static on;\r\n    root   \/usr\/share\/nginx\/html;\r\n    index  index.html index.htm;\r\n    try_files $uri $uri\/ \/index.html;\r\n  }\r\n  error_page   500 502 503 504  \/50x.html;\r\n  location = \/50x.html {\r\n    root   \/usr\/share\/nginx\/html;\r\n  }\r\n}<\/pre>\n<p>Now you can run the image on your local to verify the result. Your website should be waiting for you at http:\/\/localhost.<\/p>\n<h2>How to switch gateway endpoints from the development environment to the staging\/production environment?<\/h2>\n<p>Actually, this process can be generalized for injecting any environment variable on the frontend. The way I did it is through the index.html with a small env.js.<\/p>\n<p>My env.js looks like this:<\/p>\n<pre>window.DEV_ENDPOINT = '<a href=\"https:\/\/dev.spiderkube.io%27\/\" class=\"ap cb jk jl jm jn\">https:\/\/dev.gateway.io'<\/a>;<\/pre>\n<p id=\"136c\" class=\"io ip er bg iq b ir is it iu iv iw ix iy iz ja jb\" data-selectable-paragraph=\"\">My index.html looks like this:<\/p>\n<pre class=\"ib ic id ie if gd dp jx\"><span id=\"a719\" class=\"jy jz er bg ka b de kb kc l kd\" data-selectable-paragraph=\"\">&lt;!DOCTYPE html&gt;\r\n&lt;html&gt;\r\n    &lt;head&gt;\r\n        &lt;meta charset=&quot;utf-8&quot;&gt;\r\n        &lt;meta http-equiv=&quot;X-UA-Compatible&quot; content=&quot;IE=edge, chrome=1&quot; \/&gt;\r\n        &lt;meta name=&quot;viewport&quot; content=&quot;width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no&quot; \/&gt;\r\n    &lt;\/head&gt;\r\n    &lt;body&gt;\r\n        &lt;div id=&quot;root&quot;&gt;Loading...&lt;\/div&gt;<\/span><span id=\"76af\" class=\"jy jz er bg ka b de ke kf kg kh ki kc l kd\" data-selectable-paragraph=\"\">        &lt;!-- inject the env --&gt;\r\n        &lt;script type=&quot;text\/javascript&quot; src=&quot;\/config\/env.js&quot;&gt;&lt;\/script&gt;\r\n    &lt;\/body&gt;\r\n&lt;\/html&gt;\r\n<\/span><\/pre>\n<p id=\"4ffe\" class=\"io ip er bg iq b ir is it iu iv iw ix iy iz ja jb\" data-selectable-paragraph=\"\">This is where I use the DEV_ENDPOINT:<\/p>\n<pre class=\"ib ic id ie if gd dp jx\"><span id=\"374e\" class=\"jy jz er bg ka b de kb kc l kd\" data-selectable-paragraph=\"\">const instance = axios.create({\r\n        baseURL: window.DEV_ENDPOINT || CommonConstants.BASE_URL\r\n    });<\/span><span id=\"76af\" class=\"jy jz er bg ka b de ke kf kg kh ki kc l kd\" data-selectable-paragraph=\"\"><\/span><\/pre>\n<p id=\"c889\" class=\"io ip er bg iq b ir is it iu iv iw ix iy iz ja jb\" data-selectable-paragraph=\"\"><strong class=\"iq jw\">BASE_URL<\/strong> is actually the production gateway endpoint. As a result, if <strong class=\"iq jw\">DEV_ENDPOINT<\/strong> is not presented, it will fall back to the production endpoint. You can define anything in this env.js. Now that we&#8217;ve finished the development setup, we need to wrap everything into Kubernetes.<\/p>\n<p id=\"b0e6\" class=\"io ip er bg iq b ir is it iu iv iw ix iy iz ja jb\" data-selectable-paragraph=\"\">Kubernetes provides configmap to achieve something to this effect. Here is the configmap YAML:<\/p>\n<pre class=\"ib ic id ie if gd dp jx\"><span id=\"ff18\" class=\"jy jz er bg ka b de kb kc l kd\" data-selectable-paragraph=\"\">apiVersion: v1\r\nkind: ConfigMap\r\nmetadata:\r\n  name: frontend-dev-configmap\r\n  labels:\r\n    name: frontend-dev-configmap\r\ndata:\r\n  endpoint-config: |\r\n    window.DEV_ENDPOINT = '<a href=\"https:\/\/dev.spiderkube.io%27\/\" class=\"ap cb jk jl jm jn\">https:\/\/dev.gateway.io'<\/a>;<\/span><\/pre>\n<p id=\"8ffa\" class=\"io ip er bg iq b ir is it iu iv iw ix iy iz ja jb\" data-selectable-paragraph=\"\">And here is the deployment YAML:<\/p>\n<pre class=\"ib ic id ie if gd dp jx\"><span id=\"24da\" class=\"jy jz er bg ka b de kb kc l kd\" data-selectable-paragraph=\"\">apiVersion: extensions\/v1beta1\r\nkind: Deployment\r\nmetadata:\r\n  name: frontend\r\nspec:\r\n  replicas: 2\r\n  strategy:\r\n    type: RollingUpdate\r\n  template:\r\n    metadata:\r\n      labels:\r\n        app: frontend\r\n    spec:\r\n      containers:\r\n      - name: frontend-container\r\n        image: frontend:latest\r\n        imagePullPolicy: Always\r\n        ports:\r\n        - containerPort: 80\r\n          name: http\r\n        readinessProbe:\r\n          httpGet:\r\n            path: \/\r\n            port: 80\r\n          initialDelaySeconds: 5\r\n          periodSeconds: 3\r\n          successThreshold: 1\r\n        volumeMounts:\r\n        - name: env-config\r\n          mountPath: \/usr\/share\/nginx\/html\/config\r\n      volumes:\r\n        - name: env-config\r\n          configMap:\r\n            name: frontend-dev-configmap\r\n            items:\r\n              - key: endpoint-config\r\n                path: env.js<\/span><\/pre>\n<p id=\"72e5\" class=\"io ip er bg iq b ir is it iu iv iw ix iy iz ja jb\" data-selectable-paragraph=\"\">Now Kubernetes will create the env.js at \/usr\/share\/nginx\/html\/config before starting the frontend container.<\/p>\n<p id=\"223b\" class=\"io ip er bg iq b ir is it iu iv iw ix iy iz ja jb\" data-selectable-paragraph=\"\">That\u2019s it!<\/p>\n<p><em>This article was originally published on\u00a0<a href=\"https:\/\/medium.com\/@felixsong88\/making-a-react-application-with-reverse-proxy-and-environment-aware-at-kubernetes-deployment-eb5b353fc159\">Medium<\/a>.<\/em><\/p>\n<p><a href=\"https:\/\/ormuco.com\/fr\/webcast\/openstack-summit-2018\/\"><img loading=\"lazy\" class=\"size-full wp-image-7034 aligncenter\" src=\"https:\/\/ormuco.com\/wp-content\/uploads\/2019\/07\/Qinling-CTA-1-1.png\" alt=\"OpenStack Summit\" width=\"336\" height=\"280\" srcset=\"https:\/\/ormuco.com\/wp-content\/uploads\/2019\/07\/Qinling-CTA-1-1.png 336w, https:\/\/ormuco.com\/wp-content\/uploads\/2019\/07\/Qinling-CTA-1-1-300x250.png 300w, https:\/\/ormuco.com\/wp-content\/uploads\/2019\/07\/Qinling-CTA-1-1-270x225.png 270w\" sizes=\"(max-width: 336px) 100vw, 336px\" \/><\/a><\/p>","protected":false},"excerpt":{"rendered":"<p>A little introduction to what I would like to achieve. I have been working on the frontend for quite some time. I upgrade all my React dependencies to the latest stable versions (it\u2019s all about hooks!) and use Webpack to optimize my build to the maximum (tree-shaking, compression, chunk splitting, etc.). Now I have two [&hellip;]<\/p>","protected":false},"author":5,"featured_media":7122,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"spay_email":""},"categories":[74],"tags":[],"jetpack_featured_media_url":"https:\/\/ormuco.com\/wp-content\/uploads\/2019\/08\/React-application-1.png","yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v15.5 - https:\/\/yoast.com\/wordpress\/plugins\/seo\/ -->\n<title>Making a React application with reverse proxy and environment-awareness - Ormuco<\/title>\n<meta name=\"description\" content=\"Learn how to make a React application with reverse proxy and environment-awareness at a Kubernetes deployment with microservices architecture.\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/ormuco.com\/fr\/blog\/react-app-reverse-proxy-env-aware\/\" \/>\n<meta property=\"og:locale\" content=\"fr_CA\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Making a React application with reverse proxy and environment-awareness - Ormuco\" \/>\n<meta property=\"og:description\" content=\"Learn how to make a React application with reverse proxy and environment-awareness at a Kubernetes deployment with microservices architecture.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/ormuco.com\/fr\/blog\/react-app-reverse-proxy-env-aware\/\" \/>\n<meta property=\"og:site_name\" content=\"Ormuco\" \/>\n<meta property=\"article:publisher\" content=\"https:\/\/www.facebook.com\/Ormuco\/\" \/>\n<meta property=\"article:published_time\" content=\"2019-08-01T22:39:16+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2019-11-12T15:50:28+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/ormuco.com\/wp-content\/uploads\/2019\/08\/React-application-1.png\" \/>\n\t<meta property=\"og:image:width\" content=\"1200\" \/>\n\t<meta property=\"og:image:height\" content=\"628\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:creator\" content=\"@Ormuco_Inc\" \/>\n<meta name=\"twitter:site\" content=\"@Ormuco_Inc\" \/>\n<meta name=\"twitter:label1\" content=\"Est. reading time\">\n\t<meta name=\"twitter:data1\" content=\"3 minutes\">\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"Organization\",\"@id\":\"https:\/\/ormuco.com\/#organization\",\"name\":\"Ormuco Inc\",\"url\":\"https:\/\/ormuco.com\/\",\"sameAs\":[\"https:\/\/www.facebook.com\/Ormuco\/\",\"https:\/\/www.linkedin.com\/company\/ormuco-inc-\/\",\"https:\/\/www.youtube.com\/channel\/UCbzzf28bWMg0zhOrq0fI_sQ\",\"https:\/\/twitter.com\/Ormuco_Inc\"],\"logo\":{\"@type\":\"ImageObject\",\"@id\":\"https:\/\/ormuco.com\/#logo\",\"inLanguage\":\"fr-CA\",\"url\":\"https:\/\/ormuco.com\/wp-content\/uploads\/2018\/07\/Ormuco_logo.png\",\"width\":360,\"height\":89,\"caption\":\"Ormuco Inc\"},\"image\":{\"@id\":\"https:\/\/ormuco.com\/#logo\"}},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/ormuco.com\/#website\",\"url\":\"https:\/\/ormuco.com\/\",\"name\":\"Ormuco\",\"description\":\"Next Generation Mobile Computing\",\"publisher\":{\"@id\":\"https:\/\/ormuco.com\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":\"https:\/\/ormuco.com\/?s={search_term_string}\",\"query-input\":\"required name=search_term_string\"}],\"inLanguage\":\"fr-CA\"},{\"@type\":\"ImageObject\",\"@id\":\"https:\/\/ormuco.com\/blog\/react-app-reverse-proxy-env-aware\/#primaryimage\",\"inLanguage\":\"fr-CA\",\"url\":\"https:\/\/ormuco.com\/wp-content\/uploads\/2019\/08\/React-application-1.png\",\"width\":1200,\"height\":628,\"caption\":\"React application\"},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/ormuco.com\/blog\/react-app-reverse-proxy-env-aware\/#webpage\",\"url\":\"https:\/\/ormuco.com\/blog\/react-app-reverse-proxy-env-aware\/\",\"name\":\"Making a React application with reverse proxy and environment-awareness - Ormuco\",\"isPartOf\":{\"@id\":\"https:\/\/ormuco.com\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/ormuco.com\/blog\/react-app-reverse-proxy-env-aware\/#primaryimage\"},\"datePublished\":\"2019-08-01T22:39:16+00:00\",\"dateModified\":\"2019-11-12T15:50:28+00:00\",\"description\":\"Learn how to make a React application with reverse proxy and environment-awareness at a Kubernetes deployment with microservices architecture.\",\"inLanguage\":\"fr-CA\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/ormuco.com\/blog\/react-app-reverse-proxy-env-aware\/\"]}]},{\"@type\":\"Article\",\"@id\":\"https:\/\/ormuco.com\/blog\/react-app-reverse-proxy-env-aware\/#article\",\"isPartOf\":{\"@id\":\"https:\/\/ormuco.com\/blog\/react-app-reverse-proxy-env-aware\/#webpage\"},\"author\":{\"@id\":\"https:\/\/ormuco.com\/#\/schema\/person\/dac5540369f781a1d6ab5f745d1e09be\"},\"headline\":\"Making a React application with reverse proxy and environment-awareness\",\"datePublished\":\"2019-08-01T22:39:16+00:00\",\"dateModified\":\"2019-11-12T15:50:28+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/ormuco.com\/blog\/react-app-reverse-proxy-env-aware\/#webpage\"},\"publisher\":{\"@id\":\"https:\/\/ormuco.com\/#organization\"},\"image\":{\"@id\":\"https:\/\/ormuco.com\/blog\/react-app-reverse-proxy-env-aware\/#primaryimage\"},\"articleSection\":\"Developers Corner\",\"inLanguage\":\"fr-CA\"},{\"@type\":\"Person\",\"@id\":\"https:\/\/ormuco.com\/#\/schema\/person\/dac5540369f781a1d6ab5f745d1e09be\",\"name\":\"Yulong Song\",\"description\":\"Yulong leads the team that\\u2019s developing Ormuco's dynamic application deployment platform, with responsibilities in front-end development and DevOps. Yulong has previously worked as a Full-Stack Developer at Ormuco. He graduated with a Master of Computer Science from Concordia University and a Bachelor of Management Science from University of Shanghai for Science and Technology.\",\"sameAs\":[\"https:\/\/www.linkedin.com\/in\/yulong-song-7bbb3262\/\"]}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","jetpack_shortlink":"https:\/\/wp.me\/pa8ID1-1QB","_links":{"self":[{"href":"https:\/\/ormuco.com\/fr\/wp-json\/wp\/v2\/posts\/7105"}],"collection":[{"href":"https:\/\/ormuco.com\/fr\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/ormuco.com\/fr\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/ormuco.com\/fr\/wp-json\/wp\/v2\/users\/5"}],"replies":[{"embeddable":true,"href":"https:\/\/ormuco.com\/fr\/wp-json\/wp\/v2\/comments?post=7105"}],"version-history":[{"count":15,"href":"https:\/\/ormuco.com\/fr\/wp-json\/wp\/v2\/posts\/7105\/revisions"}],"predecessor-version":[{"id":7948,"href":"https:\/\/ormuco.com\/fr\/wp-json\/wp\/v2\/posts\/7105\/revisions\/7948"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/ormuco.com\/fr\/wp-json\/wp\/v2\/media\/7122"}],"wp:attachment":[{"href":"https:\/\/ormuco.com\/fr\/wp-json\/wp\/v2\/media?parent=7105"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/ormuco.com\/fr\/wp-json\/wp\/v2\/categories?post=7105"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/ormuco.com\/fr\/wp-json\/wp\/v2\/tags?post=7105"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}