facebook / lexical

Lexical is an extensible text editor framework that provides excellent reliability, accessibility and performance.
https://lexical.dev
MIT License
17.5k stars 1.45k forks source link

Bug: CollaborationPlugin not working with minimal code example #2153

Closed jullite closed 1 year ago

jullite commented 2 years ago

Lexical version:0.2.9 browser: chrome lasted version computer: mac

Steps To Reproduce

  1. yarn create vite
  2. copy the example code from https://lexical.dev/docs/collaboration/react to src/App.tsx
  3. add dependencies then run 'yarn install' and 'yarn dev'
  4. start a websocket server by running 'PORT=1234 npx y-websocket-server'
  5. open two tabs in browser with link 'http://localhost:3000/' and editing on one tab

Link to code example: https://github.com/jullite/hello-lexical

The current behavior

content of editor not sync between two tabs

The expected behavior

content of editor will sync between two tabs

trueadm commented 2 years ago

Have you test the Playground version? If you clone the Lexical repository locally and do npm run start, you can try collaboration under the settings menu in bottom left.

jullite commented 2 years ago

Playground worked fine but I need to use it outside, I have tired copy the playground code to my next.js based repo with no ssr , but I get wrong with "should never happen" message on one of collaboration tab console when I edit on another tab. I guess it maybe caused by the runtime environment, so I start a new vite repo to reproduce it and get this result.

jullite commented 2 years ago

I have updated code to lexical playground version(only RichTextPlugin, CollaborationPlugin and WebsocketProvider), land still don't work, did I missed something? code here https://github.com/jullite/hello-lexica

hustlefueled commented 2 years ago

Hey @jullite. Were you able to resolve this?

jullite commented 2 years ago

Hey @jullite. Were you able to resolve this?

sorry, I'm quite not familiar with this codebase.

trueadm commented 2 years ago

Have you made sure you're handling bootstrapping properly? I.e. the <RichTextPlugin> or <PlainTextPlugin> has null for initialEditorState? Also you'll need to make sure you are wrapping your app in the collaboration context, so it can access the docMap, and also ensure that you're not using the HistoryPlugin with collaboration.

jullite commented 2 years ago

All you mentioned above have been put in the right place except the collaboration context, is the SharedHistoryContext on playground? Then I tried to put it in my codebase but still don't work. Here is my code in App.tsx:


    <LexicalComposer initialConfig={initialConfig}>
      <SharedHistoryContext>
        <RichTextPlugin
          contentEditable={<ContentEditable className="editor-input" />}
          placeholder={<div>type here</div>}
          initialEditorState={null}
        />
        <CollaborationPlugin
          id="main"
          providerFactory={createWebsocketProvider}
          shouldBootstrap={true}
        />
      </SharedHistoryContext>
    </LexicalComposer>`
iamzapata commented 1 year ago

Hello! I'm struggling with something similar myself.

I'm able to get the playground running locally with collaboration on πŸŽ‰

Local Playground

Playground

But when I try to get the same playground code to run outside of the lexical codebase, collaboration doesn't work.

I get the generic Should never happen error 😭

Note: Getting the playground to at least load and work outside of the lexical repo requires a lot of changes, you have to transform all of the imports from named imports to default imports.

Standalone Playground

Broken Standalone Playground

I'm still debugging this , it seems that it fails because getOrInitCollabNodeFromSharedType is returning undefined at some point.

Hoping someone else has gotten this to work? @jullite @hustlefueled maybe?

@trueadm Any idea why I see this error or how to fix it?

Thank you!

trueadm commented 1 year ago

@iamzapata Are you ensuring that the RichTextPlugin is passing in null for initialEditorState when it is in collab?

iamzapata commented 1 year ago

@trueadm So I have the same code from packages/lexical-playground:

 <RichTextPlugin
  contentEditable={<ContentEditable />}
  placeholder={placeholder}
  initialEditorState={
    isCollab ? null : emptyEditor ? undefined : prepopulatedRichText
  }
/>

But even setting the intialEditorState to null, the app breaks with a different error.

I'm going to keep trying, but I feel the playground should be decoupled from the packages and work outside of it.

Thank you for lexical though, I'm really excited about it.

trueadm commented 1 year ago

The playground isn’t doing anything special. Make sure you add the collaboration context too for the doc map.

fomachanyade commented 1 year ago

I could make collaboration edit with npm run preview(vite preview).

what I did was

But, i still fail and struggling with error when I run npm run dev(vite).

I also removed all other plugins and nodes I think this error at console is only difference from when I run playground repo.

Yjs was already imported. Importing different versions of Yjs often leads to issues.

And I guess the key is build options, but I still trying to figure it out. Maybe I should do same thing like that(but my repo is not next, just react). https://github.com/yjs/yjs/issues/410#issuecomment-1127478919

code here: https://github.com/fomachanyade/react-lexical/tree/main/lexical_react/lexical_react_ts

iamzapata commented 1 year ago

I still haven't been able to make collaboration work locally. I continue getting the "error while handling a Yjs update error: should never happen" error

Everything but the build setup is identical to the playground, I'm using vite though.

I extracted the playground from the lexical, can be found here: https://github.com/iamzapata/lexical-test

trueadm commented 1 year ago

Did you resolve the issue of having multiple Yjs loaded? I can't access https://github.com/iamzapata/lexical-test, it seems to 404.

iamzapata commented 1 year ago

@trueadm Hi,

can you please check the link again.

And related to your question:

Did you resolve the issue of having multiple Yjs loaded?

I do see this warning you're mentioning:

Yjs was already imported. Importing different versions of Yjs often leads to issues.

y-websocket.js:386 WebSocket connection to 'ws://localhost:1212/playground/0/main' failed: WebSocket is closed before the connection is established.

I can open two windows, turn on collaboration on both.

Then I will type something in one window and right away, in the other window, I get this error:

Caught error while handling a Yjs update Error: Should never happen at syncEvent

fomachanyade commented 1 year ago

After I changed tsconfig.json and vite.config.json to reference local forked Lexical packeges, it worked and error resolved. I guess this is because Lexical${pluginName}Plugin.dev.js in npm package is in commonjs, and it doesn't match with vite command. And vite preview works fine means It solved at production build.

So, I think we can solve this problem in two ways: Fork And Build Lexical packeges in development (which I will try), Or Change vite build config.

Sorry, I'm not familiar with js bundle and build, so I can't describe the problem much. Any other information is welcomed.

trueadm commented 1 year ago

I think this seems like an issue with Vite where it's unable to handle a CJS and an ESM import of the same package. I guess this will be resolved in the future when Lexical also supports ESM, but that's quite complex to support right now (as we have DEV and PROD variants, which I'm unsure how would work in an ESM world).

fomachanyade commented 1 year ago

@jullite @iamzapata my mate solved the vite build problem. just added an alias for yjs and debugging collaboration worked.

vite.config.js

// https://vitejs.dev/config/
export default defineConfig({
  plugins: [react()],
  resolve: {
    alias: {
      yjs: path.resolve("./node_modules/yjs/src/index.js"),
    },
  },
});

please try this.

iamzapata commented 1 year ago

@fomachanyade I confirm making this change makes the collaboration work locally. Thank you! =)

ebads67 commented 1 year ago

@jullite @iamzapata my mate solved the vite build problem. just added an alias for yjs and debugging collaboration worked.

vite.config.js

// https://vitejs.dev/config/
export default defineConfig({
  plugins: [react()],
  resolve: {
    alias: {
      yjs: path.resolve("./node_modules/yjs/src/index.js"),
    },
  },
});

please try this.

Is this the only thing we need to do to get the collaboration working on a separate project? I was not able to make the collaboration work by adding this to my vite config file.

iamzapata commented 1 year ago

@jullite @iamzapata my mate solved the vite build problem. just added an alias for yjs and debugging collaboration worked. vite.config.js

// https://vitejs.dev/config/
export default defineConfig({
  plugins: [react()],
  resolve: {
    alias: {
      yjs: path.resolve("./node_modules/yjs/src/index.js"),
    },
  },
});

please try this.

Is this the only thing we need to do to get the collaboration working on a separate project? I was not able to make the collaboration work by adding this to my vite config file.

Hi @ebads67 I think so?

Check this repo out and let me know: https://github.com/iamzapata/lexical-collab

ebads67 commented 1 year ago

Okay I could actually make it work. The fix was slightly different than what proposed here:

 plugins: [react(), tsconfigPaths()],
  resolve: {
    alias: {
      yjs: resolve("./node_modules/yjs/src/index.js"),
    },
  },
theshajha commented 1 year ago

Hey @ebads67 were you able to test collaboration and sync data back to your backend server?

I've tested yjs connection and it works but it outputs the binary message when I log what it's sending to the server.

ebads67 commented 1 year ago

Hey @ebads67 were you able to test collaboration and sync data back to your backend server?

I've tested yjs connection and it works but it outputs the binary message when I log what it's sending to the server.

Yes I did. I'd suggest checking the repo mentioned above.

hustlefueled commented 1 year ago

Too many repos mentioned above. Would be kind to share the link again. Sorry for the trouble.

Sent via Superhuman ( @.*** )

On Fri, Jun 24, 2022 at 15:38:12, Ebad < @.*** > wrote:

Hey @ ebads67 ( https://github.com/ebads67 ) were you able to test collaboration and sync data back to your backend server?

I've tested yjs connection and it works but it outputs the binary message when I log what it's sending to the server.

Yes I did. I'd suggest checking the repo mentioned above.

β€” Reply to this email directly, view it on GitHub ( https://github.com/facebook/lexical/issues/2153#issuecomment-1165420271 ) , or unsubscribe ( https://github.com/notifications/unsubscribe-auth/AVDFMEHVHVCQXSALVX2JN2DVQWCIZANCNFSM5VXWKW7Q ). You are receiving this because you were mentioned. Message ID: <facebook/lexical/issues/2153/1165420271 @ github. com>

ebads67 commented 1 year ago

Too many repos mentioned above. Would be kind to share the link again. Sorry for the trouble. Sent via Superhuman ( @. ) … On Fri, Jun 24, 2022 at 15:38:12, Ebad < @. > wrote: > > > Hey @ ebads67 ( https://github.com/ebads67 ) were you able to test > collaboration and sync data back to your backend server? > > > > I've tested yjs connection and it works but it outputs the binary message > when I log what it's sending to the server. > > Yes I did. I'd suggest checking the repo mentioned above. β€” Reply to this email directly, view it on GitHub ( #2153 (comment) ) , or unsubscribe ( https://github.com/notifications/unsubscribe-auth/AVDFMEHVHVCQXSALVX2JN2DVQWCIZANCNFSM5VXWKW7Q ). You are receiving this because you were mentioned. Message ID: <facebook/lexical/issues/2153/1165420271 @ github. com>

The one mentioned by @iamzapata. https://github.com/iamzapata/lexical-test

hustlefueled commented 1 year ago

Thank you. πŸ™

Sent via Superhuman ( @.*** )

On Fri, Jun 24, 2022 at 15:45:35, Ebad < @.*** > wrote:

Too many repos mentioned above. Would be kind to share the link again. Sorry for the trouble. Sent via Superhuman ( @. ) … ( # ) On Fri, Jun 24, 2022 at 15:38:12, Ebad < @. > wrote: > > > Hey @ ebads67 ( https:/ / github. com/ ebads67 ( https://github.com/ebads67 ) ) were you able to test > collaboration and sync data back to your backend server? > > > > I've tested yjs connection and it works but it outputs the binary message > when I log what it's sending to the server. > > Yes I did. I'd suggest checking the repo mentioned above. β€” Reply to this email directly, view it on GitHub ( #2153 (comment) ( https://github.com/facebook/lexical/issues/2153#issuecomment-1165420271 ) ) , or unsubscribe ( https:/ / github. com/ notifications/ unsubscribe-auth/ AVDFMEHVHVCQXSALVX2JN2DVQWCIZANCNFSM5VXWKW7Q ( https://github.com/notifications/unsubscribe-auth/AVDFMEHVHVCQXSALVX2JN2DVQWCIZANCNFSM5VXWKW7Q ) ). You are receiving this because you were mentioned. Message ID: < / issues/ 2153 ( https://github.com/facebook/lexical/issues/2153 ) /1165420271 @ github. com>

The one mentioned by @ iamzapata ( https://github.com/iamzapata ). https:/ / github. com/ iamzapata/ lexical-test ( https://github.com/iamzapata/lexical-test )

β€” Reply to this email directly, view it on GitHub ( https://github.com/facebook/lexical/issues/2153#issuecomment-1165426498 ) , or unsubscribe ( https://github.com/notifications/unsubscribe-auth/AVDFMEGO63L7I64GFF2TDD3VQWDEPANCNFSM5VXWKW7Q ). You are receiving this because you were mentioned. Message ID: <facebook/lexical/issues/2153/1165426498 @ github. com>

echarles commented 1 year ago

The fix worked for me. the initial error I was hitting was https://github.com/yjs/yjs/issues/438 Yjs was already imported. This breaks constructor checks and will lead to issues!. @dmonad says If you see this message, make sure that you only import one version of Yjs.. However my project had a single yjs version.

It would still be useful to understand why the playground does not need that config https://github.com/facebook/lexical/blob/5d0a07a4c9fbd4d33832c824f68a7ec16e47d5f6/packages/lexical-playground/vite.config.js and why it is needed when the collab feature is used in a separated project.

dmonad commented 1 year ago

@echarles Sometimes there are nested yjs packages installed. Potentially, there can be nested yjs installations in node_modules: e.g. node_modules & node_modules/@lexical/yjs/node_modules/yjs).

Another reason for the error message is that some complex build system import both the commonjs (.cjs) and the module (.mjs) version of Yjs.

You can resolve both issues by specifying explicitly which version you want to use. In webpack and other bundlers, you can set an alias: yjs: "node_modules/yjs/dist/yjs.mjs".

echarles commented 1 year ago

@echarles Sometimes there are nested yjs packages installed. Potentially, there can be nested yjs installations in node_modules: e.g. node_modules & node_modules/@lexical/yjs/node_modules/yjs).

Yeah, absolutely, I have learned that some time ago for other libraries, like e.g. React which is also sensible to mixed versions, and have a few tips to overcome that: you can specify "resolutions" package.json, if this does not work, I have a sanity bash script that manually removes mismatched packages.

In the local env case I am referring in this issue, I have double checked with a find . -name yjs to ensure a single package was present in the node_module tree.

Another reason for the error message is that some complex build system import both the commonjs (.cjs) and the module (.mjs) version of Yjs.

That could be indeed the root cause. I don't know how to check.

You can resolve both issues by specifying explicitly which version you want to use. In webpack and other bundlers, you can set an alias: yjs: "node_modules/yjs/dist/yjs.mjs".

Yes, this is the workaround documented in this issue and it works. I found it a bit fragile, especially when you have a monorepo managed with tools like lerna, and also when that monorepo is onboarded in yet another complex other monrepo.

You don't have guarantee at which level of your tree the single yjs package will end-up.

knpwrs commented 1 year ago

Have you made sure you're handling bootstrapping properly? I.e. the <RichTextPlugin> or <PlainTextPlugin> has null for initialEditorState?

@trueadm is this a hard requirement for collaboration in Lexical? Is there any way to have an initial state?

trueadm commented 1 year ago

@knpwrs Yes. As the initial state comes from the Y.Doc for consistency reasons.

vineetdigit commented 1 year ago

@fomachanyade I can't thank you and your mate enough for this. The alias suggestion in the vite config resolved the error of duplicate import.

I have wasted several hours today trying to work this out. I hope that lexical exposes ES6 exports to avoid Vite users to go through this..

@jullite @iamzapata my mate solved the vite build problem. just added an alias for yjs and debugging collaboration worked.

vite.config.js

// https://vitejs.dev/config/
export default defineConfig({
  plugins: [react()],
  resolve: {
    alias: {
      yjs: path.resolve("./node_modules/yjs/src/index.js"),
    },
  },
});

please try this.

zolero commented 8 months ago

@fomachanyade I can't thank you and your mate enough for this. The alias suggestion in the vite config resolved the error of duplicate import.

I have wasted several hours today trying to work this out. I hope that lexical exposes ES6 exports to avoid Vite users to go through this..

@jullite @iamzapata my mate solved the vite build problem. just added an alias for yjs and debugging collaboration worked. vite.config.js

// https://vitejs.dev/config/
export default defineConfig({
  plugins: [react()],
  resolve: {
    alias: {
      yjs: path.resolve("./node_modules/yjs/src/index.js"),
    },
  },
});

please try this.

The right answer, thanks.

adamsallimo commented 4 months ago

@fomachanyade I can't thank you and your mate enough for this. The alias suggestion in the vite config resolved the error of duplicate import.

I have wasted several hours today trying to work this out. I hope that lexical exposes ES6 exports to avoid Vite users to go through this..

@jullite @iamzapata my mate solved the vite build problem. just added an alias for yjs and debugging collaboration worked. vite.config.js

// https://vitejs.dev/config/
export default defineConfig({
  plugins: [react()],
  resolve: {
    alias: {
      yjs: path.resolve("./node_modules/yjs/src/index.js"),
    },
  },
});

please try this.

Guys i have an problem, i use Electron + Vite and i try to add alias but it gave me the same error: y-websocket.js?v=99465377:720 WebSocket connection to 'ws://localhost:8000/playground/0/658c4756f67c212fec0205e2' failed: WebSocket is closed before the connection is established. , here is my electron.vite.config.ts


import { resolve } from 'path'
import { defineConfig, externalizeDepsPlugin } from 'electron-vite'
import react from '@vitejs/plugin-react'

export default defineConfig({
  main: {
    plugins: [externalizeDepsPlugin()]
  },
  preload: {
    plugins: [externalizeDepsPlugin()],
  },
  renderer: {
    resolve: {
      alias: {
        yjs: resolve("node_modules/yjs/src/index.js"),
        '@renderer': resolve('src/renderer/src')
      }
    },
    plugins: [react()]
  }
})