npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

next-ws

v1.0.1

Published

Add support for WebSockets in Next.js 13 app directory

Downloads

2,649

Readme


🤔 About

Next WS (next-ws) is an advanced Next.js plugin designed to seamlessly integrate WebSocket server functionality into API routes within the app directory. With Next WS, you no longer require a separate server for WebSocket functionality.

It's important to note that this module can only be used when working with a server. Unfortunately, in serverless environments like Vercel, WebSocket servers cannot be used. Additionally, this module was built for the app directory and is incompatible with the older pages directory.

This module is inspired by the now outdated next-plugin-websocket, if you are using an older version of Next.js, that module may work for you.


🏓 Table of Contents


📦 Installation

In order to setup a WebSocket server, Next WS needs to patch your local Next.js installation. Next WS provides a CLI command to do this for you, it will automatically detect your Next.js version and patch it accordingly, however a minimum version of Next.js 13.1.1 is required.

npx next-ws-cli@latest patch

If at any point your local Next.js installation is changed or updated you will need to re-run the patch command.

Once the patch is complete, you will need to install the Next WS package into your project.

npm install next-ws ws
# ws is a peer dependency, you must install it as well

🚓 Verify Patch (Optional)

It is recommended to add the following code to the top level of your next.config.js.

This will verify that Next WS has been patched correctly, and throw an error if it has not. Preventing you from accidentally deploying a broken setup.

require('next-ws/server').verifyPatch();

🚀 Usage

Using Next WS is a breeze, requiring zero configuration. Simply export a SOCKET function from any API route. This function gets called whenever a client connects to the WebSocket server at the respective API path.

The SOCKET function receives three arguments: the WebSocket client, the HTTP request - which you can use to get the URL path, query parameters, and headers - and the WebSocket server that next-ws created.

export function SOCKET(
  client: import('ws').WebSocket,
  request: import('http').IncomingMessage,
  server: import('ws').WebSocketServer,
) {
  // ...
}

With this straightforward setup, you can fully leverage the capabilities of Next WS and efficiently handle WebSocket connections within your Next.js application.


🌀 Example

📁 Server

Create an API route anywhere within the app directory, and export a SOCKET function from it, below is an example of a simple echo server, which sends back any message it receives.

// app/api/ws/route.ts (can be any route file in the app directory)
export function SOCKET(
  client: import('ws').WebSocket,
  request: import('http').IncomingMessage,
  server: import('ws').WebSocketServer,
) {
  console.log('A client connected!');

  client.on('message', message => {
    client.send(message);
  });
  
  client.on('close', () => {
    console.log('A client disconnected!');
  });
}

You are pretty much done at this point, you can now connect to the WebSocket server using the native WebSocket API in the browser.

📁 Client

To make it easier to connect to your new WebSocker server, Next WS also provides some client-side utilities. These are completely optional, you can use your own implementation if you wish.

// layout.tsx
'use client';

import { WebSocketProvider } from 'next-ws/client';

export default function Layout() {
  return <WebSocketProvider
    url="ws://localhost:3000/api/ws"
    // ... other props
  >
    {...}
  </WebSocketProvider>;
}

The following is the props interface for the WebSocketProvider component, containing all the available options.

interface WebSocketProviderProps {
  children: React.ReactNode;

  /** The URL for the WebSocket to connect to. */
  url: string;
  /** The subprotocols to use. */
  protocols?: string[] | string;
  /** The binary type to use. */
  binaryType?: BinaryType;
}

Now you can use the useWebSocket hook to get the WebSocket instance, and send and receive messages.

// page.tsx
'use client';

import { useWebSocket } from 'next-ws/client';
import { useCallback, useEffect, useState } from 'react';

export default function Page() {
  const ws = useWebSocket();
  //    ^? WebSocket on the client, null on the server

  const [value, setValue] = useState('');
  const [message, setMessage] = useState<string | null>(null);

  const onMessage = useCallback(
    (event: MessageEvent<Blob>) =>
      void event.data.text().then(setMessage),
    [],
  );
  
  useEffect(() => {
    ws?.addEventListener('message', onMessage);
    return () => ws?.removeEventListener('message', onMessage);
  }, [onMessage, ws]);

  return <>
    <input
      type="text"
      value={value}
      onChange={event => setValue(event.target.value)}
    />

    <button onClick={() => ws?.send(value)}>
      Send message to server
    </button>

    <p>
      {message === null
        ? 'Waiting to receive message...'
        : `Got message: ${message}`}
    </p>
  </>;
}