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