Avoiding import conflict in plugin scenarios

Has anyone confronted this issue when creating plugins for libraries that already use Yjs? For example, WordPress imports yjs in its editor code, but a WordPress plugin may want to extend this behavior (e.g., customize an awareness implementation). However, the JavaScript bundles for WordPress and a separately distributed plugin must by definition be built separately, which leads to the conflict described in the linked GitHub issue.

Does Yjs provide a way to use dependency injection or some other means to avoid this conflict? Thanks!

I had a conversation with the maintainer which helped me resolve this issue, which I am summarizing here:

maintainer:

  • Use a browser global to avoid duplicate imports:
    • Import Yjs once and assign it to a property on the window object (e.g., window['__$Y__'] = Y).
    • Create a wrapper module (my-org/yjs) that exports this global reference.
    • Plugins then import Yjs via this wrapper module.

zzz:

  • I tried using a global Yjs approach and Webpack externals.
  • Problem: Dependencies like y-websocket or y-webrtc also import Yjs directly.
    • These must also be rewritten to use the shared global or alias.
  • Manual solutions (copying/forking dependencies) are fragile and burdensome.

maintainer:

  • Use a Webpack alias to enforce that all modules import the same mocked Yjs:
alias: {
  yjs: path.resolve(__dirname, 'node_modules/gutenberg/yjs/mock.js'),
}

zzz:

  • This works! Instead of using an actual module, I created a shim file:
// yjs-shim.ts
// To avoid issues with default exports, you must individually export the
// properties you need, including those used by dependencies.
export const applyUpdate = window.Y.applyUpdate;
export const encodeStateVector = window.Y.encodeStateVector;
export const encodeStateAsUpdate = window.Y.encodeStateAsUpdate;
export const Doc = window.Y.Doc;
  • My Webpack alias looks like this:
resolve: {
	alias: {
		yjs: path.resolve( __dirname, 'yjs-shim.ts' ),
	},
}