@anycable/turbo-stream v0.5.0
AnyCable Turbo Streams
This package provides AnyCable client integration for Turbo Streams.
The default @hotwired/turbo-rails
package doesn't allow you to replace the default Action Cable client with a custom consumer implementation.
🎥 You can learn more about the motivation behind the custom Turbo Streams integration from the AnyCasts episode "Using anycable-client to auto-refresh tokens"
NOTE: Make sure you're not importing @hotwired/turbo-rails
or use a custom tag name: Hotwire's package registers the custom element implicitly and it's not possible to override it.
Usage
Assuming that you have a cable
instance defined somewhere, to activate Turbo Streams elements you need to add the following code:
import { start } from "@anycable/turbo-stream"
// This is your cable instance
import cable from "cable"
// Explicitly activate stream source elements
start(cable)
This approach let you control when (and how) to start streaming from the <turbo-cable-stream-source>
HTML elements.
No server-side changes required. We support all standard functionality: passing a custom channel class and subscription params.
Compatibility with @hotwired/turbo-rails
Our integration aims to be API compatible with the official packages, which means, HTML elements and their attributes are recognized and interpreted the same way as with @hotwired/turbo-rails
.
One subtle but important difference is that @anycable/turbo-stream
does not activate stream elements added to temporary Turbo cache pages. This way we avoid unnecessary subscriptions/unsubscriptions and potential race conditions.
Advanced configuration
Attaching X-Socket-ID
header to Turbo requests
You can automatically add a header to all Turbo requests with the current socket session ID. This can be used to perform broadcasts to others (see Rails integration docs):
import { start } from "@anycable/turbo-stream"
import cable from "cable"
start(cable, { requestSocketIDHeader: true })
// You can also specify a custom header name
// start(cable, { requestSocketIDHeader: 'X-My-Socket-ID' })
Custom channel classes
You define a custom JS channel class for Turbo Streams subscriptions:
import { TurboChannel } from "@anycable/turbo-stream"
class CustomTurboChannel extends TurboChannel {
// Constructor receives the current HTML element (turbo-cable-stream-source),
// a channel name (Turbo::StreamsChannel) by default and subscription params
constructor(element, channelName, params) {
// You can override the server-side channel name
super(element, 'MyTurboChannel', params)
// Additional state configuration goes here
this.totalActions = 0
}
// You can override receive function to intercept actions
receive(message) {
this.totalActions++
// Ignore every second message
if (this.totalActions % 2 === 0) return
// Fallback to the default behaviour,
// which sends the action to Turbo
super.receive(message)
}
}
Another example is a channel which logs all the actions before executing them:
class LogChannel extends TurboChannel {
receive(message) {
console.log("TURBO ACTION", message)
super.receive(message)
}
}
start(cable, {channelClass: LogChannel})
Custom tags
You can use a custom tag name for Turbo Streams source elements. One use case is to use different JS channels for different tags:
// Assuming you have some special channel class
import { TurboPresenceChannel } from './channel.js'
import { start } from "@anycable/turbo-stream"
import cable from "cable"
// Default behaviour
start(cable)
// Custom behaviour
start(cable, { tagName: 'turbo-presence-source', channelClass: TurboPresenceChannel })
NOTE: You need to create a custom Rails helper to render custom elements. For example:
def turbo_presence_stream_from(*streamables, **attributes)
attributes[:channel] = attributes[:channel]&.to_s || "Turbo::StreamsChannel"
attributes[:"signed-stream-name"] = Turbo::StreamsChannel.signed_stream_name(streamables)
tag.turbo_presence_source(**attributes)
end
2 months ago
7 months ago
1 year ago
1 year ago
1 year ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago