Liveblocks 2.0 is our second major release, and focuses on removing any rough edges and smoothening the developer experience. It makes Liveblocks simpler to set up for new users as well as for existing users. Our long term goal is to empower you to write and evolve your apps in the best way possible, and at enterprise scale.
Liveblocks has always embraced the benefits of static typing with TypeScript.
Roughly two years ago, we published 0.17, which
introduced the pattern of calling
createRoomContext()
and returning a “bundle” of type-safe hooks that you could
then use in your application. This pattern worked nicely because all the hooks
were bound to your custom type definitions for Presence
, Storage
, etc. in
one single place, and every Liveblocks API would deeply know about it. No need
for manual type annotations anywhere else in your codebase.
There were, however, a couple of downsides to this approach that have always kept itching:
createRoomContext()
had a fixed ordering to them. If you wanted to specify
only Presence
and RoomEvent
, you’d have to “skip” some type params, by
doing createRoomContext<Presence, {}, {}, RoomEvent>()
or similar.With 2.0, this all becomes a lot simpler. We’ve done a lot of internal refactoring to make this possible. We’ll dive in soon, but here is a sneak peek:
We’ll first go over all the breaking changes, then we’ll show you how to simplify your codebase.
First of all, let’s upgrade all Liveblocks dependencies to their latest versions. The easiest way to do that is to run the following command:
There are also some breaking changes in this update. Most users will not run into any of these, but there is a chance that some of these will affect your situation. Making the necessary code adjustments should however be easy. In many cases, we provide a codemod that makes the actual change for you, so you don’t have to do so manually.
We’ve renamed our package @liveblocks/react-comments
to
@liveblocks/react-ui
, because our library of pre-built UI components now
contains more than just Comments-related components. Please adjust your imports.
Run the following codemod or manually make the changes:
This will change your imports like this:
And also:
To avoid confusion with the newly introduced custom
RoomInfo
type, we’ve renamed the RoomInfo
type
in our @liveblocks/node
package.
Run the following codemod or manually make the changes:
This will change:
In @liveblocks/node
, none of the client methods, like
liveblocks.getThread()
, take type params any longer.
Make the following changes:
You should use global type augmentation instead. Please see “Simplifying your Liveblocks application” below for a lot more detail on this transition.
To make discoverability and refactorings easier, and to avoid confusion with the
newly introduced LiveblocksProvider
in our React package, we’re no longer
using default exports, but named exports only.
Run the following codemod or manually make the changes:
This will change your import (and its usage) like this:
The LiveList()
constructor’s argument is no longer optional, because it causes
unneeded but confusing type inference issues.
Run the following codemod or manually make the changes:
This will add an array to empty LiveList
constructors:
The webhook event NotificationEvent
’s type can represent multiple kinds of
notifications: "thread"
, "textMention"
, and custom ones (e.g.
"$myNotification"
).
If you were using properties only available on the "thread"
kind (e.g.
threadId
), you will need to first check for the kind of notification before
accessing them.
All of the following APIs have been removed in 2.0, as they were deprecated multiple versions ago.
Affecting @liveblocks/client
:
Client.enter()
has been replaced by Client.enterRoom()
Client.leave()
has been replaced by Client.enterRoom()
, which returns a
leave
functionfetchPolyfill
, WebSocketPolyfill
, are replaced by
polyfills: { fetch, WebSocket }
shouldInitiallyConnect
is now renamed to autoConnect
room.getConnectionState()
and
.subscribe("connection")
. You can use .getStatus()
or
.subscribe("status")
instead.user.isReadOnly
field is replaced by !user.canWrite
(note the negation
here)Others<P, U>
type. Please change to readonly User<P, U>[]
.Affecting @liveblocks/react
:
useMap
, useList
, and useObject
hooks. These have been deprecated
since the release of 0.18 (more than two years ago). Please see
the 0.18 upgrade guide
for tips on how to rewrite these hooks to useStorage
.options
to createRoomContext(client, options)
has been
removed. These options have been moved to the client.Affecting @liveblocks/node
:
authorize
method from @liveblocks/node
. Please refer to
the 1.2 upgrade guide to learn how to
upgrade your auth endpoint.Affecting @liveblocks/redux
and @liveblocks/zustand
:
If you have dealt with the breaking changes above, or concluded they they don’t apply to your situation, we can go a step further and really simplify your Liveblocks setup.
Go to your liveblocks.config.ts
, find your createRoomContext()
call. Now
decide which codemod to run.
Option 1: You are using Suspense hooks.
(const { suspense: { useRoom, ... } }
)
Option 2: You are using classic hooks. (const { useRoom, ... }
)
Running either of these will make the following changes.
Secondly, it will change all imports in your code base to import the hooks directly instead:
At this point, there should not be any new TypeScript issues. However, running
the code will not yet work. This is because previously the hooks were bound to
the client
instance by passing it to the createRoomContext()
factory, which
we now removed. When using the global types, we’ll have to provide the
Liveblocks client otherwise.
The way to do it is to use a pretty standard React provider. Make the following change:
If you were exporting the client
instance before and have components that
directly accessed it before, you can now obtain a reference to the client
instance that the LiveblocksProvider
creates for you using the useClient
hook:
If you also exported your Presence
, Storage
, etc types from
liveblocks.config.ts
before, you no longer have to. The main reason to export
these before was to use them in helper functions that used some of the
Liveblocks types, like User
, or Room
.
For example:
This is no longer needed. You can simply remove them. TypeScript will still know
about your custom age
property on user.info
.
Furthermore, the following miscellaneous quality-of-life improvements have been made that are non-breaking changes.
ClientSideSuspense
no longer needs a functionPreviously, the ClientSideSuspense
helper needed a function as its children
prop, but it no longer has to.
This will change:
InboxNotification
props typesWhen passing custom components to the kinds
prop of InboxNotification
,
you could use types like InboxNotificationThreadProps
for the props. But this
wasn’t always true for all notification kinds, so now you can use types named
InboxNotificationThreadKindProps
for your components, while
InboxNotificationThreadProps
describes the props of our own
InboxNotification.Thread
.
RoomInfo
By using the resolveRoomsInfo
callback from createClient
or the new
LiveblocksProvider
, you can attach arbitrary room data to a room, which
you can retrieve with the useRoomInfo
hook.
Both of these APIs will now respect the type you provide via:
ActivitiesData
By providing a custom ActivitiesData
type, you can improve how your custom
notifications and their activities’ data are typed.
That’s it!
If you have any trouble with these new patterns, run into a bug with one of the codemods, or otherwise need help, please let us know by email or by joining our Discord community! We’re here to help!
We use cookies to collect data to improve your experience on our site. Read our Privacy Policy to learn more.