{"id":10776,"date":"2024-04-02T21:15:45","date_gmt":"2024-04-02T21:15:45","guid":{"rendered":"https:\/\/putridparrot.com\/blog\/?p=10776"},"modified":"2024-04-06T09:58:26","modified_gmt":"2024-04-06T09:58:26","slug":"dockerize-your-react-application","status":"publish","type":"post","link":"https:\/\/putridparrot.com\/blog\/dockerize-your-react-application\/","title":{"rendered":"Dockerize your React application"},"content":{"rendered":"<p>You&#8217;ve created you React application and are now looking to create a docker image for it.<\/p>\n<p>Before we look at the Dockerfile, create yourself a .dockerignore file that looks like this<\/p>\n<pre class=\"brush: plain; title: ; notranslate\" title=\"\">\r\n.git\r\nnode_modules\r\n<\/pre>\n<p>We do not require the .git folder in our image and we&#8217;re going to install our node modules via <em>npm install<\/em> as you&#8217;ll find copying the node_modules folder(s) is slow.<\/p>\n<p>Let&#8217;s jump straight in and look at a Dockerfile that will take our React code containerize it and set the container up to run nginx to host it.<\/p>\n<pre class=\"brush: plain; title: ; notranslate\" title=\"\">\r\nFROM node:21-alpine3.18 as build\r\n\r\nWORKDIR \/usr\/app\r\nCOPY . .\r\nRUN npm install\r\nRUN npm run build\r\n\r\nFROM nginx:alpine\r\nCOPY --from=build \/usr\/app\/build \/usr\/share\/nginx\/html\r\nEXPOSE 80\r\nCMD &#x5B;&quot;nginx&quot;, &quot;-g&quot;, &quot;daemon off;&quot;]\r\n<\/pre>\n<p>We&#8217;re using a <a href=\"https:\/\/hub.docker.com\/_\/node\" rel=\"noopener\" target=\"_blank\">node alpine image<\/a> as our base. This is a lightweight image as we won&#8217;t our image to be lean. Next we create our WORKDIR, this can be set to your preferred location but just remember to reuse that location in the COPY command. We&#8217;re using .dockerignore to ignore .git and node_modules which allows us to then just copy everything to the image, where we then install then build our React application.<\/p>\n<p>Finally we use nginx to serve our application, first copying the <em>build<\/em> folder to nginx and finally we set up the CMD to run nginx once the container is started, thus hosting our React application.<\/p>\n<p>To build our image we can just use the following (change the tag name and version to suit your application)<\/p>\n<pre class=\"brush: plain; title: ; notranslate\" title=\"\">\r\ndocker build -t my-app:0.1.0 .\r\n<\/pre>\n<p>and to run, again set your application name any port redirects and use you tagged and version<\/p>\n<pre class=\"brush: plain; title: ; notranslate\" title=\"\">\r\ndocker run --rm --name my-app -p 8080:80 -d my-app:0.1.0\r\n<\/pre>\n<p>We could also extend this sample to include copying of nginx.conf to the image, for example if you want the supply a config like this<\/p>\n<pre class=\"brush: plain; title: ; notranslate\" title=\"\">\r\nworker_processes 4;\r\n\r\nevents { worker_connections 1024; }\r\n\r\nhttp {\r\n  server {\r\n    listen 4200;\r\n    root  \/usr\/share\/nginx\/html;\r\n    include \/etc\/nginx\/mime.types;\r\n\r\n  location \/ {\r\n    root   \/usr\/share\/nginx\/html;\r\n    index  index.html;\r\n    try_files $uri $uri\/ \/index.html;\r\n  }\r\n}\r\n}\r\n<\/pre>\n<p>If we assume we&#8217;re storing out nginx.conf file in a folder named .ngnix (this is not required it&#8217;s just for this example) then we could add the following to the Dockerfile, after the line <em>FROM nginx:alpine<\/em> add the following and whilst we&#8217;re at it let&#8217;s get rid of the default files that might be located in the images nginx\/html folder<\/p>\n<pre class=\"brush: plain; title: ; notranslate\" title=\"\">\r\nCOPY .\/.nginx\/nginx.conf \/etc\/nginx\/nginx.conf\r\nRUN rm -rf \/usr\/share\/nginx\/html\/*\r\n<\/pre>\n<p><strong>Docker Compose<\/strong><\/p>\n<p>Whilst we&#8217;re here, let&#8217;s create a simple docker-compose.yaml file for our new image. <\/p>\n<pre class=\"brush: plain; title: ; notranslate\" title=\"\">\r\nversion: &#039;3.8&#039;\r\nservices:\r\n  front-end:\r\n    build:\r\n      context: .\/ui\r\n      dockerfile: .\/ui\/Dockerfile\r\n    ports:\r\n      - 4200:4200\r\n    image: putridparrot\/my-app:0.1.0\r\n    container_name: my-app\r\n<\/pre>\n<p>We might like to store configuration for this image on the hosting server, i.e. via a volume in which case we&#8217;d simply add to the bottom of this file the following <\/p>\n<pre class=\"brush: plain; title: ; notranslate\" title=\"\">\r\n    volumes:\r\n      - .\/ui\/public\/appsettings.json:\/usr\/share\/nginx\/html\/appsettings.json\r\n<\/pre>\n<p>In this example we&#8217;re using an appsettings.json file to configure the environment, or it might include feature flag settings or whatever and assuming it&#8217;s stored in the <em>public<\/em> folder of you React application.<\/p>\n<p>Now we just <em>docker-compose up<\/em>.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>You&#8217;ve created you React application and are now looking to create a docker image for it. Before we look at the Dockerfile, create yourself a .dockerignore file that looks like this .git node_modules We do not require the .git folder in our image and we&#8217;re going to install our node modules via npm install as [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_jetpack_memberships_contains_paid_content":false,"footnotes":""},"categories":[102,243],"tags":[],"class_list":["post-10776","post","type-post","status-publish","format-standard","hentry","category-docker","category-react"],"jetpack_sharing_enabled":true,"jetpack_featured_media_url":"","_links":{"self":[{"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/posts\/10776","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/comments?post=10776"}],"version-history":[{"count":5,"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/posts\/10776\/revisions"}],"predecessor-version":[{"id":10787,"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/posts\/10776\/revisions\/10787"}],"wp:attachment":[{"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/media?parent=10776"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/categories?post=10776"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/tags?post=10776"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}