♻️(frontend) replace y-webrtc by @hocuspocus

y-webrtc had some issues, users had difficulties
to connect with each others.
We replace it by @hocuspocus/provider.
This commit is contained in:
Anthony LC
2024-09-04 15:26:45 +02:00
committed by Anthony LC
parent 9e1979f637
commit 1139c0abea
9 changed files with 25 additions and 29 deletions

View File

@@ -9,7 +9,7 @@ test.beforeEach(async ({ page }) => {
}); });
test.describe('Doc Editor', () => { test.describe('Doc Editor', () => {
test('checks the Doc is connected to the webrtc server', async ({ test('checks the Doc is connected to the provider server', async ({
page, page,
browserName, browserName,
}) => { }) => {
@@ -29,12 +29,7 @@ test.describe('Doc Editor', () => {
await page.locator('.ProseMirror.bn-editor').fill('Hello World'); await page.locator('.ProseMirror.bn-editor').fill('Hello World');
const framesent = await framesentPromise; const framesent = await framesentPromise;
const payload = JSON.parse(framesent.payload as string) as { expect(framesent.payload).not.toBeNull();
type: string;
};
const typeCases = ['publish', 'subscribe', 'unsubscribe', 'ping'];
expect(typeCases.includes(payload.type)).toBeTruthy();
}); });
test('markdown button converts from markdown to the editor syntax json', async ({ test('markdown button converts from markdown to the editor syntax json', async ({

View File

@@ -1,4 +1,4 @@
NEXT_PUBLIC_API_ORIGIN= NEXT_PUBLIC_API_ORIGIN=
NEXT_PUBLIC_Y_PROVIDER_URL=
NEXT_PUBLIC_MEDIA_URL= NEXT_PUBLIC_MEDIA_URL=
NEXT_PUBLIC_SIGNALING_URL=
NEXT_PUBLIC_THEME=dsfr NEXT_PUBLIC_THEME=dsfr

View File

@@ -1,4 +1,4 @@
NEXT_PUBLIC_API_ORIGIN=http://localhost:8071 NEXT_PUBLIC_API_ORIGIN=http://localhost:8071
NEXT_PUBLIC_SIGNALING_URL=ws://localhost:4444 NEXT_PUBLIC_Y_PROVIDER_URL=ws://localhost:4444
NEXT_PUBLIC_MEDIA_URL=http://localhost:8083 NEXT_PUBLIC_MEDIA_URL=http://localhost:8083
NEXT_PUBLIC_SW_DEACTIVATED=true NEXT_PUBLIC_SW_DEACTIVATED=true

View File

@@ -19,6 +19,7 @@
"@blocknote/mantine": "*", "@blocknote/mantine": "*",
"@blocknote/react": "*", "@blocknote/react": "*",
"@gouvfr-lasuite/integration": "1.0.2", "@gouvfr-lasuite/integration": "1.0.2",
"@hocuspocus/provider": "2.13.5",
"@openfun/cunningham-react": "2.9.4", "@openfun/cunningham-react": "2.9.4",
"@tanstack/react-query": "5.53.2", "@tanstack/react-query": "5.53.2",
"i18next": "23.14.0", "i18next": "23.14.0",
@@ -32,7 +33,6 @@
"react-i18next": "15.0.1", "react-i18next": "15.0.1",
"react-select": "5.8.0", "react-select": "5.8.0",
"styled-components": "6.1.13", "styled-components": "6.1.13",
"y-webrtc": "10.3.0",
"yjs": "*", "yjs": "*",
"zustand": "4.5.5" "zustand": "4.5.5"
}, },

View File

@@ -9,9 +9,9 @@ export const backendUrl = () =>
export const baseApiUrl = (apiVersion: string = '1.0') => export const baseApiUrl = (apiVersion: string = '1.0') =>
`${backendUrl()}/api/v${apiVersion}/`; `${backendUrl()}/api/v${apiVersion}/`;
export const signalingUrl = (docId: string) => { export const providerUrl = (docId: string) => {
const base = const base =
process.env.NEXT_PUBLIC_SIGNALING_URL || process.env.NEXT_PUBLIC_Y_PROVIDER_URL ||
(typeof window !== 'undefined' ? `wss://${window.location.host}/ws` : ''); (typeof window !== 'undefined' ? `wss://${window.location.host}/ws` : '');
return `${base}/${docId}`; return `${base}/${docId}`;

View File

@@ -21,7 +21,7 @@ namespace NodeJS {
interface ProcessEnv { interface ProcessEnv {
NEXT_PUBLIC_API_ORIGIN?: string; NEXT_PUBLIC_API_ORIGIN?: string;
NEXT_PUBLIC_MEDIA_URL?: string; NEXT_PUBLIC_MEDIA_URL?: string;
NEXT_PUBLIC_SIGNALING_URL?: string; NEXT_PUBLIC_Y_PROVIDER_URL?: string;
NEXT_PUBLIC_SW_DEACTIVATED?: string; NEXT_PUBLIC_SW_DEACTIVATED?: string;
NEXT_PUBLIC_THEME?: string; NEXT_PUBLIC_THEME?: string;
} }

View File

@@ -2,8 +2,8 @@ import { BlockNoteEditor as BlockNoteEditorCore } from '@blocknote/core';
import '@blocknote/core/fonts/inter.css'; import '@blocknote/core/fonts/inter.css';
import { BlockNoteView } from '@blocknote/mantine'; import { BlockNoteView } from '@blocknote/mantine';
import '@blocknote/mantine/style.css'; import '@blocknote/mantine/style.css';
import { HocuspocusProvider } from '@hocuspocus/provider';
import React, { useCallback, useEffect, useMemo } from 'react'; import React, { useCallback, useEffect, useMemo } from 'react';
import { WebrtcProvider } from 'y-webrtc';
import { Box, TextErrors } from '@/components'; import { Box, TextErrors } from '@/components';
import { mediaUrl } from '@/core'; import { mediaUrl } from '@/core';
@@ -44,7 +44,7 @@ export const BlockNoteEditor = ({ doc, version }: BlockNoteEditorProps) => {
const provider = docsStore?.[storeId]?.provider; const provider = docsStore?.[storeId]?.provider;
useEffect(() => { useEffect(() => {
if (!provider || provider.doc.guid !== storeId) { if (!provider || provider.document.guid !== storeId) {
createProvider(storeId, initialContent); createProvider(storeId, initialContent);
} }
}, [createProvider, initialContent, provider, storeId]); }, [createProvider, initialContent, provider, storeId]);
@@ -58,7 +58,7 @@ export const BlockNoteEditor = ({ doc, version }: BlockNoteEditorProps) => {
interface BlockNoteContentProps { interface BlockNoteContentProps {
doc: Doc; doc: Doc;
provider: WebrtcProvider; provider: HocuspocusProvider;
storeId: string; storeId: string;
} }
@@ -71,7 +71,7 @@ export const BlockNoteContent = ({
const { userData } = useAuthStore(); const { userData } = useAuthStore();
const { setStore, docsStore } = useDocStore(); const { setStore, docsStore } = useDocStore();
const canSave = doc.abilities.partial_update && !isVersion; const canSave = doc.abilities.partial_update && !isVersion;
useSaveDoc(doc.id, provider.doc, canSave); useSaveDoc(doc.id, provider.document, canSave);
const storedEditor = docsStore?.[storeId]?.editor; const storedEditor = docsStore?.[storeId]?.editor;
const { const {
mutateAsync: createDocAttachment, mutateAsync: createDocAttachment,
@@ -102,7 +102,7 @@ export const BlockNoteContent = ({
return BlockNoteEditorCore.create({ return BlockNoteEditorCore.create({
collaboration: { collaboration: {
provider, provider,
fragment: provider.doc.getXmlFragment('document-store'), fragment: provider.document.getXmlFragment('document-store'),
user: { user: {
name: userData?.email || 'Anonymous', name: userData?.email || 'Anonymous',
color: randomColor(), color: randomColor(),

View File

@@ -1,13 +1,13 @@
import { BlockNoteEditor } from '@blocknote/core'; import { BlockNoteEditor } from '@blocknote/core';
import { WebrtcProvider } from 'y-webrtc'; import { HocuspocusProvider } from '@hocuspocus/provider';
import * as Y from 'yjs'; import * as Y from 'yjs';
import { create } from 'zustand'; import { create } from 'zustand';
import { signalingUrl } from '@/core'; import { providerUrl } from '@/core';
import { Base64 } from '@/features/docs/doc-management'; import { Base64 } from '@/features/docs/doc-management';
interface DocStore { interface DocStore {
provider: WebrtcProvider; provider: HocuspocusProvider;
editor?: BlockNoteEditor; editor?: BlockNoteEditor;
} }
@@ -15,7 +15,7 @@ export interface UseDocStore {
docsStore: { docsStore: {
[storeId: string]: DocStore; [storeId: string]: DocStore;
}; };
createProvider: (storeId: string, initialDoc: Base64) => WebrtcProvider; createProvider: (storeId: string, initialDoc: Base64) => HocuspocusProvider;
setStore: (storeId: string, props: Partial<DocStore>) => void; setStore: (storeId: string, props: Partial<DocStore>) => void;
} }
@@ -30,9 +30,10 @@ export const useDocStore = create<UseDocStore>((set, get) => ({
Y.applyUpdate(doc, Buffer.from(initialDoc, 'base64')); Y.applyUpdate(doc, Buffer.from(initialDoc, 'base64'));
} }
const provider = new WebrtcProvider(storeId, doc, { const provider = new HocuspocusProvider({
signaling: [signalingUrl(storeId)], url: providerUrl(storeId),
maxConns: 5, name: storeId,
document: doc,
}); });
get().setStore(storeId, { provider }); get().setStore(storeId, { provider });

View File

@@ -51,9 +51,9 @@ export const ModalVersion = ({
}); });
revertUpdate( revertUpdate(
docsStore[docId].provider.doc, docsStore[docId].provider.document,
docsStore[docId].provider.doc, docsStore[docId].provider.document,
docsStore[versionId].provider.doc, docsStore[versionId].provider.document,
); );
onDisplaySuccess(); onDisplaySuccess();
@@ -83,7 +83,7 @@ export const ModalVersion = ({
fullWidth fullWidth
onClick={() => { onClick={() => {
const newDoc = toBase64( const newDoc = toBase64(
Y.encodeStateAsUpdate(docsStore?.[versionId]?.provider.doc), Y.encodeStateAsUpdate(docsStore?.[versionId]?.provider.document),
); );
updateDoc({ updateDoc({