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-nuxtOutput:
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)"Socket.io
Add socket.io from NPM and SASS
npm i -S socket.io axios
npm i -D node-sass sass-loaderApply 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)
}server/index.jsBecomes:
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()
server/index.jsStart the server and check socket.io
npm run devIntegrating 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
}
api/router/message.jsAPI: 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
}
api/index.jsConnect Express api Router
app.use('/api', require('../api')({ Router, io }))server/index.jsBecomes:
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()
server/index.jsAdd local script
export default {
head() {
return {
script: [{ src: '/socket.io/socket.io.js' }]
}
}
}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>
pages/index.vueAlternative global settings
export default {
head: {
script: [
{ src: '/socket.io/socket.io.js' }
]
}
}nuxt.config.jsPage Layout
Store: messages
import Vue from 'vue'
const state = Vue.observable({
messages: []
}),
methods = {
onMessage(message) {
state.messages.push(message)
}
}
export { state, methods }
lib/store/storeMessages.jsPage
<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>pages/index.vueFastifyJS
Generate Nuxt Fastify app from command
npx create-nuxt-app chat-fastify-nuxtOutput:
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-loaderApply socket.io
We can use fastify.server to connect our socket.io.
Like so:
const io = require('socket.io')(fastify.server)server/index.jsconst { 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()
server/index.jsStart the server and check socket.io
npm run devIntegrating 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
})
}
api/routes/message.jsApi: 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 })
})
})
}
api/index.jsConnect fastify api Router
fastify.register(require('../api')(io), { prefix: '/api' })
fastify.setNotFoundHandler(({ req }, { res }) => nuxt.render(req, res))server/index.jsReplace: 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()
server/index.jsAdd local script
export default {
head() {
return {
script: [{ src: '/socket.io/socket.io.js' }]
}
}
}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>
pages/index.vueAlternative global settings
export default {
head: {
script: [
{ src: '/socket.io/socket.io.js' }
]
}
}nuxt.config.jsPage Layout
Store: messages
import Vue from 'vue'
const state = Vue.observable({
messages: []
}),
methods = {
onMessage(message) {
state.messages.push(message)
}
}
export { state, methods }
lib/store/storeMessages.jsPage
<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>
pages/index.vueNext
Other Nuxt SSR configurations
Babel sourceType
Make CommonJS and ES modules a love couple.
module.exports = {
build: {
babel: {
sourceType: 'unambiguous'
}
}
}
nuxt.config.js