From 975b17598deffe923ac9918ef236404bfdc1888f Mon Sep 17 00:00:00 2001
From: David Di Biase <1168397+davedbase@users.noreply.github.com>
Date: Sun, 3 May 2026 14:31:27 -0400
Subject: [PATCH] Port to Solid 2.0 beta 10
---
.../mutation-observer-solid2-migration.md | 16 ++++++++
packages/mutation-observer/CHANGELOG.md | 15 +++++++
packages/mutation-observer/README.md | 10 ++++-
packages/mutation-observer/package.json | 9 ++--
packages/mutation-observer/src/index.ts | 27 +++++++-----
.../mutation-observer/test/server.test.ts | 30 ++++++++++++++
pnpm-lock.yaml | 41 +++----------------
7 files changed, 95 insertions(+), 53 deletions(-)
create mode 100644 .changeset/mutation-observer-solid2-migration.md
create mode 100644 packages/mutation-observer/test/server.test.ts
diff --git a/.changeset/mutation-observer-solid2-migration.md b/.changeset/mutation-observer-solid2-migration.md
new file mode 100644
index 000000000..36fbfa9e4
--- /dev/null
+++ b/.changeset/mutation-observer-solid2-migration.md
@@ -0,0 +1,16 @@
+---
+"@solid-primitives/mutation-observer": major
+---
+
+Migrate to Solid.js v2.0 (beta.10)
+
+## Breaking Changes
+
+**Peer dependencies**: `solid-js@^2.0.0-beta.10` and `@solidjs/web@^2.0.0-beta.10` are now required.
+
+### `@solid-primitives/mutation-observer`
+
+- `onMount` replaced with `onSettled` — observation starts after the component fully settles (async-aware) rather than after initial synchronous render
+- `isServer` now imported from `@solidjs/web`; `isSupported` returns `false` on the server without touching `window`
+- `start()` is a no-op on the server, guarding against missing DOM globals in Node.js
+- Added `test/server.test.ts` to verify safe SSR behavior
diff --git a/packages/mutation-observer/CHANGELOG.md b/packages/mutation-observer/CHANGELOG.md
index 564a33e2b..8dc515592 100644
--- a/packages/mutation-observer/CHANGELOG.md
+++ b/packages/mutation-observer/CHANGELOG.md
@@ -1,5 +1,20 @@
# @solid-primitives/mutation-observer
+## 2.0.0
+
+### Major Changes
+
+- Migrate to Solid.js v2.0 (beta.10)
+
+## Breaking Changes
+
+**Peer dependencies**: `solid-js@^2.0.0-beta.10` and `@solidjs/web@^2.0.0-beta.10` are now required.
+
+- `onMount` replaced with `onSettled` — observation starts after the component fully settles (async-aware) rather than after the initial synchronous render
+- `isServer` is now imported from `@solidjs/web`; `isSupported` returns `false` on the server without checking `window`
+- `start()` is a no-op on the server (guards against missing DOM globals in Node.js)
+- Added `server.test.ts` to verify safe SSR behavior
+
## 1.2.3
### Patch Changes
diff --git a/packages/mutation-observer/README.md b/packages/mutation-observer/README.md
index e20643878..3559a2dfa 100644
--- a/packages/mutation-observer/README.md
+++ b/packages/mutation-observer/README.md
@@ -16,8 +16,12 @@ Primitive providing the ability to watch for changes made to the DOM tree. A wra
npm install @solid-primitives/mutation-observer
# or
yarn add @solid-primitives/mutation-observer
+# or
+pnpm add @solid-primitives/mutation-observer
```
+**Requires** `solid-js` and `@solidjs/web` >= `2.0.0-beta.10` as peer dependencies.
+
## How to use it
### createMutationObserver
@@ -49,13 +53,15 @@ createMutationObserver(
e => {...}
);
-// Primitive return usefull values:
+// Primitive return useful values:
const [observe, {start, stop, instance}] = createMutationObserver(el, options, handler)
observe(el1, { childList: true })
stop()
```
+The primitive automatically starts observing after the component settles (via `onSettled`) and disconnects on cleanup. You can also control observation manually with `start()` and `stop()`.
+
### Directive Usage
```tsx
@@ -73,7 +79,7 @@ import { mutationObserver } from "@solid-primitives/mutation-observer";
// has to be used in code to avoid tree-shaking it:
mutationObserver;
-
{...}]}>...
+ {...}]}>
```
### Types
diff --git a/packages/mutation-observer/package.json b/packages/mutation-observer/package.json
index 21c3fa0b1..fe2c18087 100644
--- a/packages/mutation-observer/package.json
+++ b/packages/mutation-observer/package.json
@@ -1,6 +1,6 @@
{
"name": "@solid-primitives/mutation-observer",
- "version": "1.2.3",
+ "version": "2.0.0",
"description": "Primitive providing the ability to watch for changes made to the DOM tree.",
"author": "Damian Tarnawski @thetarnav ",
"license": "MIT",
@@ -47,14 +47,15 @@
"test:ssr": "pnpm run vitest --mode ssr"
},
"devDependencies": {
- "@solid-primitives/composites": "^1.1.1",
- "solid-js": "^1.9.7"
+ "@solidjs/web": "2.0.0-beta.10",
+ "solid-js": "2.0.0-beta.10"
},
"dependencies": {
"@solid-primitives/utils": "workspace:^"
},
"peerDependencies": {
- "solid-js": "^1.6.12"
+ "@solidjs/web": "^2.0.0-beta.10",
+ "solid-js": "^2.0.0-beta.10"
},
"typesVersions": {}
}
diff --git a/packages/mutation-observer/src/index.ts b/packages/mutation-observer/src/index.ts
index 8e20b7dd9..f7a3b2489 100644
--- a/packages/mutation-observer/src/index.ts
+++ b/packages/mutation-observer/src/index.ts
@@ -1,5 +1,6 @@
-import { onCleanup, onMount } from "solid-js";
+import { onCleanup, onSettled } from "solid-js";
import type { JSX } from "solid-js";
+import { isServer } from "@solidjs/web";
import { access, asArray, type MaybeAccessor } from "@solid-primitives/utils";
export type MutationObserverAdd = (
@@ -34,27 +35,26 @@ export type E = JSX.Element;
/**
* Primitive providing the ability to watch for changes being made to the DOM tree.
- *
+ *
* @param initial html elements to be observed by the MutationObserver
* @param options MutationObserver options
* @param callback function called by MutationObserver when DOM tree mutation is triggered
- *
+ *
* @see https://github.com/solidjs-community/solid-primitives/tree/main/packages/mutation-observer
* @see https://developer.mozilla.org/en-US/docs/Web/API/MutationObserver
- *
+ *
* @example
* ```ts
- * let ref: !HTMLElement;
+ * let ref: HTMLElement;
* const [observe, { start, stop, instance }] = createMutationObserver(
* () => ref,
* { attributes: true, subtree: true },
* records => console.log(records)
* );
- *
+ *
* // Usage as a directive
* const [mutationObserver] = createMutationObserver([], e => {...})
-
-...
+ * ...
* ```
*/
export function createMutationObserver(
@@ -74,7 +74,7 @@ export function createMutationObserver(
c?: MutationCallback,
): MutationObserverReturn {
let defaultOptions: MutationObserverInit, callback: MutationCallback;
- const isSupported = typeof window !== "undefined" && "MutationObserver" in window;
+ const isSupported = !isServer;
if (typeof b === "function") {
defaultOptions = {};
callback = b;
@@ -86,13 +86,18 @@ export function createMutationObserver(
const add: MutationObserverAdd = (el, options) =>
instance?.observe(el, access(options) ?? defaultOptions);
const start = () => {
+ if (!isSupported) return;
asArray(access(initial)).forEach(item => {
item instanceof Node ? add(item, defaultOptions) : add(item[0], item[1]);
});
};
const stop = () => instance?.disconnect();
- onMount(start);
- onCleanup(stop);
+
+ if (isSupported) {
+ onSettled(start);
+ onCleanup(stop);
+ }
+
return [
add,
{
diff --git a/packages/mutation-observer/test/server.test.ts b/packages/mutation-observer/test/server.test.ts
new file mode 100644
index 000000000..eff483b9e
--- /dev/null
+++ b/packages/mutation-observer/test/server.test.ts
@@ -0,0 +1,30 @@
+import { describe, expect, it } from "vitest";
+import { createRoot } from "solid-js";
+import { createMutationObserver, mutationObserver } from "../src/index.js";
+
+describe("SSR", () => {
+ it("createMutationObserver is a noop on the server", () =>
+ createRoot(dispose => {
+ const fakeNode = {} as Node;
+ const [add, { start, stop, instance, isSupported }] = createMutationObserver(
+ fakeNode,
+ { childList: true },
+ _ => {},
+ );
+
+ expect(isSupported).toBe(false);
+ expect(instance).toBeUndefined();
+ expect(() => start()).not.toThrow();
+ expect(() => stop()).not.toThrow();
+ expect(() => add(fakeNode)).not.toThrow();
+
+ dispose();
+ }));
+
+ it("mutationObserver directive is a noop on the server", () =>
+ createRoot(dispose => {
+ const fakeEl = {} as Element;
+ expect(() => mutationObserver(fakeEl, () => [{ childList: true }, _ => {}])).not.toThrow();
+ dispose();
+ }));
+});
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index f59c63a9c..83b2cb200 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -634,12 +634,12 @@ importers:
specifier: workspace:^
version: link:../utils
devDependencies:
- '@solid-primitives/composites':
- specifier: ^1.1.1
- version: 1.1.1(solid-js@1.9.7)
+ '@solidjs/web':
+ specifier: 2.0.0-beta.10
+ version: 2.0.0-beta.10(solid-js@2.0.0-beta.10)
solid-js:
- specifier: ^1.9.7
- version: 1.9.7
+ specifier: 2.0.0-beta.10
+ version: 2.0.0-beta.10
packages/page-visibility:
dependencies:
@@ -2556,28 +2556,11 @@ packages:
resolution: {integrity: sha512-LtoMMhxAlorcGhmFYI+LhPgbPZCkgP6ra1YL604EeF6U98pLlQ3iWIGMdWSC+vWmPBWBNgmDBAhnAobLROJmwg==}
engines: {node: '>=18'}
- '@solid-primitives/composites@1.1.1':
- resolution: {integrity: sha512-eNi1jnUJehBjcVQvod8N1uz91Cn3KvJn/HJIPHUVpnpDj8dFhu5eHJtsiEdNBFJFOR/pPmf9RhJG0pKoTdPz6g==}
- peerDependencies:
- solid-js: ^1.3.1
-
- '@solid-primitives/debounce@1.3.0':
- resolution: {integrity: sha512-Cen4ccCPTuEtQM7o9aEKuOJ0LRlAnzKvN7loEBBOQ+zKdu7/7kYKr7HHE/WS8JAI3QeQr5v2ModYRIZLERw5zw==}
- deprecated: debounce primitive moved to @solid-primitives/scheduled
- peerDependencies:
- solid-js: '>=1.0.0'
-
'@solid-primitives/refs@1.0.8':
resolution: {integrity: sha512-+jIsWG8/nYvhaCoG2Vg6CJOLgTmPKFbaCrNQKWfChalgUf9WrVxWw0CdJb3yX15n5lUcQ0jBo6qYtuVVmBLpBw==}
peerDependencies:
solid-js: ^1.6.12
- '@solid-primitives/throttle@1.2.0':
- resolution: {integrity: sha512-qYKYEgGl/nSCF+wq7H6zFFi8s2e/woFZJkZbCbyUrtbEIvCze4xSZRr64Xi067GlBE+T/N4LZX/htJmLfwkAeg==}
- deprecated: throttle primitive moved to @solid-primitives/scheduled
- peerDependencies:
- solid-js: ^1.3.1
-
'@solid-primitives/transition-group@1.0.5':
resolution: {integrity: sha512-G3FuqvL13kQ55WzWPX2ewiXdZ/1iboiX53195sq7bbkDbXqP6TYKiadwEdsaDogW5rPnPYAym3+xnsNplQJRKQ==}
peerDependencies:
@@ -8590,25 +8573,11 @@ snapshots:
'@sindresorhus/merge-streams@2.3.0': {}
- '@solid-primitives/composites@1.1.1(solid-js@1.9.7)':
- dependencies:
- '@solid-primitives/debounce': 1.3.0(solid-js@1.9.7)
- '@solid-primitives/throttle': 1.2.0(solid-js@1.9.7)
- solid-js: 1.9.7
-
- '@solid-primitives/debounce@1.3.0(solid-js@1.9.7)':
- dependencies:
- solid-js: 1.9.7
-
'@solid-primitives/refs@1.0.8(solid-js@1.9.7)':
dependencies:
'@solid-primitives/utils': 6.2.3(solid-js@1.9.7)
solid-js: 1.9.7
- '@solid-primitives/throttle@1.2.0(solid-js@1.9.7)':
- dependencies:
- solid-js: 1.9.7
-
'@solid-primitives/transition-group@1.0.5(solid-js@1.9.7)':
dependencies:
solid-js: 1.9.7