I'm currently working on a TypeScript project that is using Socket.io to communicate between a Next.js frontend and a custom Express server backend.
While setting up Socket.io I struggled to find documentation explaining how you could set up Socket.io in a TypeScript project using the ES6 import
syntax rather than require
. It was even more difficult to find anything that explained how it should all fit together with Next.js.
And so this post was born...
If you're starting from scratch...
If you want to make a TypeScript/Express custom server Next.js project, mine was created by combining the custom Express Server example and custom TypeScript Server example located in the Next.js repository.
First I created the project using the command npx create-next-app --example custom-server-typescript
to create the custom TypeScript server. Then I retrofitted Express into it by looking at the custom Express server example. The resulting server.ts
is at the bottom of this post.
Why didn't I follow another example?
Most of the examples I saw online want you to do something like the following:
import express from 'express';
const app = express();
const server = require('http').Server(app);
const io = require('socket.io')(server);
But I didn't want two or any random require
statements in my TypeScript code if I thought they could be avoided.
My server.ts
with only ES6 import
The dependencies you need (In addition to Next.js/React/TypeScript):
npm install -s express @types/express socket-io
The code you've been waiting for:
import express, { Express, Request, Response } from 'express';
import * as http from 'http';
import next, { NextApiHandler } from 'next';
import * as socketio from 'socket.io';
const port: number = parseInt(process.env.PORT || '3000', 10);
const dev: boolean = process.env.NODE_ENV !== 'production';
const nextApp = next({ dev });
const nextHandler: NextApiHandler = nextApp.getRequestHandler();
nextApp.prepare().then(async() => {
const app: Express = express();
const server: http.Server = http.createServer(app);
const io: socketio.Server = new socketio.Server();
io.attach(server);
app.get('/hello', async (_: Request, res: Response) => {
res.send('Hello World')
});
io.on('connection', (socket: socketio.Socket) => {
console.log('connection');
socket.emit('status', 'Hello from Socket.io');
socket.on('disconnect', () => {
console.log('client disconnected');
})
});
app.all('*', (req: any, res: any) => nextHandler(req, res));
server.listen(port, () => {
console.log(`> Ready on http://localhost:${port}`);
});
});
server.ts
explanation
The main difference between my server.ts
and the ones produced by the Next.js examples is the use of the http
module to run the server whereas before Express ran it. This is required so that Socket.io can attach to the server once it's setup.
Additional changes:
- Changed
app
to benextApp
so that it is clearer that it was anext
app, also changedhandler
tonextHandler
for the same reason. In addition, it's the convention to use theapp
variable with Express. - Used
http.CreateServer()
rather thanconst server = require("http").Server(app);
to create the HTTP server. - Used
io.attach()
to attach to the HTTP server rather than using require e.g.const io = require("socket.io")(server);
.
Summary
This post demonstrates how to use Socket.io with a Next.js custom server using ES6 import
rather than require
.
If this post helped you drop me a reaction! Found something I could improve? Let me know in the comments.
Thanks for reading!