Fluid Framework Core Client Libraries
The `fluid-framework` package serves as the primary client-side entry point for building collaborative applications with Fluid Framework. It bundles core Fluid Framework client libraries, including the `IFluidContainer` interface and various Distributed Data Structures (DDSes) like `SharedTree` and the now legacy `SharedMap`. The current stable version is 2.93.0, with minor releases occurring frequently, often including new features and breaking changes. This package abstracts away many individual Fluid package dependencies, simplifying development. While it provides the core collaborative primitives, it requires a separate service client (e.g., `@fluidframework/azure-client` or `@fluidframework/tinylicious-client`) to connect to a Fluid service. Its key differentiators include real-time, low-latency collaboration primitives, robust data modeling with `SharedTree`, and a comprehensive API for managing collaborative sessions.
Common errors
-
Error: minVersionForCollab must be a non-negative number. Received: undefined
cause `minVersionForCollab` is missing from the container configuration object.fixAdd `{ minVersionForCollab: 1 }` or an appropriate version to your `containerSchema` when calling `client.createContainer()` or `client.getContainer()`. -
TypeError: require is not a function in ES module scope
cause Attempting to use `require()` for ESM-only Fluid Framework client packages (e.g., `@fluidframework/react`) in a CommonJS environment.fixConfigure your project for ECMAScript Modules (ESM) by setting `"type": "module"` in your `package.json` and using `import` statements. -
Property 'TreeAlpha' does not exist on type 'typeof import("fluid-framework")'.cause Attempting to import a beta or alpha API directly from the root `fluid-framework` package instead of its specific subpath.fixImport beta APIs from `fluid-framework/beta` and alpha APIs from `fluid-framework/alpha`. For example: `import { TreeAlpha } from 'fluid-framework/alpha';`. -
Type 'number' is not assignable to type 'string'.
cause Attempting to use a number as a key in a `LatestMap` instance after Fluid Framework v2.80.fixConvert number keys to strings before using them in `LatestMap`, or refactor to use `SharedTree` for structured data where numeric identifiers can be modeled differently.
Warnings
- breaking The `minVersionForCollab` property is now a non-optional requirement in Fluid Framework client configurations, necessitating explicit specification when creating or loading containers.
- breaking The `@fluidframework/react` package, used for integrating Fluid content into React applications, no longer supports CommonJS (CJS) imports. It is now exclusively an ECMAScript Module (ESM).
- breaking The `cleared` event for `IDirectory` (and potentially other similar DDSes) now includes a `path` parameter in its signature, which may affect existing event listeners.
- breaking `LatestMap`, a specific type of Distributed Data Structure, has removed support for number keys.
- deprecated `SharedMap` is now considered a legacy Distributed Data Structure (DDS) as of Fluid Framework version 2.0. While still functional, it is not recommended for new development.
- gotcha Fluid Framework APIs are segmented by their stability level (public, beta, alpha, legacy) and require importing from specific package subpaths (e.g., `fluid-framework`, `fluid-framework/beta`, `fluid-framework/alpha`).
- gotcha When declaring dependencies in `package.json`, use a `^` (caret) version range for public Fluid Framework APIs. However, for unstable (beta or alpha) APIs, a more constrained `~` (tilde) version range is recommended to minimize exposure to unannounced breaking changes.
Install
-
npm install fluid-framework -
yarn add fluid-framework -
pnpm add fluid-framework
Imports
- IFluidContainer
const IFluidContainer = require('fluid-framework');import { IFluidContainer } from 'fluid-framework'; - SharedTree
import { SharedTree } from 'fluid-framework/beta';import { SharedTree } from 'fluid-framework'; - TinyliciousClient
import { TinyliciousClient } from 'fluid-framework';import { TinyliciousClient } from '@fluidframework/tinylicious-client'; - TreeAlpha
import { TreeAlpha } from 'fluid-framework';import { TreeAlpha } from 'fluid-framework/alpha';
Quickstart
import { SharedTree } from "fluid-framework";
import { TinyliciousClient } from "@fluidframework/tinylicious-client";
import { TreeConfiguration, SchemaFactory } from "@fluidframework/tree";
const client = new TinyliciousClient();
// Define the schema for our collaborative tree
const sf = new SchemaFactory("my-app");
class MyTreeNode extends sf.object("MyTreeNode", {
message: sf.string,
timestamp: sf.number,
children: sf.array(sf.reference("MyTreeNode"))
}) {}
const appSchema = new TreeConfiguration(
[MyTreeNode],
() => new MyTreeNode({ message: "Hello from Fluid!", timestamp: Date.now(), children: [] })
);
const containerSchema = {
initialObjects: {
myTree: SharedTree
}
};
async function startFluidClient() {
const containerId = location.hash.substring(1);
let container;
if (!containerId) {
// Create a new container
({ container } = await client.createContainer(containerSchema));
const tree = container.initialObjects.myTree.schematize(appSchema);
tree.root.message = "Initial message";
tree.root.timestamp = Date.now();
const newChild = new MyTreeNode({ message: "First child", timestamp: Date.now(), children: [] });
tree.root.children.insertAtStart(newChild);
const id = await container.attach();
location.hash = id;
console.log("New container created with ID:", id);
} else {
// Get existing container
({ container } = await client.getContainer(containerId, containerSchema));
console.log("Existing container loaded with ID:", containerId);
}
const tree = container.initialObjects.myTree.schematize(appSchema);
// Event listener for changes
tree.events.on("treeChanged", () => {
console.log("Tree changed: Current message is ", JSON.stringify(tree.root.message));
console.log("Number of children: ", tree.root.children.length);
});
// Update the tree after 5 seconds
setTimeout(() => {
const newMessage = `Message from client ${Math.random().toFixed(2)}`;
tree.root.message = newMessage;
const newChild = new MyTreeNode({ message: `Another child ${Math.random().toFixed(2)}`, timestamp: Date.now(), children: [] });
tree.root.children.insertAtEnd(newChild);
console.log(`Updated tree message to: ${newMessage}`);
}, 5000);
}
startFluidClient().catch(console.error);