Boilerplates for Express and Fastify .
ExpressJS Understanding the basic way for enabling socket.io in Nuxt Express app and use Vue.observable as global store.
Generate Nuxt Express app from command npx create-nuxt-app chat-express-nuxt
Output:
create-nuxt-app v2.15.0
✨ Generating Nuxt.js project in chat-express-nuxt
? Project name chat-express-nuxt
? Project description Chat Express Nuxt
? Author name Harianto
? Choose programming language JavaScript
? Choose the package manager Npm
? Choose UI framework None
? Choose custom server framework Express
? Choose Nuxt.js modules Axios, Progressive Web App (PWA) Support
? Choose linting tools Prettier
? Choose test framework None
? Choose rendering mode Universal (SSR)
? Choose development tools jsconfig.json (Recommended for VS Code)
- chat-express-nuxt - Chat Express Nuxt - Harianto - JavaScript - npm - None - Express - Axios, PWA - Prettier - None - SSR - jsconfig.json Optional cd chat-express-nuxt
# Save Node version to a file
node -v > .nvmrc
# optional
git add .
git commit -avm "INIT Express PWA SSR Nuxt - Node $(node -v) | NPM $(npm -v)"
Always save node & npm versions in your projects.
Socket.io Add socket.io from NPM and SASS
npm i -S socket.io axios
npm i -D node-sass sass-loader
Apply socket.io We require http and use that to create server instead of express from the default generated project. I highlight the lines of code in the snippet below:
const http = require('http'),
express = require('express'),
app = express(),
{ Router } = express,
server = http.createServer(app),
io = require('socket.io')(server)
async function start() {
app.use(express.json()) // Receive Header: Content-Type: application/json
app.use(express.urlencoded({ extended: false })) // Parse Body to JSON
app.use(nuxt.render)
// Listen the server
server.listen(port, host)
}
Snippet: server/index.js
Becomes:
const http = require('http'),
express = require('express'),
app = express(),
{ Router } = express,
server = http.createServer(app),
io = require('socket.io')(server)
const consola = require('consola')
const { Nuxt, Builder } = require('nuxt')
// Import and Set Nuxt.js options
const config = require('../nuxt.config.js')
config.dev = process.env.NODE_ENV !== 'production'
async function start() {
// Init Nuxt.js
const nuxt = new Nuxt(config)
const { host, port } = nuxt.options.server
await nuxt.ready()
// Build only in dev mode
if (config.dev) {
const builder = new Builder(nuxt)
await builder.build()
}
app.use(express.json())
app.use(express.urlencoded({ extended: false }))
// // Give nuxt middleware to express
app.use(nuxt.render)
// Listen the server
server.listen(port, host)
consola.ready({
message: `Server listening on http://${host}:${port}`,
badge: true
})
}
start()
File: server/index.js
Start the server and check socket.io npm run dev
Integrating socket.io Router: message module.exports = ({ Router, io }) => {
const router = Router()
/* GET users listing. */
router
.get('/', function(req, res, next) {
res.json({
message: true
})
})
.post('/', (req, res) => {
io.emit('chat-message', { ...req.body, id: 'POST' })
res.json(req.body)
})
return router
}
File: api/router/message.js
API: index module.exports = ({ Router, io }) => {
const router = Router()
/* GET users listing. */
router
.get('/', function(req, res, next) {
res.json({
api: true
})
})
// Router: message
.use('/message', require('./router/message')({ Router, io }))
io.on('connection', socket => {
console.log('Socket Connect:', { id: socket.id })
io.emit('chat-message', { id: socket.id, status: 'ENTERS ROOM' })
socket.on('disconnect', message => {
console.log({ id: socket.id, message })
socket.broadcast.emit('chat-message', { id: socket.id, status: 'LEFT' })
})
socket.on('chat-message', msg => {
console.log('chat-message:', msg)
io.emit('chat-message', { id: socket.id, message: msg })
})
})
return router
}
File: api/index.js
Connect Express api Router app.use('/api', require('../api')({ Router, io }))
Snippet: server/index.js
Becomes:
const http = require('http'),
express = require('express'),
app = express(),
{ Router } = express,
server = http.createServer(app),
io = require('socket.io')(server)
const consola = require('consola')
const { Nuxt, Builder } = require('nuxt')
// Import and Set Nuxt.js options
const config = require('../nuxt.config.js')
config.dev = process.env.NODE_ENV !== 'production'
async function start() {
// Init Nuxt.js
const nuxt = new Nuxt(config)
const { host, port } = nuxt.options.server
await nuxt.ready()
// Build only in dev mode
if (config.dev) {
const builder = new Builder(nuxt)
await builder.build()
}
app.use(express.json())
app.use(express.urlencoded({ extended: false }))
app.use('/api', require('../api')({ Router, io }))
// Give nuxt middleware to express
app.use(nuxt.render)
// Listen the server
server.listen(port, host)
consola.ready({
message: `Server listening on http://${host}:${port}`,
badge: true
})
}
start()
File: server/index.js
Add local script export default {
head() {
return {
script: [{ src: '/socket.io/socket.io.js' }]
}
}
}
Snippet: pages/index.vue
<template>
<div class="container">
<div>
<logo />
<h1 class="title">chat-express-nuxt</h1>
<h2 class="subtitle">Chat Express Nuxt</h2>
<div class="links">
<a href="https://nuxtjs.org/" target="_blank" class="button--green">Documentation</a>
<a href="https://github.com/nuxt/nuxt.js" target="_blank" class="button--grey">GitHub</a>
</div>
</div>
</div>
</template>
<script>
import Logo from '~/components/Logo.vue'
export default {
head() {
return {
script: [{ src: '/socket.io/socket.io.js' }]
}
},
components: {
Logo
}
}
</script>
<style>
.container {
margin: 0 auto;
min-height: 100vh;
display: flex;
justify-content: center;
align-items: center;
text-align: center;
}
.title {
font-family: 'Quicksand', 'Source Sans Pro', -apple-system, BlinkMacSystemFont,
'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
display: block;
font-weight: 300;
font-size: 100px;
color: #35495e;
letter-spacing: 1px;
}
.subtitle {
font-weight: 300;
font-size: 42px;
color: #526488;
word-spacing: 5px;
padding-bottom: 15px;
}
.links {
padding-top: 15px;
}
</style>
File: pages/index.vue
Alternative global settings export default {
head: {
script: [
{ src: '/socket.io/socket.io.js' }
]
}
}
Snippet: nuxt.config.js
Page Layout Store: messages import Vue from 'vue'
const state = Vue.observable({
messages: []
}),
methods = {
onMessage(message) {
state.messages.push(message)
}
}
export { state, methods }
File: lib/store/storeMessages.js
Page <template>
<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>
</template>
<script>
import Logo from '~/components/Logo.vue'
import { state, methods } from '~/lib/store/storeMessages'
import axios from 'axios'
const post = (url, data) => axios.post(url, data).then(({ data }) => data)
let socket
export default {
head() {
return {
script: [{ src: '/socket.io/socket.io.js' }]
}
},
components: {
Logo
},
data: () => ({
title: 'Chat Nuxt App',
formData: {
message: ''
}
}),
computed: {
messages() {
return state.messages
}
},
methods: {
onEmit() {
const { formData } = this
socket.emit('chat-message', formData.message)
console.log('onEmit:', formData.message, socket.id)
formData.message = ''
},
onPost() {
const { formData } = this,
url = '/api/message'
console.log('onPost:', formData.message)
post(url, {
id: socket.id,
message: formData.message
})
.then(console.log.bind(console, 'RESPONSE:'))
.catch(console.error.bind(console, 'FAIL - onPost:'))
formData.message = ''
}
},
// Life Cycle Hooks
mounted() {
socket = io()
socket.on('chat-message', methods.onMessage)
}
}
</script>
<style lang="scss">
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>
File: pages/index.vue
FastifyJS Generate Nuxt Fastify app from command npx create-nuxt-app chat-fastify-nuxt
Output:
create-nuxt-app v2.15.0
✨ Generating Nuxt.js project in chat-fastify-nuxt
? Project name chat-fastify-nuxt
? Project description Chat Fastify Nuxt
? Author name Harianto
? Choose programming language JavaScript
? Choose the package manager Npm
? Choose UI framework None
? Choose custom server framework Fastify
? Choose Nuxt.js modules Axios, Progressive Web App (PWA) Support
? Choose linting tools Prettier
? Choose test framework None
? Choose rendering mode Universal (SSR)
? Choose development tools jsconfig.json (Recommended for VS Code)
- chat-fastify-nuxt - Chat Fastify Nuxt - Harianto - JavaScript - Npm - None - Fastify - Axios, WPA - Prettier - None - SSR - jsconfig.json Optional cd chat-fastify-nuxt
# Save Node version to a file
node -v > .nvmrc
# optional
git add .
git commit -avm "INIT Fastify PWA SSR Nuxt - Node $(node -v) | NPM $(npm -v)"
Socket.io Add socket.io from NPM and SASS
npm i -S socket.io axios
npm i -D node-sass sass-loader
Apply socket.io We can use fastify.server
to connect our socket.io . Like so:
const io = require('socket.io')(fastify.server)
Snippet: server/index.js
const { Nuxt, Builder } = require('nuxt')
const fastify = require('fastify')({
logger: true
}),
io = require('socket.io')(fastify.server)
// Import and Set Nuxt.js options
const config = require('../nuxt.config.js')
config.dev = process.env.NODE_ENV !== 'production'
async function start() {
// Instantiate nuxt.js
const nuxt = new Nuxt(config)
const {
host = process.env.HOST || '127.0.0.1',
port = process.env.PORT || 3000
} = nuxt.options.server
await nuxt.ready()
// Build only in dev mode
if (config.dev) {
const builder = new Builder(nuxt)
await builder.build()
}
fastify.use(nuxt.render)
fastify.listen(port, host, (err, address) => {
if (err) {
fastify.log.error(err)
process.exit(1)
}
})
}
start()
File: server/index.js
Start the server and check socket.io npm run dev
Integrating socket.io Router: message module.exports = io => async (fastify, options) => {
fastify
// Route: /
.get('/', async () => ({ message: true }))
.post('/', {}, async (request, reply) => {
io.emit('chat-message', {
...request.body,
id: `POST: ${request.body.id}`
})
return request.body
})
}
File: api/routes/message.js
Api: index module.exports = io => async (fastify, options) => {
fastify
.get('/', async () => ({ api: true }))
// register
.register(require('./routes/message')(io), { prefix: '/message' })
io.on('connection', socket => {
console.log('Socket Connect:', { id: socket.id })
io.emit('chat-message', { id: socket.id, status: 'ENTERS ROOM' })
socket.on('disconnect', message => {
console.log({ id: socket.id, message })
socket.broadcast.emit('chat-message', { id: socket.id, status: 'LEFT' })
})
socket.on('chat-message', msg => {
console.log('chat-message:', msg)
io.emit('chat-message', { id: socket.id, message: msg })
})
})
}
File: api/index.js
Connect fastify api Router fastify.register(require('../api')(io), { prefix: '/api' })
fastify.setNotFoundHandler(({ req }, { res }) => nuxt.render(req, res))
Snippet: server/index.js
Replace: fastify.use(nuxt.render)
const { Nuxt, Builder } = require('nuxt')
const fastify = require('fastify')({
logger: true
}),
io = require('socket.io')(fastify.server)
// Import and Set Nuxt.js options
const config = require('../nuxt.config.js')
config.dev = process.env.NODE_ENV !== 'production'
async function start() {
// Instantiate nuxt.js
const nuxt = new Nuxt(config)
const {
host = process.env.HOST || '127.0.0.1',
port = process.env.PORT || 3000
} = nuxt.options.server
await nuxt.ready()
// Build only in dev mode
if (config.dev) {
const builder = new Builder(nuxt)
await builder.build()
}
fastify.register(require('../api')(io), { prefix: '/api' })
fastify.setNotFoundHandler(({ req }, { res }) => nuxt.render(req, res))
fastify.listen(port, host, (err, address) => {
if (err) {
fastify.log.error(err)
process.exit(1)
}
})
}
start()
File: server/index.js
Add local script export default {
head() {
return {
script: [{ src: '/socket.io/socket.io.js' }]
}
}
}
Snippet: pages/index.vue
<template>
<div class="container">
<div>
<logo />
<h1 class="title">chat-nuxt</h1>
<h2 class="subtitle">Chat Nuxt</h2>
<div class="links">
<a href="https://nuxtjs.org/" target="_blank" class="button--green">Documentation</a>
<a href="https://github.com/nuxt/nuxt.js" target="_blank" class="button--grey">GitHub</a>
</div>
</div>
</div>
</template>
<script>
import Logo from '~/components/Logo.vue'
export default {
head() {
return {
script: [{ src: '/socket.io/socket.io.js' }]
}
},
components: {
Logo
}
}
</script>
<style>
.container {
margin: 0 auto;
min-height: 100vh;
display: flex;
justify-content: center;
align-items: center;
text-align: center;
}
.title {
font-family: 'Quicksand', 'Source Sans Pro', -apple-system, BlinkMacSystemFont,
'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
display: block;
font-weight: 300;
font-size: 100px;
color: #35495e;
letter-spacing: 1px;
}
.subtitle {
font-weight: 300;
font-size: 42px;
color: #526488;
word-spacing: 5px;
padding-bottom: 15px;
}
.links {
padding-top: 15px;
}
</style>
File: pages/index.vue
Alternative global settings export default {
head: {
script: [
{ src: '/socket.io/socket.io.js' }
]
}
}
Snippet: nuxt.config.js
Page Layout Store: messages import Vue from 'vue'
const state = Vue.observable({
messages: []
}),
methods = {
onMessage(message) {
state.messages.push(message)
}
}
export { state, methods }
File: lib/store/storeMessages.js
Page <template>
<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>
</template>
<script>
import Logo from '~/components/Logo.vue'
import { state, methods } from '~/lib/store/storeMessages'
import axios from 'axios'
const post = (url, data) => axios.post(url, data).then(({ data }) => data)
let socket
export default {
head() {
return {
script: [{ src: '/socket.io/socket.io.js' }]
}
},
components: {
Logo
},
data: () => ({
title: 'Chat Nuxt App',
formData: {
message: ''
}
}),
computed: {
messages() {
return state.messages
}
},
methods: {
onEmit() {
const { formData } = this
socket.emit('chat-message', formData.message)
console.log('onEmit:', formData.message, socket.id)
formData.message = ''
},
onPost() {
const { formData } = this,
url = '/api/message'
console.log('onPost:', formData.message)
post(url, {
id: socket.id,
message: formData.message
})
.then(console.log.bind(console, 'RESPONSE:'))
.catch(console.error.bind(console, 'FAIL - onPost:'))
formData.message = ''
}
},
// Life Cycle Hooks
mounted() {
socket = io()
socket.on('chat-message', methods.onMessage)
}
}
</script>
<style lang="scss">
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>
File: pages/index.vue
Next Other Nuxt SSR configurations
Babel sourceType Make CommonJS and ES modules a love couple.
module.exports = {
build: {
babel: {
sourceType: 'unambiguous'
}
}
}
Snippet: nuxt.config.js