diff --git a/.changeset/optional-react-dom-batching.md b/.changeset/optional-react-dom-batching.md new file mode 100644 index 000000000..4dfbe05b5 --- /dev/null +++ b/.changeset/optional-react-dom-batching.md @@ -0,0 +1,5 @@ +--- +"mobx-react-lite": patch +--- + +Avoid requiring optional `react-dom` during module initialization and fall back to no-op batching when it is unavailable. diff --git a/packages/mobx-react-lite/__tests__/optionalReactDom.test.ts b/packages/mobx-react-lite/__tests__/optionalReactDom.test.ts new file mode 100644 index 000000000..d0db79cdc --- /dev/null +++ b/packages/mobx-react-lite/__tests__/optionalReactDom.test.ts @@ -0,0 +1,15 @@ +afterEach(() => { + jest.dontMock("react-dom") + jest.resetModules() +}) + +test("does not fail to load when react-dom is unavailable", () => { + jest.resetModules() + jest.doMock("react-dom", () => { + throw Object.assign(new Error("Cannot find module 'react-dom'"), { + code: "MODULE_NOT_FOUND" + }) + }) + + expect(() => require("../src/index.ts")).not.toThrow() +}) diff --git a/packages/mobx-react-lite/src/utils/reactBatchedUpdates.ts b/packages/mobx-react-lite/src/utils/reactBatchedUpdates.ts index 8c64462b0..374cd45fe 100644 --- a/packages/mobx-react-lite/src/utils/reactBatchedUpdates.ts +++ b/packages/mobx-react-lite/src/utils/reactBatchedUpdates.ts @@ -1 +1,19 @@ -export { unstable_batchedUpdates } from "react-dom" +import { defaultNoopBatch } from "./observerBatching" + +declare const require: + | ((moduleName: string) => { unstable_batchedUpdates?: typeof defaultNoopBatch }) + | undefined + +export let unstable_batchedUpdates = defaultNoopBatch + +if (typeof require === "function") { + try { + const reactDom = require("react-dom") + if (reactDom.unstable_batchedUpdates) { + unstable_batchedUpdates = reactDom.unstable_batchedUpdates + } + } catch { + // react-dom is optional. React 18+ batches updates automatically, so fall back to no-op + // batching when react-dom isn't available (for example in React Native or server-only installs). + } +}