docs: add example with Next.js (with app router)
4
.github/workflows/ci.yml
vendored
@@ -55,8 +55,8 @@ jobs:
|
||||
- webpack-build-server
|
||||
- basic-crud-application/angular-client
|
||||
- basic-crud-application/vue-client
|
||||
- nextjs-pages-router-api-route
|
||||
- nextjs-pages-router-custom-server
|
||||
- nextjs-pages-router
|
||||
- nextjs-app-router
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
|
||||
@@ -16,11 +16,7 @@ bun dev
|
||||
|
||||
Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.
|
||||
|
||||
You can start editing the page by modifying `pages/index.js`. The page auto-updates as you edit the file.
|
||||
|
||||
[API routes](https://nextjs.org/docs/api-routes/introduction) can be accessed on [http://localhost:3000/api/hello](http://localhost:3000/api/hello). This endpoint can be edited in `pages/api/hello.js`.
|
||||
|
||||
The `pages/api` directory is mapped to `/api/*`. Files in this directory are treated as [API routes](https://nextjs.org/docs/api-routes/introduction) instead of React pages.
|
||||
You can start editing the page by modifying `app/page.js`. The page auto-updates as you edit the file.
|
||||
|
||||
This project uses [`next/font`](https://nextjs.org/docs/basic-features/font-optimization) to automatically optimize and load Inter, a custom Google Font.
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
/** @type {import('next').NextConfig} */
|
||||
const nextConfig = {
|
||||
reactStrictMode: true,
|
||||
};
|
||||
const nextConfig = {};
|
||||
|
||||
export default nextConfig;
|
||||
@@ -1,7 +1,8 @@
|
||||
{
|
||||
"name": "nextjs-pages-router-api-route",
|
||||
"name": "nextjs-app-router",
|
||||
"version": "0.1.0",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "next dev",
|
||||
"build": "next build",
|
||||
|
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 1.3 KiB |
|
Before Width: | Height: | Size: 629 B After Width: | Height: | Size: 629 B |
@@ -1,5 +1,4 @@
|
||||
import { createServer } from "http";
|
||||
import { parse } from "url";
|
||||
import next from "next";
|
||||
import { Server } from "socket.io";
|
||||
|
||||
@@ -8,25 +7,12 @@ const hostname = "localhost";
|
||||
const port = 3000;
|
||||
// when using middleware `hostname` and `port` must be provided below
|
||||
const app = next({ dev, hostname, port });
|
||||
const handle = app.getRequestHandler();
|
||||
const handler = app.getRequestHandler();
|
||||
|
||||
app.prepare().then(() => {
|
||||
const httpServer = createServer(async (req, res) => {
|
||||
try {
|
||||
const parsedUrl = parse(req.url, true);
|
||||
const { pathname, query } = parsedUrl;
|
||||
const httpServer = createServer(handler);
|
||||
|
||||
await handle(req, res, parsedUrl);
|
||||
} catch (err) {
|
||||
console.error("Error occurred handling", req.url, err);
|
||||
res.statusCode = 500;
|
||||
res.end("internal server error");
|
||||
}
|
||||
});
|
||||
|
||||
const io = new Server(httpServer, {
|
||||
pingInterval: 2000
|
||||
});
|
||||
const io = new Server(httpServer);
|
||||
|
||||
io.on("connection", (socket) => {
|
||||
// ...
|
||||
|
Before Width: | Height: | Size: 25 KiB After Width: | Height: | Size: 25 KiB |
17
examples/nextjs-app-router/src/app/layout.js
Normal file
@@ -0,0 +1,17 @@
|
||||
import { Inter } from "next/font/google";
|
||||
import "./globals.css";
|
||||
|
||||
const inter = Inter({ subsets: ["latin"] });
|
||||
|
||||
export const metadata = {
|
||||
title: "Create Next App",
|
||||
description: "Generated by create next app",
|
||||
};
|
||||
|
||||
export default function RootLayout({ children }) {
|
||||
return (
|
||||
<html lang="en">
|
||||
<body className={inter.className}>{children}</body>
|
||||
</html>
|
||||
);
|
||||
}
|
||||
@@ -1,11 +1,9 @@
|
||||
import Head from "next/head";
|
||||
import Image from "next/image";
|
||||
import { Inter } from "next/font/google";
|
||||
import styles from "@/styles/Home.module.css";
|
||||
import { useEffect, useState } from "react";
|
||||
import { socket } from "@/socket";
|
||||
"use client";
|
||||
|
||||
const inter = Inter({ subsets: ["latin"] });
|
||||
import Image from "next/image";
|
||||
import styles from "./page.module.css";
|
||||
import { useEffect, useState } from "react";
|
||||
import { socket } from "../socket";
|
||||
|
||||
export default function Home() {
|
||||
const [isConnected, setIsConnected] = useState(false);
|
||||
@@ -40,17 +38,9 @@ export default function Home() {
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<>
|
||||
<Head>
|
||||
<title>Create Next App</title>
|
||||
<meta name="description" content="Generated by create next app" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<link rel="icon" href="/favicon.ico" />
|
||||
</Head>
|
||||
<div>
|
||||
<p>Status: { isConnected ? "connected" : "disconnected" }</p>
|
||||
<p>Transport: { transport }</p>
|
||||
</div>
|
||||
</>
|
||||
<div>
|
||||
<p>Status: { isConnected ? "connected" : "disconnected" }</p>
|
||||
<p>Transport: { transport }</p>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -42,8 +42,8 @@
|
||||
.grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(4, minmax(25%, auto));
|
||||
max-width: var(--max-width);
|
||||
width: 100%;
|
||||
max-width: 100%;
|
||||
width: var(--max-width);
|
||||
}
|
||||
|
||||
.card {
|
||||
@@ -70,6 +70,7 @@
|
||||
font-size: 0.9rem;
|
||||
line-height: 1.5;
|
||||
max-width: 30ch;
|
||||
text-wrap: balance;
|
||||
}
|
||||
|
||||
.center {
|
||||
5
examples/nextjs-app-router/src/socket.js
Normal file
@@ -0,0 +1,5 @@
|
||||
"use client";
|
||||
|
||||
import { io } from "socket.io-client";
|
||||
|
||||
export const socket = io();
|
||||
@@ -1,5 +0,0 @@
|
||||
import "@/styles/globals.css";
|
||||
|
||||
export default function App({ Component, pageProps }) {
|
||||
return <Component {...pageProps} />;
|
||||
}
|
||||
@@ -1,45 +0,0 @@
|
||||
import { Server } from "socket.io";
|
||||
import { Server as Engine } from "engine.io";
|
||||
|
||||
const engine = new Engine({
|
||||
pingInterval: 2000
|
||||
});
|
||||
|
||||
const io = new Server();
|
||||
|
||||
io.bind(engine);
|
||||
|
||||
io.on("connection", (socket) => {
|
||||
// ...
|
||||
});
|
||||
|
||||
let once = true;
|
||||
|
||||
export default function handler(req, res) {
|
||||
if (once) {
|
||||
once = false;
|
||||
const server = req.socket.server;
|
||||
|
||||
// the default listener closes the websocket connection if the path does not match "/_next/webpack-hmr"
|
||||
// see https://github.com/vercel/next.js/blob/f9d73cc2fa710a7ba90ee28f7783a8f05ea62b3a/packages/next/src/server/lib/router-server.ts#L669-L671
|
||||
const defaultListener = server.listeners("upgrade")[0];
|
||||
server.removeAllListeners("upgrade");
|
||||
|
||||
server.on("upgrade", (req, socket, head) => {
|
||||
if (req.url.startsWith("/api/socket.io")) {
|
||||
engine.handleUpgrade(req, socket, head);
|
||||
} else {
|
||||
defaultListener.call(server, req, socket, head);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
engine.handleRequest(req, res);
|
||||
}
|
||||
|
||||
export const config = {
|
||||
api: {
|
||||
bodyParser: false, // prevents body parsing
|
||||
externalResolver: true, // prevents "this may result in stalled requests" warnings
|
||||
},
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
import { io } from "socket.io-client";
|
||||
|
||||
const isBrowser = typeof window !== "undefined";
|
||||
|
||||
// only create the Socket.IO client on the client side (no ssr)
|
||||
export const socket = isBrowser ? io({
|
||||
path: "/api/socket.io",
|
||||
addTrailingSlash: false,
|
||||
}) : {};
|
||||
@@ -1,13 +0,0 @@
|
||||
import { Html, Head, Main, NextScript } from "next/document";
|
||||
|
||||
export default function Document() {
|
||||
return (
|
||||
<Html lang="en">
|
||||
<Head />
|
||||
<body>
|
||||
<Main />
|
||||
<NextScript />
|
||||
</body>
|
||||
</Html>
|
||||
);
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
// Next.js API route support: https://nextjs.org/docs/api-routes/introduction
|
||||
|
||||
export default function handler(req, res) {
|
||||
res.status(200).json({ name: "John Doe" });
|
||||
}
|
||||
@@ -12,6 +12,7 @@
|
||||
# next.js
|
||||
/.next/
|
||||
/out/
|
||||
/src/.next/
|
||||
|
||||
# production
|
||||
/build
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"name": "nextjs-pages-router-custom-server",
|
||||
"name": "nextjs-pages-router",
|
||||
"version": "0.1.0",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
|
Before Width: | Height: | Size: 25 KiB After Width: | Height: | Size: 25 KiB |
|
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 1.3 KiB |
|
Before Width: | Height: | Size: 629 B After Width: | Height: | Size: 629 B |
29
examples/nextjs-pages-router/server.js
Normal file
@@ -0,0 +1,29 @@
|
||||
import { createServer } from "http";
|
||||
import next from "next";
|
||||
import { Server } from "socket.io";
|
||||
|
||||
const dev = process.env.NODE_ENV !== "production";
|
||||
const hostname = "localhost";
|
||||
const port = 3000;
|
||||
// when using middleware `hostname` and `port` must be provided below
|
||||
const app = next({ dev, hostname, port });
|
||||
const handler = app.getRequestHandler();
|
||||
|
||||
app.prepare().then(() => {
|
||||
const httpServer = createServer(handler);
|
||||
|
||||
const io = new Server(httpServer);
|
||||
|
||||
io.on("connection", (socket) => {
|
||||
// ...
|
||||
});
|
||||
|
||||
httpServer
|
||||
.once("error", (err) => {
|
||||
console.error(err);
|
||||
process.exit(1);
|
||||
})
|
||||
.listen(port, () => {
|
||||
console.log(`> Ready on http://${hostname}:${port}`);
|
||||
});
|
||||
});
|
||||
@@ -18,7 +18,7 @@ export default function Home() {
|
||||
|
||||
function onConnect() {
|
||||
setIsConnected(true);
|
||||
setTransport(socket.io.engine.transport.name || "N/A");
|
||||
setTransport(socket.io.engine.transport.name);
|
||||
|
||||
socket.io.engine.on("upgrade", (transport) => {
|
||||
setTransport(transport.name);
|
||||