{"id":173286,"date":"2021-02-08T16:00:14","date_gmt":"2021-02-08T13:00:14","guid":{"rendered":"https:\/\/en.buradabiliyorum.com\/how-to-dockerise-a-react-app-cloudsavvy-it\/"},"modified":"2021-02-08T16:00:14","modified_gmt":"2021-02-08T13:00:14","slug":"how-to-dockerise-a-react-app-cloudsavvy-it","status":"publish","type":"post","link":"https:\/\/buradabiliyorum.com\/en\/how-to-dockerise-a-react-app-cloudsavvy-it\/","title":{"rendered":"#How to Dockerise A React App \u2013 CloudSavvy IT"},"content":{"rendered":"<div id=\"ez-toc-container\" class=\"ez-toc-v2_0_84 counter-hierarchy ez-toc-counter ez-toc-custom ez-toc-container-direction\">\n<p class=\"ez-toc-title\" style=\"cursor:inherit\">Table of Contents<\/p>\n<label for=\"ez-toc-cssicon-toggle-item-6a264a7e788d1\" class=\"ez-toc-cssicon-toggle-label\"><span class=\"\"><span class=\"eztoc-hide\" style=\"display:none;\">Toggle<\/span><span class=\"ez-toc-icon-toggle-span\"><svg style=\"fill: #dd3333;color:#dd3333\" xmlns=\"http:\/\/www.w3.org\/2000\/svg\" class=\"list-377408\" width=\"20px\" height=\"20px\" viewBox=\"0 0 24 24\" fill=\"none\"><path d=\"M6 6H4v2h2V6zm14 0H8v2h12V6zM4 11h2v2H4v-2zm16 0H8v2h12v-2zM4 16h2v2H4v-2zm16 0H8v2h12v-2z\" fill=\"currentColor\"><\/path><\/svg><svg style=\"fill: #dd3333;color:#dd3333\" class=\"arrow-unsorted-368013\" xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"10px\" height=\"10px\" viewBox=\"0 0 24 24\" version=\"1.2\" baseProfile=\"tiny\"><path d=\"M18.2 9.3l-6.2-6.3-6.2 6.3c-.2.2-.3.4-.3.7s.1.5.3.7c.2.2.4.3.7.3h11c.3 0 .5-.1.7-.3.2-.2.3-.5.3-.7s-.1-.5-.3-.7zM5.8 14.7l6.2 6.3 6.2-6.3c.2-.2.3-.5.3-.7s-.1-.5-.3-.7c-.2-.2-.4-.3-.7-.3h-11c-.3 0-.5.1-.7.3-.2.2-.3.5-.3.7s.1.5.3.7z\"\/><\/svg><\/span><\/span><\/label><input type=\"checkbox\"  id=\"ez-toc-cssicon-toggle-item-6a264a7e788d1\" checked aria-label=\"Toggle\" \/><nav><ul class='ez-toc-list ez-toc-list-level-1 ' ><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-1\" href=\"https:\/\/buradabiliyorum.com\/en\/how-to-dockerise-a-react-app-cloudsavvy-it\/#Defining_Our_Requirements\" >Defining Our Requirements<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-2\" href=\"https:\/\/buradabiliyorum.com\/en\/how-to-dockerise-a-react-app-cloudsavvy-it\/#A_Dockerfile_For_CRA\" >A Dockerfile For CRA<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-3\" href=\"https:\/\/buradabiliyorum.com\/en\/how-to-dockerise-a-react-app-cloudsavvy-it\/#Using_The_Docker_Image\" >Using The Docker Image<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-4\" href=\"https:\/\/buradabiliyorum.com\/en\/how-to-dockerise-a-react-app-cloudsavvy-it\/#Switching_to_NGINX\" >Switching to NGINX<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-5\" href=\"https:\/\/buradabiliyorum.com\/en\/how-to-dockerise-a-react-app-cloudsavvy-it\/#Benefits_of_This_Approach\" >Benefits of This Approach<\/a><\/li><\/ul><\/nav><\/div>\n<p><strong>&#8220;#How to Dockerise A React <a href=\"https:\/\/buradabiliyorum.com\/en\/category\/download-scripts-themes-apps\/\" data-internallinksmanager029f6b8e52c=\"9\" title=\"Download Scripts &amp; Themes &amp; Apps\" target=\"_blank\" rel=\"noopener\">App<\/a> \u2013 CloudSavvy IT&#8221;<\/strong><\/p>\n<div id=\"article-content-area\">\n<img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-9496\" src=\"https:\/\/www.cloudsavvyit.com\/thumbcache\/0\/0\/b667a97480ac2ee2c1c6205721d5a0cb\/p\/uploads\/2021\/02\/7f4575d6.jpeg\" alt=\"Graphic of Docker and React logos\" width=\"1600\" height=\"900\" onload=\"pagespeed.lazyLoadImages.loadIfVisibleAndMaybeBeacon(this);\" onerror=\"this.onerror=null;pagespeed.lazyLoadImages.loadIfVisibleAndMaybeBeacon(this);\"\/><\/p>\n<p>Containerising your projects with Docker simplifies the development experience and facilitates straightforward deployment to cloud environments. Let\u2019s look at how we can package a React site as a Docker container.<\/p>\n<p>This article focuses on projects that have been bootstrapped using <a rel=\"nofollow noopener\" target=\"_blank\" href=\"https:\/\/create-react-app.dev\/\"><code>create-react-app<\/code><\/a> (CRA). If you\u2019ve ejected your CRA configuration, or are using a custom build process, you\u2019ll need to adjust the <code>npm run build<\/code> command accordingly.<\/p>\n<p>Docker images are created via a <code>Dockerfile<\/code>. This defines a base image to use, such as the Apache web server. You then list a <a href=\"https:\/\/buradabiliyorum.com\/en\/category\/watch-movies-tv-seriess\/\" data-internallinksmanager029f6b8e52c=\"8\" title=\"Watch Movies &amp; TV Series\" target=\"_blank\" rel=\"noopener\">series<\/a> of commands which add packages, apply config changes and copy in files needed by your application.<\/p>\n<h2 id=\"defining-our-requirements\"><span class=\"ez-toc-section\" id=\"Defining_Our_Requirements\"><\/span>Defining Our Requirements<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p>CRA includes a built-in live build and reload system, which you access via <code>npm run start<\/code>. This enables you to quickly iterate on your site during development.<\/p>\n<p>When moving to production, you need to compile your static resources using <code>npm run build<\/code>. This produces minified HTML, CSS and JavaScript bundles in your <code>build<\/code> directory. These files are what you upload to your web server.<\/p>\n<p>A basic approach to Dockerising could be to <code>npm run build<\/code> locally. You\u2019d then copy the contents of the <code>build<\/code> directory into your Docker image \u2013 using a web server base image \u2013 and call it a day.<\/p>\n<p>This approach doesn\u2019t scale well, particularly when building your Docker image within a CI enviroment. Your app\u2019s build process isn\u2019t completely encapsulated within the container build, as it\u2019s dependent on the external <code>npm run build<\/code> command. We\u2019ll now proceed with a more complete example where the entire routine runs within Docker.<\/p>\n<h2 id=\"a-dockerfile-for-cra\"><span class=\"ez-toc-section\" id=\"A_Dockerfile_For_CRA\"><\/span>A Dockerfile For CRA<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<pre>FROM node:latest AS build&#13;\nWORKDIR \/build&#13;\n&#13;\nCOPY package.json package.json&#13;\nCOPY package-lock.json package-lock.json&#13;\nRUN npm ci&#13;\n&#13;\nCOPY public\/ public&#13;\nCOPY src\/ src&#13;\nRUN npm run build&#13;\n&#13;\nFROM httpd:alpine&#13;\nWORKDIR \/var\/www\/html&#13;\nCOPY --from=build \/build\/build\/ .<\/pre>\n<p>This <code>Dockerfile<\/code> incorporates everything needed to fully containerise the project. It uses Docker\u2019s multi-stage builds to first run the React build and then copy the output into an <code>alpine<\/code> Apache server container. This ensures the final image is as small as possible.<\/p>\n<p>The first section of the file defines the build stage. It uses the official Node.js base image. The <code>package.json<\/code> and <code>package-lock.json<\/code> files are copied in. <code>npm ci<\/code> is then used to install the project\u2019s npm packages. <code>ci<\/code> is used instead of <code>install<\/code> because it forces an exact match with the contents of <code>package-lock.json<\/code>.<\/p>\n<p>Once the dependencies are installed, the <code>public<\/code> and <code>src<\/code> directories are copied into the container. The folders are copied after the <code>npm ci<\/code> command because they\u2019re likely to change much more frequently than the dependencies. This ensures the build can take full advantage of Docker\u2019s layer caching \u2013 the potentially expensive <code>npm ci<\/code> command won\u2019t be run unless the <code>package.json<\/code> or <code>package-lock.json<\/code> files change.<\/p>\n<p>The last step in this build stage is to <code>npm run build<\/code>. CRA will compile our React app and place its output into the <code>build<\/code> directory.<\/p>\n<p>The second stage in the <code>Dockerfile<\/code> is much simpler. The <code>httpd:alpine<\/code> base image is selected. It includes the Apache web server in an image which weighs in at around 5MB. The compiled HTML, CSS and JavaScript is copied out of the build stage container and into the final image.<\/p>\n<h2 id=\"using-the-docker-image\"><span class=\"ez-toc-section\" id=\"Using_The_Docker_Image\"><\/span>Using The Docker Image<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p>Use the <code>docker build<\/code> command to build your image:<\/p>\n<pre>docker build -t my-react-app:latest .<\/pre>\n<p>This builds the image and tags it as <code>my-react-app:latest<\/code>. It uses the <code>Dockerfile<\/code> found in your working directory (specified as <code>.<\/code>).<\/p>\n<p>The build may take a few minutes to complete. Subsequent builds will be faster, as layers like the <code>npm ci<\/code> command will be cached between runs.<\/p>\n<p>Once your image has been built, you\u2019re ready to use it:<\/p>\n<pre>docker run -d -p 8080:80 my-react-app:latest<\/pre>\n<p>Docker will create a new container using the <code>my-react-app:latest<\/code> image. Port 8080 on the host (your machine) is bound to port 80 within the container. This means you can visit <code>http:\/\/localhost:8080<\/code> in your browser to see your React project! The <code>-d<\/code> flag is present so the container runs in the background.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-9495\" src=\"https:\/\/www.cloudsavvyit.com\/thumbcache\/0\/0\/48802d3edb3b3c66d4617a12ded89695\/p\/uploads\/2021\/02\/f2aaf526.png\" alt=\"\" width=\"960\" height=\"540\" onload=\"pagespeed.lazyLoadImages.loadIfVisibleAndMaybeBeacon(this);\" onerror=\"this.onerror=null;pagespeed.lazyLoadImages.loadIfVisibleAndMaybeBeacon(this);\"\/><\/p>\n<h2 id=\"switching-to-nginx\"><span class=\"ez-toc-section\" id=\"Switching_to_NGINX\"><\/span>Switching to NGINX<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p>The example above uses Apache but you can easily switch to NGINX instead.<\/p>\n<pre>FROM nginx:alpine&#13;\nCOPY --from=build \/build\/build\/ \/usr\/share\/nginx\/html<\/pre>\n<p>You can adopt alternative web servers in a similar manner; as CRA produces completely static output, you have great flexibility in selecting how your site is hosted. Copy the contents of the <code>\/build\/build<\/code> directory from the <code>build<\/code> stage into the default HTML directory of your chosen server software.<\/p>\n<h2 id=\"benefits-of-this-approach\"><span class=\"ez-toc-section\" id=\"Benefits_of_This_Approach\"><\/span>Benefits of This Approach<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p>Using Docker to not only encapsulate your final build, but also to create the build itself, gives your project complete portability across environments. Developers only need Docker installed to build and run your React site.<\/p>\n<p>More realistically, this image is ready to use with a CI server to build images in an automated fashion. As long as a Docker environment is available, you can convert your source code into a deployable image without any manual intervention.<\/p>\n<p>By using multi-stage builds, the final image remains streamlined and should be only a few megabytes in size. The much larger <code>node<\/code> image is only used during the compilation stage, where Node and npm are necessary.\n<\/div>\n<blockquote><p><strong><span style=\"color: #ff6600;\">If you liked the article, do not forget to share it with your friends. Follow us on\u00a0<span style=\"color: #ff0000;\"><a style=\"color: #ff0000;\" href=\"https:\/\/news.google.com\/publications\/CAAqBwgKMLG0nwswvr63Aw\" target=\"_blank\" rel=\"nofollow noopener noreferrer\">Google News<\/a><\/span>\u00a0too, click on the star and choose us from your favorites.<\/span><\/strong><\/p><\/blockquote>\n<blockquote>\n<p style=\"text-align: center;\">For forums sites go to <span style=\"color: #ff9900;\"><a style=\"color: #ff9900;\" href=\"https:\/\/forum.buradabiliyorum.com\/\" target=\"_blank\" rel=\"noopener\">Forum.BuradaBiliyorum.Com<\/a><\/span><\/strong><\/p>\n<\/blockquote>\n<blockquote>\n<p style=\"text-align: center;\"><strong>If you want to read more like this article, you can visit our <span style=\"color: #ff9900;\"><a style=\"color: #ff9900;\" href=\"https:\/\/en.buradabiliyorum.com\/technology\/\" target=\"_blank\" rel=\"noopener\">Technology category.<\/a><\/span><\/strong><\/p>\n<\/blockquote>\n<p><span style=\"color: black;\"><a style=\"color: #ff9900;\" href=\"https:\/\/www.cloudsavvyit.com\/9490\/how-to-dockerise-a-react-app\/\" target=\"_blank\" rel=\"noopener\">Source<\/a><\/span><\/p>\n","protected":false},"excerpt":{"rendered":"<p>&#8220;#How to Dockerise A React App \u2013 CloudSavvy IT&#8221; Containerising your projects with Docker simplifies the development experience and facilitates straightforward deployment to cloud environments. Let\u2019s look at how we can package a React site as a Docker container. This article focuses on projects that have been bootstrapped using create-react-app (CRA). If you\u2019ve ejected your&#8230;<\/p>\n","protected":false},"author":1,"featured_media":173287,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"fifu_image_url":"https:\/\/www.cloudsavvyit.com\/p\/uploads\/2021\/02\/7f4575d6.jpeg","fifu_image_alt":"","footnotes":""},"categories":[18],"tags":[],"class_list":["post-173286","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-technology"],"_links":{"self":[{"href":"https:\/\/buradabiliyorum.com\/en\/wp-json\/wp\/v2\/posts\/173286","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/buradabiliyorum.com\/en\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/buradabiliyorum.com\/en\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/buradabiliyorum.com\/en\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/buradabiliyorum.com\/en\/wp-json\/wp\/v2\/comments?post=173286"}],"version-history":[{"count":0,"href":"https:\/\/buradabiliyorum.com\/en\/wp-json\/wp\/v2\/posts\/173286\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/buradabiliyorum.com\/en\/wp-json\/wp\/v2\/media\/173287"}],"wp:attachment":[{"href":"https:\/\/buradabiliyorum.com\/en\/wp-json\/wp\/v2\/media?parent=173286"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/buradabiliyorum.com\/en\/wp-json\/wp\/v2\/categories?post=173286"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/buradabiliyorum.com\/en\/wp-json\/wp\/v2\/tags?post=173286"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}