Skip to content

Commit

Permalink
+ client-side.md
Browse files Browse the repository at this point in the history
  • Loading branch information
palkan committed Oct 9, 2024
1 parent 8c95b34 commit 6307ead
Show file tree
Hide file tree
Showing 3 changed files with 199 additions and 6 deletions.
8 changes: 2 additions & 6 deletions docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,18 +26,14 @@ Make your real-time communication fast and [reliable](./anycable-go/reliable_str

## Latest updates 🆕

- **2024-10-08**: [File-based configuration (`anycable.toml`)](./anycable-go/configuration.md)

- **2024-03-12**: [Standalone mode via signed streams](./anycable-go/signed_streams.md)

- **2023-11-08**: [AnyCable for serverlsess JavaScript applications](./guides/serverless.md)

- **2023-11-03**: [NATS JetStream broker](./anycable-go/reliable_streams.md#nats) support is added to AnyCable-Go v1.4.7+.

- **2023-10-13**: [Batch broadcasts](./ruby/broadcast_adapters.md#broadcast-options) and [broadcasting to others](./rails/getting_started.md#action-cable-extensions).

- **2023-09-07**: [Server-sent events](./anycable-go/sse.md) suppport is added to AnyCable-Go 1.4.4+.

- **2023-08-09**: `pong` command is added to the [extended Action Cable protocol](./misc/action_cable_protocol.md#action-cable-extended-protocol) and is supported by AnyCable-Go 1.4.3+.

- **2023-08-04**: [Slow drain mode for disconnecting clients on shutdown <img class='pro-badge' src='/assets/pro.svg' alt='pro' />](./anycable-go/configuration.md#slow-drain-mode)

- **2023-07-05**: [Reliable streams](./anycable-go/reliable_streams.md)
Expand Down
1 change: 1 addition & 0 deletions docs/_sidebar.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@

* Guides
* [Using with Rails](/rails/getting_started.md)
* [Client-side usage](/guides/client-side.md)
* [Using with JavaScript (serverless)](/guides/serverless.md)
* [Using with Hotwire](/guides/hotwire.md)
* [Broadcasting](/anycable-go/broadcasting.md)
Expand Down
196 changes: 196 additions & 0 deletions docs/guides/client-side.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,196 @@
# Using AnyCable JS SDK

> See the full documentation at [anycable/anycable-client](https://github.com/anycable/anycable-client).
Even though AnyCable server utilizes Action Cable protocol and, thus, can be used with the existing Action Cable client libraries (such as `@rails/actioncable`),
we recommend using AnyCable JS SDK for the following reasons:

- Multi-platform out-of-the-box (web, workers, React Native, Node.js).
- TypeScript support.
- Extended protocol support (e.g., [binary formats](./anycable-go/binary_formats.md)).
- AnyCable-specific features support (e.g., [reliable streams](./anycable-go/reliable_streams.md) and [signed streams](./anycable-go/signed_streams.md)).
- Better [Turbo Streams support](#hotwire-integration)
- ... and more.

## Quick start

You can install AnyCable JS SDK via npm/yard/pnpm:

```bash
npm install @anycable/web
yarn add @anycable/web
pnpm install @anycable/web
```

The `@anycable/web` package is assumed to be used in the browser environment.
If you want to use AnyCable client in a non-web environment (e.g., Node.js),
you should use `@anycable/core` package.

Then you can use it in your application.

First, you need to create a _cable_ (or _consumer_ as it's called in Action Cable):

```js
// cable.js
import { createCable } from '@anycable/web'

export default createCable({
// There are various options available. For example:
// - Enable verbose logging
logLevel: 'debug',
// - Use the extended Action Cable protocol
protocol: 'actioncable-v1-ext-json',
})
```

Typically, the cable is a singleton in your application. You create it once for the whole lifetime of your application.

### Pub/Sub

You can subscribe to data streams as follows:

```js
import cable from 'cable';

const chatChannel = cable.streamFrom('room/42');

chatChannel.on('message', (msg) => {
// ...
});
```

In most cases, however, you'd prefer to use secured (_signed_) stream names generated by your backend (see [signed streams](./anycable-go/signed_streams.md)):

```js
const cable = createCable();
const signedName = await obtainSignedStreamNameFromWhenever();
const chatChannel = cable.streamFromSigned(signedName);
// ...
```

### Channels

AnyCable client provides multiple ways to subscribe to channels: class-based subscriptions and _headless_ subscriptions.

> [!TIP]
> Read more about the concept of channels and how AnyCable uses it [here](./anycable-go/rpc).
#### Class-based subscriptions

Class-based APIs allows provides an abstraction layer to hide implementation details of subscriptions.
You can add additional API methods, dispatch custom events, etc.

Let's consider an example:

```js
import { Channel } from '@anycable/web'

// channels/chat.js
export default class ChatChannel extends Channel {
// Unique channel identifier (channel class for Action Cable)
static identifier = 'ChatChannel'

async speak(message) {
return this.perform('speak', { message })
}

receive(message) {
if (message.type === 'typing') {
// Emit custom event when message type is 'typing'
return this.emit('typing', message)
}

// Fallback to the default behaviour
super.receive(message)
}
}
```

Then, you can you this class to create a channel instance and subscribe to it:

```js
import cable from 'cable'
import { ChatChannel } from 'channels/chat'

// Build an instance of a ChatChannel class.
const channel = new ChatChannel({ roomId: '42' })

// Subscribe to the server channel via the client.
cable.subscribe(channel) // return channel itself for chaining

// Wait for subscription confirmation or rejection
// NOTE: it's not necessary to do that, you can perform actions right away,
// the channel would wait for connection automatically
await channel.ensureSubscribed()

// Perform an action
let _ = await channel.speak('Hello')

// Handle incoming messages
channel.on('message', msg => console.log(`${msg.name}: ${msg.text}`))

// Handle custom typing messages
channel.on('typing', msg => console.log(`User ${msg.name} is typing`))

// Or subscription close events
channel.on('close', () => console.log('Disconnected from chat'))

// Or temporary disconnect
channel.on('disconnect', () => console.log('No chat connection'))

// Unsubscribe from the channel (results in a 'close' event)
channel.disconnect()
```

#### Headless subscriptions

_Headless_ subscriptions are very similar to Action Cable client-side subscriptions except from the fact that no mixins are allowed (you classes in case you need them).

Let's rewrite the same example using headless subscriptions:

```js
import cable from 'cable'

const subscription = cable.subscribeTo('ChatChannel', { roomId: '42' })

const _ = await subscription.perform('speak', { msg: 'Hello' })

subscription.on('message', msg => {
if (msg.type === 'typing') {
console.log(`User ${msg.name} is typing`)
} else {
console.log(`${msg.name}: ${msg.text}`)
}
})
```

## Migrating from @rails/actioncable

AnyCable JS SDK comes with a compatibility layer that allows you to use it as a drop-in replacement for `@rails/actioncable`.
All you need is to change the imports:

```diff
- import { createConsumer } from "@rails/actioncable";
+ import { createConsumer } from "@anycable/web";

// createConsumer accepts all the options available to createCable
export default createConsumer();
```

Then you can use `consumer.subscriptions.create` as before (under the hood a headless channel would be create).

## Hotwire integration

You can also use AnyCable JS SDK with Hotwire (Turbo Streams) to provide better real-time experience and benefit from AnyCable features.
For that, you must install the [`@anycable/turbo-stream` package](https://github.com/anycable/anycable-client/tree/master/packages/turbo-stream).

Here is how to switch `@hotwired/turbo` to use AnyCable client:

```diff
- import "@hotwired/turbo-rails";
+ import "@hotwired/turbo";
+ import { start } from "@anycable/turbo-stream";
+ import cable from "cable"
+
+ start(cable, { delayedUnsubscribe: true })
```

0 comments on commit 6307ead

Please sign in to comment.