[
  {
    "path": ".dockerignore",
    "content": ".dockerignore\n.git\ndocker-compose*.yml\nDockerfile\nnode_modules\n"
  },
  {
    "path": "Dockerfile",
    "content": "FROM node:10.16.3 AS development\n\nRUN mkdir /srv/chat && chown node:node /srv/chat\n\nUSER node\n\nWORKDIR /srv/chat\n\nCOPY --chown=node:node package.json package-lock.json ./\n\nRUN npm install --quiet\n\nFROM node:10.16.3-slim AS production\n\nUSER node\n\nWORKDIR /srv/chat\n\nCOPY --from=development --chown=root:root /srv/chat/node_modules ./node_modules\n\nCOPY . .\n\nCMD [\"node\", \"index.js\"]\n"
  },
  {
    "path": "README.md",
    "content": "# Docker Chat Demo\n\nCompanion repo for this article on my blog:\n- [Lessons from Building a Node App in Docker](https://jdlm.info/articles/2019/09/06/lessons-building-node-app-docker.html) (2019 update).\n- [Lessons from Building a Node App in Docker](http://jdlm.info/articles/2016/03/06/lessons-building-node-app-docker.html) (2016 original).\n\nContains step-by-step examples used in the article to get the [socket.io chat example](http://socket.io/get-started/chat) running in Docker.\n\n## 2019 Update\n\nEach step has a tag:\n- [2019-01-bootstrapping](https://github.com/jdleesmiller/docker-chat-demo/tree/2019-01-bootstrapping)\n- [2019-02-bootstrapped](https://github.com/jdleesmiller/docker-chat-demo/tree/2019-02-bootstrapped)\n- [2019-03-dependencies](https://github.com/jdleesmiller/docker-chat-demo/tree/2019-03-dependencies)\n- [2019-04-the-app](https://github.com/jdleesmiller/docker-chat-demo/tree/2019-04-the-app)\n- [2019-05-dev-prod](https://github.com/jdleesmiller/docker-chat-demo/tree/2019-05-dev-prod)\n\n## 2016 Original\n\nHere's the [original code from 2016](https://github.com/jdleesmiller/docker-chat-demo/tree/2016).\n\nEach step has a tag:\n- [01-bootstrapping](https://github.com/jdleesmiller/docker-chat-demo/tree/01-bootstrapping)\n- [02-bootstrapped](https://github.com/jdleesmiller/docker-chat-demo/tree/02-bootstrapped)\n- [03-dependencies](https://github.com/jdleesmiller/docker-chat-demo/tree/03-dependencies)\n- [04-the-app](https://github.com/jdleesmiller/docker-chat-demo/tree/04-the-app)\n- [05-dev-prod](https://github.com/jdleesmiller/docker-chat-demo/tree/05-dev-prod)\n\n## License\n\nThe ISC license:\n\nCopyright (c) 2016–2019, John Lees-Miller\n\nPermission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.\n"
  },
  {
    "path": "docker-compose.yml",
    "content": "version: '3.7'\n\nservices:\n  chat:\n    build:\n      context: .\n      target: development\n    command: npx nodemon index.js\n    ports:\n      - '3000:3000'\n    volumes:\n      - .:/srv/chat\n      - chat_node_modules:/srv/chat/node_modules\n\nvolumes:\n  chat_node_modules:\n"
  },
  {
    "path": "index.html",
    "content": "<!doctype html>\n<html>\n  <head>\n    <title>Socket.IO chat</title>\n    <style>\n      * { margin: 0; padding: 0; box-sizing: border-box; }\n      body { font: 13px Helvetica, Arial; }\n      form { background: #000; padding: 3px; position: fixed; bottom: 0; width: 100%; }\n      form input { border: 0; padding: 10px; width: 90%; margin-right: .5%; }\n      form button { width: 9%; background: rgb(130, 224, 255); border: none; padding: 10px; }\n      #messages { list-style-type: none; margin: 0; padding: 0; }\n      #messages li { padding: 5px 10px; }\n      #messages li:nth-child(odd) { background: #eee; }\n      #messages { margin-bottom: 40px }\n    </style>\n  </head>\n  <body>\n    <ul id=\"messages\"></ul>\n    <form action=\"\">\n      <input id=\"m\" autocomplete=\"off\" /><button>Send</button>\n    </form>\n    <script src=\"https://cdn.socket.io/socket.io-1.2.0.js\"></script>\n    <script src=\"https://code.jquery.com/jquery-1.11.1.js\"></script>\n    <script>\n      $(function () {\n        var socket = io();\n        $('form').submit(function(){\n          socket.emit('chat message', $('#m').val());\n          $('#m').val('');\n          return false;\n        });\n        socket.on('chat message', function(msg){\n          $('#messages').append($('<li>').text(msg));\n          window.scrollTo(0, document.body.scrollHeight);\n        });\n      });\n    </script>\n  </body>\n</html>\n"
  },
  {
    "path": "index.js",
    "content": "var app = require('express')();\nvar http = require('http').Server(app);\nvar io = require('socket.io')(http);\nvar port = process.env.PORT || 3000;\n\napp.get('/', function(req, res){\n  res.sendFile(__dirname + '/index.html');\n});\n\nio.on('connection', function(socket){\n  socket.on('chat message', function(msg){\n    io.emit('chat message', msg);\n  });\n});\n\nhttp.listen(port, function(){\n  console.log('listening on *:' + port);\n});\n"
  },
  {
    "path": "package.json",
    "content": "{\n  \"name\": \"chat\",\n  \"version\": \"1.0.0\",\n  \"description\": \"\",\n  \"main\": \"index.js\",\n  \"scripts\": {\n    \"test\": \"echo \\\"Error: no test specified\\\" && exit 1\"\n  },\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"git+https://github.com/jdleesmiller/docker-chat-demo.git\"\n  },\n  \"keywords\": [],\n  \"author\": \"\",\n  \"license\": \"ISC\",\n  \"bugs\": {\n    \"url\": \"https://github.com/jdleesmiller/docker-chat-demo/issues\"\n  },\n  \"homepage\": \"https://github.com/jdleesmiller/docker-chat-demo#readme\",\n  \"dependencies\": {\n    \"express\": \"^4.17.1\",\n    \"socket.io\": \"^1.7.4\"\n  },\n  \"devDependencies\": {\n    \"nodemon\": \"^1.19.2\"\n  }\n}\n"
  }
]