Routes

module.exports = ({ Router, io }) => {
	const router = Router()
	/* GET users listing. */
	router
		.get('/', function (req, res, next) {
			res.render('message', { title: 'Message Page' })
		})
		.post('/', (req, res) => {
			io.emit('client-message', { ...req.body, id: 'POST' })
			res.json(req.body)
		})

	return router
}
File: routes/io-message.js

App

module.exports = ({ express, app, io }) => {
	const { Router } = express

	app.use('/message', require('./routes/io-message')({ Router, io }))
	
	io.on('connection', socket => {
		console.log('Socket Connect:', { id: socket.id })
		socket.on('disconnect', log => {
			console.log({ id: socket.id, log })
		})

		socket.on('server-message', msg => {
			console.log('message:', { msg })
			io.emit('client-message', { id: socket.id, message: msg })
		})

	})

	return app
}
Snippet: app.js

Server

#!/usr/bin/env node

var http = require('http'),
	express = require('express'),
	app = express()

/**
 * Create HTTP server.
 */

var server = http.createServer(app)
var io = require('socket.io')(server)
require('../app')({ express, app, io })

/**
 * Listen on provided port, on all network interfaces.
 */

server.listen(port)
Snippet: bin/www

View

<style rel="stylesheet/less" type="text/less">
	body {
		margin: 0;
		padding: 0;
	}

	.app-tpl {
		height: ~'calc(100vh)';
		overflow-y: auto;
		overflow-x: hidden;
		background-color: rgb(248, 239, 201);
	}

	.messages {
		list-style: none;
		margin: 0;
		padding: 0;

		li {
			&:nth-child(odd) {
				background-color: yellow;
			}
		}
	}
</style>
<script src="//cdnjs.cloudflare.com/ajax/libs/less.js/2.7.1/less.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.6.11/vue.js"></script>
<script src="/socket.io/socket.io.js"></script>

<script type="text/html" id="app-tpl">
	<div class="app-tpl">
	       <h1>{{title}}</h1>
	       <input v-model="formData.message" placeholder="Message" />
		<div>
			<button @click="onEmit">Emit Message</button>
			<button @click="onPost">Post Message</button>
		</div>
		<ul class="messages">
			<li v-for="msg in messages"><pre v-text="msg" /></li>
		</ul>
	</div>
</script>

<script>
	var socket = io(),
		el = document.currentScript

	const storeMessages = {
			state: Vue.observable({
				messages: []
			}),
			methods: {
				onMessage(message) {
					this.state.messages.unshift(message)
				}
			}
		},
		App = new Vue({
			template: '#app-tpl',
			data: () => ({
				formData: {
					message: ''
				}
			}),
			computed: {
				messages() {
					return storeMessages.state.messages
				}
			},
			methods: {
				onEmit() {
					const { formData } = this
					socket.emit('server-message', formData.message)
					console.log('onEmit:', formData.message)
					formData.message = ''
				},
				onPost() {
					const { formData } = this,
						url = '//localhost:3000/message'
					console.log('onPost:', formData.message)
					fetch(url, {
						method: 'POST',
						body: JSON.stringify(formData)
					})
						.then(res => res.json())
						.then(console.log.bind(console, 'RESPONSE:'))
						.catch(console.error.bind(console, 'FAIL - onPost:'))
					formData.message = ''
				}
			}
		})

	App.$mount(el)

	socket.on(
		'client-message',
		storeMessages.methods.onMessage.bind(storeMessages)
	)
</script>
File: views/message.hbs