@tanstack/redact 0.0.12 → 0.0.14
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/dom/dispatcher.js +57 -21
- package/dist/dom/dispatcher.js.map +2 -2
- package/dist/vite/index.js +19 -3
- package/dist/vite/index.js.map +2 -2
- package/package.json +5 -5
- package/src/dom/dispatcher.ts +69 -29
- package/src/vite/index.ts +34 -3
package/dist/dom/dispatcher.js
CHANGED
|
@@ -185,33 +185,69 @@ function makeDispatcherImpl() {
|
|
|
185
185
|
useSyncExternalStore(subscribe, getSnapshot, getServerSnapshot) {
|
|
186
186
|
const fiber = getCurrentFiber();
|
|
187
187
|
const hook = nextHook();
|
|
188
|
+
const store = hook.queue ?? {
|
|
189
|
+
getSnapshot,
|
|
190
|
+
getServerSnapshot
|
|
191
|
+
};
|
|
192
|
+
hook.queue = store;
|
|
193
|
+
store.getSnapshot = getSnapshot;
|
|
194
|
+
store.getServerSnapshot = getServerSnapshot;
|
|
188
195
|
const root = fiber.root ?? findRootFromFiber(fiber);
|
|
189
196
|
const isHydrating = Boolean(root?.hydrating);
|
|
190
197
|
const value = isHydrating && getServerSnapshot ? getServerSnapshot() : getSnapshot();
|
|
191
198
|
hook.state = value;
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
199
|
+
const deps = [subscribe];
|
|
200
|
+
if (hook.deps === void 0 || !depsEqual(hook.deps, deps)) {
|
|
201
|
+
hook.deps = deps;
|
|
202
|
+
const effect = {
|
|
203
|
+
tag: "layout",
|
|
204
|
+
deps,
|
|
205
|
+
destroy: void 0,
|
|
206
|
+
create: () => {
|
|
207
|
+
if (hook.cleanup) {
|
|
208
|
+
try {
|
|
209
|
+
hook.cleanup();
|
|
210
|
+
} catch {
|
|
211
|
+
}
|
|
212
|
+
if (fiber.cleanups) {
|
|
213
|
+
const i = fiber.cleanups.indexOf(hook.cleanup);
|
|
214
|
+
if (i >= 0) fiber.cleanups.splice(i, 1);
|
|
215
|
+
}
|
|
216
|
+
hook.cleanup = null;
|
|
217
|
+
}
|
|
218
|
+
let unsubscribed = false;
|
|
219
|
+
const cleanup = () => {
|
|
220
|
+
unsubscribed = true;
|
|
221
|
+
if (typeof unsubscribe === "function") {
|
|
222
|
+
unsubscribe();
|
|
223
|
+
}
|
|
224
|
+
};
|
|
225
|
+
const forceUpdate = () => {
|
|
226
|
+
if (unsubscribed || fiber.unmounted) {
|
|
227
|
+
return;
|
|
228
|
+
}
|
|
229
|
+
let next;
|
|
230
|
+
try {
|
|
231
|
+
next = store.getSnapshot();
|
|
232
|
+
} catch {
|
|
233
|
+
scheduleUpdate(fiber);
|
|
234
|
+
return;
|
|
235
|
+
}
|
|
236
|
+
if (!Object.is(hook.state, next)) {
|
|
237
|
+
hook.state = next;
|
|
238
|
+
scheduleUpdate(fiber);
|
|
239
|
+
}
|
|
240
|
+
};
|
|
241
|
+
const unsubscribe = subscribe(forceUpdate);
|
|
242
|
+
if (isHydrating && store.getServerSnapshot) {
|
|
243
|
+
queueMicrotask(() => queueMicrotask(forceUpdate));
|
|
244
|
+
}
|
|
245
|
+
forceUpdate();
|
|
246
|
+
hook.cleanup = cleanup;
|
|
247
|
+
return cleanup;
|
|
204
248
|
}
|
|
205
249
|
};
|
|
206
|
-
|
|
207
|
-
hook.cleanup = unsubscribe;
|
|
208
|
-
if (typeof unsubscribe === "function") {
|
|
209
|
-
fiber.cleanups ||= [];
|
|
210
|
-
fiber.cleanups.push(unsubscribe);
|
|
211
|
-
}
|
|
212
|
-
if (isHydrating && getServerSnapshot) {
|
|
213
|
-
queueMicrotask(() => queueMicrotask(forceUpdate));
|
|
214
|
-
}
|
|
250
|
+
enqueueEffect(fiber, effect);
|
|
215
251
|
}
|
|
216
252
|
return value;
|
|
217
253
|
},
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/dom/dispatcher.ts"],
|
|
4
|
-
"sourcesContent": ["import type { Hook, Fiber, FiberRoot, Effect } from '../core'\nimport { ReactSharedInternals, REACT_CONTEXT_TYPE } from '../react'\nimport { scheduleUpdate, enqueueEffect, readContext } from './reconcile'\n\nfunction getCurrentFiber(): Fiber {\n const f = ReactSharedInternals.currentFiber\n if (!f) throw new Error('Hook called outside a function component render.')\n return f\n}\n\nfunction nextHook(): Hook {\n const fiber = getCurrentFiber()\n const idx = ReactSharedInternals.hookIndex++\n\n let prev = ReactSharedInternals.currentHook\n\n if (idx === 0) {\n if (fiber.hooks) {\n ReactSharedInternals.currentHook = fiber.hooks\n return fiber.hooks\n }\n const h: Hook = { state: undefined, queue: undefined, deps: undefined, cleanup: undefined, next: null }\n fiber.hooks = h\n ReactSharedInternals.currentHook = h\n return h\n }\n\n if (prev && prev.next) {\n ReactSharedInternals.currentHook = prev.next\n return prev.next\n }\n\n const h: Hook = { state: undefined, queue: undefined, deps: undefined, cleanup: undefined, next: null }\n if (prev) prev.next = h\n else fiber.hooks = h\n ReactSharedInternals.currentHook = h\n return h\n}\n\nfunction depsEqual(\n a: ReadonlyArray<unknown> | undefined,\n b: ReadonlyArray<unknown> | undefined,\n): boolean {\n if (a === b) return true\n if (!a || !b) return false\n if (a.length !== b.length) return false\n for (let i = 0; i < a.length; i++) {\n if (!Object.is(a[i], b[i])) return false\n }\n return true\n}\n\n// Singleton \u2014 every method reads render context via ReactSharedInternals,\n// and per-hook closures live on the hook itself, so nothing is render-local\n// to capture. Allocating a fresh wrapper + 17 method closures per function-\n// component render was pure GC pressure.\nconst DISPATCHER = makeDispatcherImpl()\n\nexport function makeDispatcher() {\n return DISPATCHER\n}\n\nfunction makeDispatcherImpl() {\n return {\n useState<S>(initial: S | (() => S)) {\n return this.useReducer<S, S | ((p: S) => S)>(\n basicReducer as any,\n typeof initial === 'function' ? (initial as () => S)() : initial,\n )\n },\n\n useReducer<S, A>(reducer: (s: S, a: A) => S, initialArg: any, init?: (a: any) => S) {\n const hook = nextHook()\n const fiber = getCurrentFiber()\n if (hook.queue === undefined) {\n hook.state = init ? init(initialArg) : initialArg\n const queue: any = { reducer }\n const dispatch = (action: A) => {\n const currentState = hook.state as S\n const next = queue.reducer(currentState, action)\n if (!Object.is(next, currentState)) {\n hook.state = next\n scheduleUpdate(fiber)\n }\n }\n queue.dispatch = dispatch\n hook.queue = queue\n } else {\n hook.queue.reducer = reducer\n }\n return [hook.state, hook.queue.dispatch] as [S, (a: A) => void]\n },\n\n useEffect(create: () => any, deps?: ReadonlyArray<unknown>) {\n const hook = nextHook()\n const fiber = getCurrentFiber()\n const prevDeps = hook.deps\n if (prevDeps !== undefined && depsEqual(prevDeps, deps)) return\n hook.deps = deps\n const effect: Effect = {\n tag: 'effect',\n create: () => {\n // Run the prior cleanup INSIDE the effect run, not during the\n // dispatch/render phase. If render A \u2192 B \u2192 C all happen back-to-\n // back before the passive microtask drains, dispatch-time cleanup\n // only fires once (between A\u2192B) and effects B + C both run fresh,\n // leaving two side-effects (e.g. two plot SVGs) in the DOM. Doing\n // it here, at effect-run time, means every new create first tears\n // down whatever cleanup is currently live on the hook.\n if (hook.cleanup) {\n try { hook.cleanup() } catch {}\n // The prior cleanup was also pushed onto fiber.cleanups; remove\n // it so unmount doesn't double-call it.\n if (fiber.cleanups) {\n const i = fiber.cleanups.indexOf(hook.cleanup)\n if (i >= 0) fiber.cleanups.splice(i, 1)\n }\n hook.cleanup = null\n }\n const c = create()\n hook.cleanup = typeof c === 'function' ? c : null\n return hook.cleanup\n },\n destroy: undefined,\n deps,\n }\n enqueueEffect(fiber, effect)\n },\n\n useLayoutEffect(create: () => any, deps?: ReadonlyArray<unknown>) {\n const hook = nextHook()\n const fiber = getCurrentFiber()\n const prevDeps = hook.deps\n if (prevDeps !== undefined && depsEqual(prevDeps, deps)) return\n hook.deps = deps\n const effect: Effect = {\n tag: 'layout',\n create: () => {\n // Mirror useEffect: tear down the prior cleanup at run time so\n // coalesced renders don't leak side-effects.\n if (hook.cleanup) {\n try { hook.cleanup() } catch {}\n if (fiber.cleanups) {\n const i = fiber.cleanups.indexOf(hook.cleanup)\n if (i >= 0) fiber.cleanups.splice(i, 1)\n }\n hook.cleanup = null\n }\n const c = create()\n hook.cleanup = typeof c === 'function' ? c : null\n return hook.cleanup\n },\n destroy: undefined,\n deps,\n }\n enqueueEffect(fiber, effect)\n },\n\n useInsertionEffect(create: () => any, deps?: ReadonlyArray<unknown>) {\n return this.useLayoutEffect(create, deps)\n },\n\n useRef<T>(initial: T) {\n const hook = nextHook()\n if (hook.state === undefined) hook.state = { current: initial }\n return hook.state as { current: T }\n },\n\n useMemo<T>(factory: () => T, deps?: ReadonlyArray<unknown>) {\n const hook = nextHook()\n if (hook.deps !== undefined && depsEqual(hook.deps, deps)) {\n return hook.state as T\n }\n const value = factory()\n hook.state = value\n hook.deps = deps\n return value\n },\n\n useCallback<T extends Function>(fn: T, deps?: ReadonlyArray<unknown>): T {\n return this.useMemo(() => fn, deps) as T\n },\n\n useContext<T>(ctx: any): T {\n const fiber = getCurrentFiber()\n return readContext(fiber, ctx)\n },\n\n useImperativeHandle<T>(ref: any, factory: () => T, deps?: ReadonlyArray<unknown>) {\n const hook = nextHook()\n if (hook.deps !== undefined && depsEqual(hook.deps, deps)) return\n hook.deps = deps\n const value = factory()\n if (ref) {\n if (typeof ref === 'function') ref(value)\n else ref.current = value\n }\n },\n\n useDebugValue<T>(_value: T, _formatter?: (v: T) => any): void {\n // noop\n },\n\n useId(): string {\n const hook = nextHook()\n if (hook.state === undefined) {\n const fiber = getCurrentFiber()\n const root = findRootFromFiber(fiber)\n hook.state = (root?.identifierPrefix ?? ':r') + (idCounter++).toString(36)\n }\n return hook.state as string\n },\n\n useTransition(): [boolean, (fn: () => void) => void] {\n return [false, (fn: () => void) => fn()]\n },\n\n useDeferredValue<T>(v: T): T {\n return v\n },\n\n useSyncExternalStore<T>(\n subscribe: (cb: () => void) => () => void,\n getSnapshot: () => T,\n getServerSnapshot?: () => T,\n ): T {\n const fiber = getCurrentFiber()\n const hook = nextHook()\n\n // During hydration, use the server snapshot (if provided) so the tree\n // matches the SSR output. Components like TanStack Router's ClientOnly\n // rely on this: they render `false` on server, `true` on client \u2014 and\n // if we return `true` during hydration, client and server diverge and\n // the tree mounts fresh next to the SSR fallback DOM.\n const root = fiber.root ?? findRootFromFiber(fiber)\n const isHydrating = Boolean(root?.hydrating)\n const value =\n isHydrating && getServerSnapshot ? getServerSnapshot() : getSnapshot()\n hook.state = value\n\n if (hook.cleanup == null) {\n const forceUpdate = () => {\n let next: T\n try {\n next = getSnapshot()\n } catch {\n scheduleUpdate(fiber)\n return\n }\n if (!Object.is(hook.state, next)) {\n hook.state = next\n scheduleUpdate(fiber)\n }\n }\n const unsubscribe = subscribe(forceUpdate)\n hook.cleanup = unsubscribe\n // Register with fiber so unmountFiber runs it. Without this, the store\n // keeps holding forceUpdate and every store update schedules an already-\n // unmounted fiber \u2014 its rerender walks stale .parent pointers and mounts\n // zombie DOM into the old parent.\n if (typeof unsubscribe === 'function') {\n fiber.cleanups ||= []\n fiber.cleanups.push(unsubscribe)\n }\n\n // If we served the server snapshot, run a post-hydration check so\n // components like `useHydrated()` flip from false \u2192 true after the\n // initial render commits. Queued late so hydration finishes first.\n if (isHydrating && getServerSnapshot) {\n queueMicrotask(() => queueMicrotask(forceUpdate))\n }\n }\n return value\n },\n\n use<T>(resource: any): T {\n if (resource == null) throw new Error('use() received null or undefined')\n if (resource.$$typeof === REACT_CONTEXT_TYPE) {\n return readContext(getCurrentFiber(), resource)\n }\n if (typeof resource.then === 'function') {\n const thenable = resource\n switch (thenable.status) {\n case 'fulfilled':\n return thenable.value\n case 'rejected':\n throw thenable.reason\n default: {\n if (thenable.status === undefined) {\n thenable.status = 'pending'\n thenable.then(\n (v: any) => {\n if (thenable.status === 'pending') {\n thenable.status = 'fulfilled'\n thenable.value = v\n }\n },\n (e: any) => {\n if (thenable.status === 'pending') {\n thenable.status = 'rejected'\n thenable.reason = e\n }\n },\n )\n }\n throw thenable\n }\n }\n }\n throw new Error('use() expected a Promise or Context')\n },\n }\n}\n\nfunction basicReducer<S>(state: S, action: S | ((p: S) => S)): S {\n return typeof action === 'function' ? (action as (p: S) => S)(state) : action\n}\n\nlet idCounter = 0\n\nfunction findRootFromFiber(fiber: Fiber): FiberRoot | null {\n let f: Fiber | null = fiber\n while (f) {\n if (f.root) return f.root\n f = f.parent\n }\n return null\n}\n"],
|
|
5
|
-
"mappings": "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
|
|
4
|
+
"sourcesContent": ["import type { Hook, Fiber, FiberRoot, Effect } from '../core'\nimport { ReactSharedInternals, REACT_CONTEXT_TYPE } from '../react'\nimport { scheduleUpdate, enqueueEffect, readContext } from './reconcile'\n\nfunction getCurrentFiber(): Fiber {\n const f = ReactSharedInternals.currentFiber\n if (!f) throw new Error('Hook called outside a function component render.')\n return f\n}\n\nfunction nextHook(): Hook {\n const fiber = getCurrentFiber()\n const idx = ReactSharedInternals.hookIndex++\n\n let prev = ReactSharedInternals.currentHook\n\n if (idx === 0) {\n if (fiber.hooks) {\n ReactSharedInternals.currentHook = fiber.hooks\n return fiber.hooks\n }\n const h: Hook = { state: undefined, queue: undefined, deps: undefined, cleanup: undefined, next: null }\n fiber.hooks = h\n ReactSharedInternals.currentHook = h\n return h\n }\n\n if (prev && prev.next) {\n ReactSharedInternals.currentHook = prev.next\n return prev.next\n }\n\n const h: Hook = { state: undefined, queue: undefined, deps: undefined, cleanup: undefined, next: null }\n if (prev) prev.next = h\n else fiber.hooks = h\n ReactSharedInternals.currentHook = h\n return h\n}\n\nfunction depsEqual(\n a: ReadonlyArray<unknown> | undefined,\n b: ReadonlyArray<unknown> | undefined,\n): boolean {\n if (a === b) return true\n if (!a || !b) return false\n if (a.length !== b.length) return false\n for (let i = 0; i < a.length; i++) {\n if (!Object.is(a[i], b[i])) return false\n }\n return true\n}\n\n// Singleton \u2014 every method reads render context via ReactSharedInternals,\n// and per-hook closures live on the hook itself, so nothing is render-local\n// to capture. Allocating a fresh wrapper + 17 method closures per function-\n// component render was pure GC pressure.\nconst DISPATCHER = makeDispatcherImpl()\n\nexport function makeDispatcher() {\n return DISPATCHER\n}\n\nfunction makeDispatcherImpl() {\n return {\n useState<S>(initial: S | (() => S)) {\n return this.useReducer<S, S | ((p: S) => S)>(\n basicReducer as any,\n typeof initial === 'function' ? (initial as () => S)() : initial,\n )\n },\n\n useReducer<S, A>(reducer: (s: S, a: A) => S, initialArg: any, init?: (a: any) => S) {\n const hook = nextHook()\n const fiber = getCurrentFiber()\n if (hook.queue === undefined) {\n hook.state = init ? init(initialArg) : initialArg\n const queue: any = { reducer }\n const dispatch = (action: A) => {\n const currentState = hook.state as S\n const next = queue.reducer(currentState, action)\n if (!Object.is(next, currentState)) {\n hook.state = next\n scheduleUpdate(fiber)\n }\n }\n queue.dispatch = dispatch\n hook.queue = queue\n } else {\n hook.queue.reducer = reducer\n }\n return [hook.state, hook.queue.dispatch] as [S, (a: A) => void]\n },\n\n useEffect(create: () => any, deps?: ReadonlyArray<unknown>) {\n const hook = nextHook()\n const fiber = getCurrentFiber()\n const prevDeps = hook.deps\n if (prevDeps !== undefined && depsEqual(prevDeps, deps)) return\n hook.deps = deps\n const effect: Effect = {\n tag: 'effect',\n create: () => {\n // Run the prior cleanup INSIDE the effect run, not during the\n // dispatch/render phase. If render A \u2192 B \u2192 C all happen back-to-\n // back before the passive microtask drains, dispatch-time cleanup\n // only fires once (between A\u2192B) and effects B + C both run fresh,\n // leaving two side-effects (e.g. two plot SVGs) in the DOM. Doing\n // it here, at effect-run time, means every new create first tears\n // down whatever cleanup is currently live on the hook.\n if (hook.cleanup) {\n try { hook.cleanup() } catch {}\n // The prior cleanup was also pushed onto fiber.cleanups; remove\n // it so unmount doesn't double-call it.\n if (fiber.cleanups) {\n const i = fiber.cleanups.indexOf(hook.cleanup)\n if (i >= 0) fiber.cleanups.splice(i, 1)\n }\n hook.cleanup = null\n }\n const c = create()\n hook.cleanup = typeof c === 'function' ? c : null\n return hook.cleanup\n },\n destroy: undefined,\n deps,\n }\n enqueueEffect(fiber, effect)\n },\n\n useLayoutEffect(create: () => any, deps?: ReadonlyArray<unknown>) {\n const hook = nextHook()\n const fiber = getCurrentFiber()\n const prevDeps = hook.deps\n if (prevDeps !== undefined && depsEqual(prevDeps, deps)) return\n hook.deps = deps\n const effect: Effect = {\n tag: 'layout',\n create: () => {\n // Mirror useEffect: tear down the prior cleanup at run time so\n // coalesced renders don't leak side-effects.\n if (hook.cleanup) {\n try { hook.cleanup() } catch {}\n if (fiber.cleanups) {\n const i = fiber.cleanups.indexOf(hook.cleanup)\n if (i >= 0) fiber.cleanups.splice(i, 1)\n }\n hook.cleanup = null\n }\n const c = create()\n hook.cleanup = typeof c === 'function' ? c : null\n return hook.cleanup\n },\n destroy: undefined,\n deps,\n }\n enqueueEffect(fiber, effect)\n },\n\n useInsertionEffect(create: () => any, deps?: ReadonlyArray<unknown>) {\n return this.useLayoutEffect(create, deps)\n },\n\n useRef<T>(initial: T) {\n const hook = nextHook()\n if (hook.state === undefined) hook.state = { current: initial }\n return hook.state as { current: T }\n },\n\n useMemo<T>(factory: () => T, deps?: ReadonlyArray<unknown>) {\n const hook = nextHook()\n if (hook.deps !== undefined && depsEqual(hook.deps, deps)) {\n return hook.state as T\n }\n const value = factory()\n hook.state = value\n hook.deps = deps\n return value\n },\n\n useCallback<T extends Function>(fn: T, deps?: ReadonlyArray<unknown>): T {\n return this.useMemo(() => fn, deps) as T\n },\n\n useContext<T>(ctx: any): T {\n const fiber = getCurrentFiber()\n return readContext(fiber, ctx)\n },\n\n useImperativeHandle<T>(ref: any, factory: () => T, deps?: ReadonlyArray<unknown>) {\n const hook = nextHook()\n if (hook.deps !== undefined && depsEqual(hook.deps, deps)) return\n hook.deps = deps\n const value = factory()\n if (ref) {\n if (typeof ref === 'function') ref(value)\n else ref.current = value\n }\n },\n\n useDebugValue<T>(_value: T, _formatter?: (v: T) => any): void {\n // noop\n },\n\n useId(): string {\n const hook = nextHook()\n if (hook.state === undefined) {\n const fiber = getCurrentFiber()\n const root = findRootFromFiber(fiber)\n hook.state = (root?.identifierPrefix ?? ':r') + (idCounter++).toString(36)\n }\n return hook.state as string\n },\n\n useTransition(): [boolean, (fn: () => void) => void] {\n return [false, (fn: () => void) => fn()]\n },\n\n useDeferredValue<T>(v: T): T {\n return v\n },\n\n useSyncExternalStore<T>(\n subscribe: (cb: () => void) => () => void,\n getSnapshot: () => T,\n getServerSnapshot?: () => T,\n ): T {\n const fiber = getCurrentFiber()\n const hook = nextHook()\n const store: {\n getSnapshot: () => T\n getServerSnapshot: (() => T) | undefined\n } = hook.queue ?? {\n getSnapshot,\n getServerSnapshot,\n }\n hook.queue = store\n store.getSnapshot = getSnapshot\n store.getServerSnapshot = getServerSnapshot\n\n // During hydration, use the server snapshot (if provided) so the tree\n // matches the SSR output. Components like TanStack Router's ClientOnly\n // rely on this: they render `false` on server, `true` on client \u2014 and\n // if we return `true` during hydration, client and server diverge and\n // the tree mounts fresh next to the SSR fallback DOM.\n const root = fiber.root ?? findRootFromFiber(fiber)\n const isHydrating = Boolean(root?.hydrating)\n const value =\n isHydrating && getServerSnapshot ? getServerSnapshot() : getSnapshot()\n hook.state = value\n\n const deps = [subscribe]\n if (hook.deps === undefined || !depsEqual(hook.deps, deps)) {\n hook.deps = deps\n const effect: Effect = {\n tag: 'layout',\n deps,\n destroy: undefined,\n create: () => {\n if (hook.cleanup) {\n try {\n hook.cleanup()\n } catch {\n // ignore cleanup failures\n }\n if (fiber.cleanups) {\n const i = fiber.cleanups.indexOf(hook.cleanup)\n if (i >= 0) fiber.cleanups.splice(i, 1)\n }\n hook.cleanup = null\n }\n\n let unsubscribed = false\n const cleanup = () => {\n unsubscribed = true\n if (typeof unsubscribe === 'function') {\n unsubscribe()\n }\n }\n const forceUpdate = () => {\n if (unsubscribed || fiber.unmounted) {\n return\n }\n\n let next: T\n try {\n next = store.getSnapshot()\n } catch {\n scheduleUpdate(fiber)\n return\n }\n\n if (!Object.is(hook.state, next)) {\n hook.state = next\n scheduleUpdate(fiber)\n }\n }\n const unsubscribe = subscribe(forceUpdate)\n\n // If we served the server snapshot, run a post-hydration check so\n // components like `useHydrated()` flip from false \u2192 true after the\n // initial render commits. Queued late so hydration finishes first.\n if (isHydrating && store.getServerSnapshot) {\n queueMicrotask(() => queueMicrotask(forceUpdate))\n }\n\n forceUpdate()\n hook.cleanup = cleanup\n return cleanup\n },\n }\n enqueueEffect(fiber, effect)\n }\n return value\n },\n\n use<T>(resource: any): T {\n if (resource == null) throw new Error('use() received null or undefined')\n if (resource.$$typeof === REACT_CONTEXT_TYPE) {\n return readContext(getCurrentFiber(), resource)\n }\n if (typeof resource.then === 'function') {\n const thenable = resource\n switch (thenable.status) {\n case 'fulfilled':\n return thenable.value\n case 'rejected':\n throw thenable.reason\n default: {\n if (thenable.status === undefined) {\n thenable.status = 'pending'\n thenable.then(\n (v: any) => {\n if (thenable.status === 'pending') {\n thenable.status = 'fulfilled'\n thenable.value = v\n }\n },\n (e: any) => {\n if (thenable.status === 'pending') {\n thenable.status = 'rejected'\n thenable.reason = e\n }\n },\n )\n }\n throw thenable\n }\n }\n }\n throw new Error('use() expected a Promise or Context')\n },\n }\n}\n\nfunction basicReducer<S>(state: S, action: S | ((p: S) => S)): S {\n return typeof action === 'function' ? (action as (p: S) => S)(state) : action\n}\n\nlet idCounter = 0\n\nfunction findRootFromFiber(fiber: Fiber): FiberRoot | null {\n let f: Fiber | null = fiber\n while (f) {\n if (f.root) return f.root\n f = f.parent\n }\n return null\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": ["h"]
|
|
7
7
|
}
|
package/dist/vite/index.js
CHANGED
|
@@ -135,9 +135,18 @@ function resolveSpecifier(specifier, fromDir, packageRoots) {
|
|
|
135
135
|
return target;
|
|
136
136
|
}
|
|
137
137
|
}
|
|
138
|
+
function pruneOptimizeDepsInclude(optimizeDeps, blocked) {
|
|
139
|
+
if (!optimizeDeps?.include) return;
|
|
140
|
+
optimizeDeps.include = optimizeDeps.include.filter((id) => {
|
|
141
|
+
const tailSpecifier = id.split(">").pop()?.trim() ?? id;
|
|
142
|
+
return !blocked.has(id) && !blocked.has(tailSpecifier);
|
|
143
|
+
});
|
|
144
|
+
}
|
|
138
145
|
function redact(options = {}) {
|
|
139
146
|
const skip = new Set(options.skip ?? []);
|
|
140
147
|
const entries = Object.entries(ALIASES).filter(([k]) => !skip.has(k));
|
|
148
|
+
const excludeList = entries.map(([k]) => k);
|
|
149
|
+
const optimizeDepsBlocked = new Set(excludeList);
|
|
141
150
|
const features = resolveFeatures(options.preset ?? "full", options.features ?? {});
|
|
142
151
|
const resolvedMap = {};
|
|
143
152
|
let done = false;
|
|
@@ -151,11 +160,10 @@ function redact(options = {}) {
|
|
|
151
160
|
}
|
|
152
161
|
done = true;
|
|
153
162
|
}
|
|
154
|
-
return {
|
|
163
|
+
return [{
|
|
155
164
|
name: "redact",
|
|
156
165
|
enforce: "pre",
|
|
157
166
|
config() {
|
|
158
|
-
const excludeList = entries.map(([k]) => k);
|
|
159
167
|
const noExt = ["@tanstack/redact"];
|
|
160
168
|
const aliasMap = Object.fromEntries(entries.filter(([from, to]) => from !== to));
|
|
161
169
|
const dedupe = noExt;
|
|
@@ -208,7 +216,15 @@ function redact(options = {}) {
|
|
|
208
216
|
}
|
|
209
217
|
return resolvedMap[id] ?? null;
|
|
210
218
|
}
|
|
211
|
-
}
|
|
219
|
+
}, {
|
|
220
|
+
name: "redact:optimize-deps-guard",
|
|
221
|
+
enforce: "post",
|
|
222
|
+
configResolved(config) {
|
|
223
|
+
pruneOptimizeDepsInclude(config.optimizeDeps, optimizeDepsBlocked);
|
|
224
|
+
pruneOptimizeDepsInclude(config.environments?.client?.optimizeDeps, optimizeDepsBlocked);
|
|
225
|
+
pruneOptimizeDepsInclude(config.environments?.ssr?.optimizeDeps, optimizeDepsBlocked);
|
|
226
|
+
}
|
|
227
|
+
}];
|
|
212
228
|
}
|
|
213
229
|
var vite_default = redact;
|
|
214
230
|
export {
|
package/dist/vite/index.js.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/vite/index.ts"],
|
|
4
|
-
"sourcesContent": ["import { existsSync, readFileSync, realpathSync } from 'node:fs'\nimport { dirname, resolve as resolvePath } from 'node:path'\nimport { fileURLToPath } from 'node:url'\n\nexport type RedactPreset = 'nano' | 'full'\n\n/**\n * Opt-in feature set. Each flag toggles whether the feature's real\n * implementation ships (`true`) or is swapped with a stub module that\n * degrades gracefully (`false`). Missing keys fall back to the preset's\n * default. Adding a feature to this interface propagates to consumer\n * configs as autocompleted options.\n */\nexport interface RedactFeatures {\n /**\n * `createPortal`. When `false`, portal elements render in place as a\n * Fragment (the `container` prop is ignored). `renderPortal` and its\n * deps are stripped from the bundle.\n */\n portal?: boolean\n /**\n * `createContext` / `useContext` / `<Provider>` / `<Consumer>`. When\n * `false`, Providers render as Fragments (value never propagates),\n * Consumers invoke their function-children with the context's default\n * value, and `useContext` returns the default. Provider-walk logic and\n * `renderProvider` are stripped.\n */\n context?: boolean\n /**\n * `<Suspense>` boundaries + streaming hydration. When `false`, Suspense\n * elements render as Fragments (children mount inline, `fallback` is\n * ignored). Thrown thenables still schedule a re-render on settle, so\n * eventual consistency works \u2014 just no fallback UI during the pending\n * window. Boundary-handler stack and hydration integration are stripped.\n */\n suspense?: boolean\n /**\n * `React.memo`. When `false`, memoized components still render but without\n * the prop-equality gate \u2014 every parent rerender passes through.\n * `shallowEqual` and the force-rerender bypass are stripped.\n */\n memo?: boolean\n /**\n * `React.forwardRef`. When `false`, forwardRef components still render but\n * the ref prop isn't forwarded to the inner function. React 19+ treats\n * refs as normal props on function components anyway, so most apps can\n * drop this. The dispatcher save/restore machinery is stripped.\n */\n forwardRef?: boolean\n /**\n * `React.lazy`. When `false`, lazy elements still resolve if their payload\n * is already available synchronously (e.g. pre-awaited RSC Flight); async\n * resolution throws a clear error. The hydration-deferred-reveal path and\n * Suspense coordination are stripped.\n */\n lazy?: boolean\n /**\n * Class components (`extends Component`). When `false`, class components\n * still render but only honor the core contract: constructor + `render()`\n * + `setState`. Dropped: `contextType`, `getDerivedStateFromProps`,\n * `shouldComponentUpdate`, `componentDidMount`/`Update`/`WillUnmount`,\n * `getDerivedStateFromError`/`componentDidCatch` (error boundaries).\n */\n classComponents?: boolean\n /**\n * SSR hydration (`hydrateRoot`). When `false`, `hydrateRoot` throws\n * (use `createRoot` for SPAs). The HydrationCursor / DOM adoption /\n * streaming-boundary coordination / event-replay / scroll-guard\n * machinery is stripped \u2014 the biggest single chunk of reducible code.\n */\n hydration?: boolean\n}\n\ninterface ResolvedFeatures {\n portal: boolean\n context: boolean\n suspense: boolean\n memo: boolean\n forwardRef: boolean\n lazy: boolean\n classComponents: boolean\n hydration: boolean\n}\n\nconst PRESET_DEFAULTS: Record<RedactPreset, ResolvedFeatures> = {\n // Opt-in: everything off. Turn individual features on via `features`.\n nano: {\n portal: false, context: false, suspense: false, memo: false,\n forwardRef: false, lazy: false, classComponents: false, hydration: false,\n },\n // Opt-out: everything on (drop-in React parity). Turn features off via `features`.\n full: {\n portal: true, context: true, suspense: true, memo: true,\n forwardRef: true, lazy: true, classComponents: true, hydration: true,\n },\n}\n\nfunction resolveFeatures(\n preset: RedactPreset,\n overrides: RedactFeatures,\n): ResolvedFeatures {\n const p = PRESET_DEFAULTS[preset]\n return {\n portal: overrides.portal ?? p.portal,\n context: overrides.context ?? p.context,\n suspense: overrides.suspense ?? p.suspense,\n memo: overrides.memo ?? p.memo,\n forwardRef: overrides.forwardRef ?? p.forwardRef,\n lazy: overrides.lazy ?? p.lazy,\n classComponents: overrides.classComponents ?? p.classComponents,\n hydration: overrides.hydration ?? p.hydration,\n }\n}\n\nexport interface RedactOptions {\n /** Skip aliasing specific specifiers, e.g. if a consumer wants real React somewhere. */\n skip?: ReadonlyArray<string>\n /**\n * Override package resolution root. Defaults to the Vite config root. Useful\n * for monorepos where the plugin lives in a different workspace than the\n * consumer app.\n */\n resolveFrom?: string\n /**\n * Explicit package roots, bypassing node_modules lookup. Keys are package\n * names (e.g. `@tanstack/redact`), values are absolute paths to the package\n * directory. Handy for cross-workspace testing / bring-your-own-build setups.\n */\n packageRoots?: Record<string, string>\n /**\n * Starting point for feature selection. `'full'` (default) turns every\n * feature on \u2014 drop-in React parity, opt-out individual features via\n * `features`. `'nano'` turns everything off \u2014 opt in to what you need.\n */\n preset?: RedactPreset\n /**\n * Per-feature overrides merged on top of the preset's defaults. Enables\n * fine-grained \"preset minus X\" or \"preset plus Y\" configurations.\n */\n features?: RedactFeatures\n}\n\n// Alias map. ORDER MATTERS \u2014 Vite's alias matcher uses first-match against\n// prefix, so more-specific specifiers MUST come before less-specific ones.\n// Without this, `react-dom/server` would prefix-match `react-dom` first and\n// resolve to `@tanstack/redact/dom/server` (wrong) instead of\n// `@tanstack/redact/server`.\n//\n// `use-sync-external-store` aliases are here because its CJS-only React 17\n// compat shim does `var React = require('react')`. That survives Vite's\n// pre-bundling intact and explodes in Cloudflare Workers (no `require`).\n// Modern React has `useSyncExternalStore` built-in, and `@tanstack/redact`\n// additionally exports `useSyncExternalStoreWithSelector` so this alias\n// is safe everywhere.\nconst ALIASES: Record<string, string> = {\n // ---- most-specific first ----\n 'use-sync-external-store/shim/with-selector': '@tanstack/redact',\n 'use-sync-external-store/shim/with-selector.js': '@tanstack/redact',\n 'use-sync-external-store/with-selector': '@tanstack/redact',\n 'use-sync-external-store/with-selector.js': '@tanstack/redact',\n 'use-sync-external-store/shim': '@tanstack/redact',\n 'use-sync-external-store': '@tanstack/redact',\n\n // React drop-in shim targets. Subpaths first.\n 'react/jsx-runtime': '@tanstack/redact/jsx-runtime',\n 'react/jsx-dev-runtime': '@tanstack/redact/jsx-dev-runtime',\n 'react/compiler-runtime': '@tanstack/redact/compiler-runtime',\n 'react-dom/client': '@tanstack/redact/dom-client',\n 'react-dom/server.edge': '@tanstack/redact/server',\n 'react-dom/static.edge': '@tanstack/redact/server',\n 'react-dom/server': '@tanstack/redact/server',\n 'react-dom/test-utils': '@tanstack/redact/dom-test-utils',\n 'react-dom': '@tanstack/redact/dom',\n react: '@tanstack/redact',\n scheduler: '@tanstack/redact/scheduler',\n\n // Self-aliases so Vite resolves `@tanstack/redact/*` imports to the same\n // canonical file path no matter where they originate (worker bundle vs\n // deps_ssr pre-bundle vs source). Without these, Cloudflare's\n // `noExternal: true` worker config inlines one copy while Vite's\n // optimizeDeps pre-bundles another, ending up with two separate\n // ReactSharedInternals instances and a null dispatcher in user hooks.\n // Subpaths first here too.\n '@tanstack/redact/jsx-runtime': '@tanstack/redact/jsx-runtime',\n '@tanstack/redact/jsx-dev-runtime': '@tanstack/redact/jsx-dev-runtime',\n '@tanstack/redact/compiler-runtime': '@tanstack/redact/compiler-runtime',\n '@tanstack/redact/dom-client': '@tanstack/redact/dom-client',\n '@tanstack/redact/dom-test-utils': '@tanstack/redact/dom-test-utils',\n '@tanstack/redact/server': '@tanstack/redact/server',\n '@tanstack/redact/scheduler': '@tanstack/redact/scheduler',\n '@tanstack/redact/dom': '@tanstack/redact/dom',\n '@tanstack/redact': '@tanstack/redact',\n}\n\nfunction splitSpecifier(specifier: string): { pkg: string; sub: string } {\n if (specifier.startsWith('@')) {\n const slash1 = specifier.indexOf('/')\n const slash2 = specifier.indexOf('/', slash1 + 1)\n if (slash2 < 0) return { pkg: specifier, sub: '' }\n return { pkg: specifier.slice(0, slash2), sub: specifier.slice(slash2 + 1) }\n }\n const slash = specifier.indexOf('/')\n if (slash < 0) return { pkg: specifier, sub: '' }\n return { pkg: specifier.slice(0, slash), sub: specifier.slice(slash + 1) }\n}\n\nfunction findPackageDir(pkg: string, fromDir: string): string | null {\n let dir = fromDir\n while (true) {\n const candidate = resolvePath(dir, 'node_modules', pkg)\n if (existsSync(resolvePath(candidate, 'package.json'))) return candidate\n const parent = dirname(dir)\n if (parent === dir) return null\n dir = parent\n }\n}\n\nfunction resolveExport(packageDir: string, sub: string): string | null {\n const pkgJsonPath = resolvePath(packageDir, 'package.json')\n let pkg: any\n try {\n pkg = JSON.parse(readFileSync(pkgJsonPath, 'utf8'))\n } catch {\n return null\n }\n const key = sub ? './' + sub : '.'\n const exp = pkg.exports?.[key]\n // Prefer published `import` (dist/.js) over `source` \u2014 dist is a single\n // transformed bundle so Vite's dep optimizer doesn't thrash on dozens of\n // individual source files. The package keeps cross-subpath imports\n // external, so there's still only one runtime instance.\n const pick = (v: any): string | null => {\n if (typeof v === 'string') return v\n if (v && typeof v === 'object') {\n return pick(v.import ?? v.module ?? v.source ?? v.default ?? null)\n }\n return null\n }\n const target = pick(exp)\n if (target) return resolvePath(packageDir, target)\n if (!sub) {\n const main = pkg.module ?? pkg.main\n if (typeof main === 'string') return resolvePath(packageDir, main)\n }\n return null\n}\n\n// When installed from npm, `@tanstack/redact` is declared as a `dependency`\n// of consumer apps. Under pnpm's strict mode it ends up nested under the\n// plugin's own `.pnpm/@tanstack+redact@.../node_modules/` rather than\n// hoisted to the consumer's root, so a `findPackageDir` walk starting at\n// the Vite project root won't always find it. Search from the plugin's own\n// directory first (which walks into its nested node_modules), then fall\n// back to the consumer root for hoisted installs.\nconst pluginDir = dirname(fileURLToPath(import.meta.url))\n\nfunction resolveSpecifier(\n specifier: string,\n fromDir: string,\n packageRoots: Record<string, string>,\n): string | null {\n const { pkg, sub } = splitSpecifier(specifier)\n const packageDir =\n packageRoots[pkg] ??\n findPackageDir(pkg, pluginDir) ??\n findPackageDir(pkg, fromDir)\n if (!packageDir) return null\n const target = resolveExport(packageDir, sub)\n if (!target) return null\n // Canonicalize through pnpm symlinks. Under strict pnpm, the package may\n // live nested under `.pnpm/@tanstack+redact@.../node_modules/*`, but each\n // of those is itself a symlink to the flat `.pnpm/@tanstack+redact@.../`\n // entry. Vite's `fetchModule` (used by TanStack Start's server-fn\n // compiler) follows the realpath, so the id seen by the capture-transform\n // differs from the nested id we'd return. That leaves the compiler's\n // moduleCache keyed on the realpath while `getModuleInfo` looks up the\n // nested path \u2192 miss \u2192 \"could not load module info\". Returning the\n // canonical realpath here keeps the two sides in agreement.\n try {\n return realpathSync(target)\n } catch {\n return target\n }\n}\n\nexport function redact(options: RedactOptions = {}): any {\n const skip = new Set(options.skip ?? [])\n const entries = Object.entries(ALIASES).filter(([k]) => !skip.has(k))\n const features = resolveFeatures(options.preset ?? 'full', options.features ?? {})\n\n const resolvedMap: Record<string, string> = {}\n let done = false\n\n function resolveAll(root: string): void {\n if (done) return\n const fromDir = options.resolveFrom ?? root\n const packageRoots = options.packageRoots ?? {}\n for (const [from, to] of entries) {\n const resolved = resolveSpecifier(to, fromDir, packageRoots)\n if (resolved) resolvedMap[from] = resolved\n }\n done = true\n }\n\n return {\n name: 'redact',\n enforce: 'pre',\n\n config() {\n const excludeList = entries.map(([k]) => k)\n // Single package \u2014 only one name to dedupe / no-external.\n const noExt = ['@tanstack/redact']\n const aliasMap = Object.fromEntries(entries.filter(([from, to]) => from !== to))\n // Dedupe `@tanstack/redact` so Vite resolves it to a single instance\n // even when multiple packages (e.g. @tanstack/react-router and user\n // code) drag it into different parts of the module graph.\n const dedupe = noExt\n // Scope `resolve.alias` to client + ssr environments ONLY. Do NOT set\n // a top-level alias: it would apply to the `rsc` environment too,\n // where `@vitejs/plugin-rsc`'s vendored `react-server-dom-server`\n // imports `react` and needs the *real* React (with the `.d` field on\n // ReactSharedInternals that our shim deliberately doesn't have).\n // Aliasing `react` \u2192 `@tanstack/redact` in the RSC env crashes Flight\n // serialization. The Cloudflare vite-plugin's rolldown worker-runner\n // also pre-scans bare specifiers via Vite's alias map (not plugin\n // hooks), but it scans within the *ssr* environment specifically \u2014\n // so per-env `environments.ssr.resolve.alias` covers it. The\n // `enforce: 'pre'` resolveId hook below already skips RSC, so the\n // remaining concern is alias placement. Object form is required \u2014\n // array form is silently ignored by rolldown's worker-runner.\n return {\n environments: {\n client: {\n optimizeDeps: { exclude: excludeList },\n resolve: { alias: aliasMap, dedupe },\n },\n ssr: {\n optimizeDeps: { exclude: excludeList },\n resolve: { alias: aliasMap, dedupe, noExternal: noExt },\n },\n },\n ssr: { noExternal: noExt },\n }\n },\n\n configResolved(config: any) {\n resolveAll(config.root)\n // With `packageRoots`, package sources live outside the consumer's Vite\n // project root, so the default server.fs.allow list blocks them. Append\n // to the resolved allow list rather than replacing via `config()`, so we\n // keep Vite's defaults (root + node_modules + client runtime).\n const fsAllow = Object.values(options.packageRoots ?? {})\n if (fsAllow.length && config.server?.fs?.allow) {\n for (const p of fsAllow) {\n if (!config.server.fs.allow.includes(p)) {\n config.server.fs.allow.push(p)\n }\n }\n }\n },\n\n async resolveId(this: any, id: string, importer?: string, opts?: any) {\n // Skip the RSC environment \u2014 it relies on real React internals via\n // @vitejs/plugin-rsc's vendored react-server-dom. Substituting our\n // shim there breaks Flight serialization. Client + SSR envs still swap.\n const envName = this?.environment?.name\n if (envName === 'rsc') return null\n\n // Feature-flag swap: when the reconciler's `features/index` module\n // imports a feature by relative path, redirect to that feature's stub\n // if the flag is off. The stub registers a graceful-degradation\n // matcher (e.g. Portal \u2192 Fragment) so user code keeps working.\n if (importer && /[\\\\/]features[\\\\/]index\\.[jt]sx?$/.test(importer)) {\n const m = id.match(/^\\.\\/([a-z-]+)$/)\n if (m) {\n const name = m[1] as keyof ResolvedFeatures\n if (name in features && !features[name]) {\n const r = await this.resolve(`./${name}/stub`, importer, {\n ...opts,\n skipSelf: true,\n })\n if (r) return r.id\n }\n }\n }\n\n // Hydration swap: hydration isn't self-registering, so it's imported\n // from reconcile.ts, root.ts, and the Suspense/Lazy feature modules.\n // Any specifier ending in `/hydration` that resolves to our feature\n // module gets redirected to the stub when the flag is off.\n if (!features.hydration && importer && /[\\\\/]hydration$/.test(id)) {\n const r = await this.resolve(id, importer, { ...opts, skipSelf: true })\n if (r && /features[\\\\/]hydration[\\\\/]index\\.(ts|js)$/.test(r.id)) {\n return r.id.replace(/index\\.(ts|js)$/, 'stub.$1')\n }\n }\n\n return resolvedMap[id] ?? null\n },\n }\n}\n\nexport default redact\n"],
|
|
5
|
-
"mappings": "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
|
|
4
|
+
"sourcesContent": ["import { existsSync, readFileSync, realpathSync } from 'node:fs'\nimport { dirname, resolve as resolvePath } from 'node:path'\nimport { fileURLToPath } from 'node:url'\n\nexport type RedactPreset = 'nano' | 'full'\n\n/**\n * Opt-in feature set. Each flag toggles whether the feature's real\n * implementation ships (`true`) or is swapped with a stub module that\n * degrades gracefully (`false`). Missing keys fall back to the preset's\n * default. Adding a feature to this interface propagates to consumer\n * configs as autocompleted options.\n */\nexport interface RedactFeatures {\n /**\n * `createPortal`. When `false`, portal elements render in place as a\n * Fragment (the `container` prop is ignored). `renderPortal` and its\n * deps are stripped from the bundle.\n */\n portal?: boolean\n /**\n * `createContext` / `useContext` / `<Provider>` / `<Consumer>`. When\n * `false`, Providers render as Fragments (value never propagates),\n * Consumers invoke their function-children with the context's default\n * value, and `useContext` returns the default. Provider-walk logic and\n * `renderProvider` are stripped.\n */\n context?: boolean\n /**\n * `<Suspense>` boundaries + streaming hydration. When `false`, Suspense\n * elements render as Fragments (children mount inline, `fallback` is\n * ignored). Thrown thenables still schedule a re-render on settle, so\n * eventual consistency works \u2014 just no fallback UI during the pending\n * window. Boundary-handler stack and hydration integration are stripped.\n */\n suspense?: boolean\n /**\n * `React.memo`. When `false`, memoized components still render but without\n * the prop-equality gate \u2014 every parent rerender passes through.\n * `shallowEqual` and the force-rerender bypass are stripped.\n */\n memo?: boolean\n /**\n * `React.forwardRef`. When `false`, forwardRef components still render but\n * the ref prop isn't forwarded to the inner function. React 19+ treats\n * refs as normal props on function components anyway, so most apps can\n * drop this. The dispatcher save/restore machinery is stripped.\n */\n forwardRef?: boolean\n /**\n * `React.lazy`. When `false`, lazy elements still resolve if their payload\n * is already available synchronously (e.g. pre-awaited RSC Flight); async\n * resolution throws a clear error. The hydration-deferred-reveal path and\n * Suspense coordination are stripped.\n */\n lazy?: boolean\n /**\n * Class components (`extends Component`). When `false`, class components\n * still render but only honor the core contract: constructor + `render()`\n * + `setState`. Dropped: `contextType`, `getDerivedStateFromProps`,\n * `shouldComponentUpdate`, `componentDidMount`/`Update`/`WillUnmount`,\n * `getDerivedStateFromError`/`componentDidCatch` (error boundaries).\n */\n classComponents?: boolean\n /**\n * SSR hydration (`hydrateRoot`). When `false`, `hydrateRoot` throws\n * (use `createRoot` for SPAs). The HydrationCursor / DOM adoption /\n * streaming-boundary coordination / event-replay / scroll-guard\n * machinery is stripped \u2014 the biggest single chunk of reducible code.\n */\n hydration?: boolean\n}\n\ninterface ResolvedFeatures {\n portal: boolean\n context: boolean\n suspense: boolean\n memo: boolean\n forwardRef: boolean\n lazy: boolean\n classComponents: boolean\n hydration: boolean\n}\n\nconst PRESET_DEFAULTS: Record<RedactPreset, ResolvedFeatures> = {\n // Opt-in: everything off. Turn individual features on via `features`.\n nano: {\n portal: false, context: false, suspense: false, memo: false,\n forwardRef: false, lazy: false, classComponents: false, hydration: false,\n },\n // Opt-out: everything on (drop-in React parity). Turn features off via `features`.\n full: {\n portal: true, context: true, suspense: true, memo: true,\n forwardRef: true, lazy: true, classComponents: true, hydration: true,\n },\n}\n\nfunction resolveFeatures(\n preset: RedactPreset,\n overrides: RedactFeatures,\n): ResolvedFeatures {\n const p = PRESET_DEFAULTS[preset]\n return {\n portal: overrides.portal ?? p.portal,\n context: overrides.context ?? p.context,\n suspense: overrides.suspense ?? p.suspense,\n memo: overrides.memo ?? p.memo,\n forwardRef: overrides.forwardRef ?? p.forwardRef,\n lazy: overrides.lazy ?? p.lazy,\n classComponents: overrides.classComponents ?? p.classComponents,\n hydration: overrides.hydration ?? p.hydration,\n }\n}\n\nexport interface RedactOptions {\n /** Skip aliasing specific specifiers, e.g. if a consumer wants real React somewhere. */\n skip?: ReadonlyArray<string>\n /**\n * Override package resolution root. Defaults to the Vite config root. Useful\n * for monorepos where the plugin lives in a different workspace than the\n * consumer app.\n */\n resolveFrom?: string\n /**\n * Explicit package roots, bypassing node_modules lookup. Keys are package\n * names (e.g. `@tanstack/redact`), values are absolute paths to the package\n * directory. Handy for cross-workspace testing / bring-your-own-build setups.\n */\n packageRoots?: Record<string, string>\n /**\n * Starting point for feature selection. `'full'` (default) turns every\n * feature on \u2014 drop-in React parity, opt-out individual features via\n * `features`. `'nano'` turns everything off \u2014 opt in to what you need.\n */\n preset?: RedactPreset\n /**\n * Per-feature overrides merged on top of the preset's defaults. Enables\n * fine-grained \"preset minus X\" or \"preset plus Y\" configurations.\n */\n features?: RedactFeatures\n}\n\n// Alias map. ORDER MATTERS \u2014 Vite's alias matcher uses first-match against\n// prefix, so more-specific specifiers MUST come before less-specific ones.\n// Without this, `react-dom/server` would prefix-match `react-dom` first and\n// resolve to `@tanstack/redact/dom/server` (wrong) instead of\n// `@tanstack/redact/server`.\n//\n// `use-sync-external-store` aliases are here because its CJS-only React 17\n// compat shim does `var React = require('react')`. That survives Vite's\n// pre-bundling intact and explodes in Cloudflare Workers (no `require`).\n// Modern React has `useSyncExternalStore` built-in, and `@tanstack/redact`\n// additionally exports `useSyncExternalStoreWithSelector` so this alias\n// is safe everywhere.\nconst ALIASES: Record<string, string> = {\n // ---- most-specific first ----\n 'use-sync-external-store/shim/with-selector': '@tanstack/redact',\n 'use-sync-external-store/shim/with-selector.js': '@tanstack/redact',\n 'use-sync-external-store/with-selector': '@tanstack/redact',\n 'use-sync-external-store/with-selector.js': '@tanstack/redact',\n 'use-sync-external-store/shim': '@tanstack/redact',\n 'use-sync-external-store': '@tanstack/redact',\n\n // React drop-in shim targets. Subpaths first.\n 'react/jsx-runtime': '@tanstack/redact/jsx-runtime',\n 'react/jsx-dev-runtime': '@tanstack/redact/jsx-dev-runtime',\n 'react/compiler-runtime': '@tanstack/redact/compiler-runtime',\n 'react-dom/client': '@tanstack/redact/dom-client',\n 'react-dom/server.edge': '@tanstack/redact/server',\n 'react-dom/static.edge': '@tanstack/redact/server',\n 'react-dom/server': '@tanstack/redact/server',\n 'react-dom/test-utils': '@tanstack/redact/dom-test-utils',\n 'react-dom': '@tanstack/redact/dom',\n react: '@tanstack/redact',\n scheduler: '@tanstack/redact/scheduler',\n\n // Self-aliases so Vite resolves `@tanstack/redact/*` imports to the same\n // canonical file path no matter where they originate (worker bundle vs\n // deps_ssr pre-bundle vs source). Without these, Cloudflare's\n // `noExternal: true` worker config inlines one copy while Vite's\n // optimizeDeps pre-bundles another, ending up with two separate\n // ReactSharedInternals instances and a null dispatcher in user hooks.\n // Subpaths first here too.\n '@tanstack/redact/jsx-runtime': '@tanstack/redact/jsx-runtime',\n '@tanstack/redact/jsx-dev-runtime': '@tanstack/redact/jsx-dev-runtime',\n '@tanstack/redact/compiler-runtime': '@tanstack/redact/compiler-runtime',\n '@tanstack/redact/dom-client': '@tanstack/redact/dom-client',\n '@tanstack/redact/dom-test-utils': '@tanstack/redact/dom-test-utils',\n '@tanstack/redact/server': '@tanstack/redact/server',\n '@tanstack/redact/scheduler': '@tanstack/redact/scheduler',\n '@tanstack/redact/dom': '@tanstack/redact/dom',\n '@tanstack/redact': '@tanstack/redact',\n}\n\nfunction splitSpecifier(specifier: string): { pkg: string; sub: string } {\n if (specifier.startsWith('@')) {\n const slash1 = specifier.indexOf('/')\n const slash2 = specifier.indexOf('/', slash1 + 1)\n if (slash2 < 0) return { pkg: specifier, sub: '' }\n return { pkg: specifier.slice(0, slash2), sub: specifier.slice(slash2 + 1) }\n }\n const slash = specifier.indexOf('/')\n if (slash < 0) return { pkg: specifier, sub: '' }\n return { pkg: specifier.slice(0, slash), sub: specifier.slice(slash + 1) }\n}\n\nfunction findPackageDir(pkg: string, fromDir: string): string | null {\n let dir = fromDir\n while (true) {\n const candidate = resolvePath(dir, 'node_modules', pkg)\n if (existsSync(resolvePath(candidate, 'package.json'))) return candidate\n const parent = dirname(dir)\n if (parent === dir) return null\n dir = parent\n }\n}\n\nfunction resolveExport(packageDir: string, sub: string): string | null {\n const pkgJsonPath = resolvePath(packageDir, 'package.json')\n let pkg: any\n try {\n pkg = JSON.parse(readFileSync(pkgJsonPath, 'utf8'))\n } catch {\n return null\n }\n const key = sub ? './' + sub : '.'\n const exp = pkg.exports?.[key]\n // Prefer published `import` (dist/.js) over `source` \u2014 dist is a single\n // transformed bundle so Vite's dep optimizer doesn't thrash on dozens of\n // individual source files. The package keeps cross-subpath imports\n // external, so there's still only one runtime instance.\n const pick = (v: any): string | null => {\n if (typeof v === 'string') return v\n if (v && typeof v === 'object') {\n return pick(v.import ?? v.module ?? v.source ?? v.default ?? null)\n }\n return null\n }\n const target = pick(exp)\n if (target) return resolvePath(packageDir, target)\n if (!sub) {\n const main = pkg.module ?? pkg.main\n if (typeof main === 'string') return resolvePath(packageDir, main)\n }\n return null\n}\n\n// When installed from npm, `@tanstack/redact` is declared as a `dependency`\n// of consumer apps. Under pnpm's strict mode it ends up nested under the\n// plugin's own `.pnpm/@tanstack+redact@.../node_modules/` rather than\n// hoisted to the consumer's root, so a `findPackageDir` walk starting at\n// the Vite project root won't always find it. Search from the plugin's own\n// directory first (which walks into its nested node_modules), then fall\n// back to the consumer root for hoisted installs.\nconst pluginDir = dirname(fileURLToPath(import.meta.url))\n\nfunction resolveSpecifier(\n specifier: string,\n fromDir: string,\n packageRoots: Record<string, string>,\n): string | null {\n const { pkg, sub } = splitSpecifier(specifier)\n const packageDir =\n packageRoots[pkg] ??\n findPackageDir(pkg, pluginDir) ??\n findPackageDir(pkg, fromDir)\n if (!packageDir) return null\n const target = resolveExport(packageDir, sub)\n if (!target) return null\n // Canonicalize through pnpm symlinks. Under strict pnpm, the package may\n // live nested under `.pnpm/@tanstack+redact@.../node_modules/*`, but each\n // of those is itself a symlink to the flat `.pnpm/@tanstack+redact@.../`\n // entry. Vite's `fetchModule` (used by TanStack Start's server-fn\n // compiler) follows the realpath, so the id seen by the capture-transform\n // differs from the nested id we'd return. That leaves the compiler's\n // moduleCache keyed on the realpath while `getModuleInfo` looks up the\n // nested path \u2192 miss \u2192 \"could not load module info\". Returning the\n // canonical realpath here keeps the two sides in agreement.\n try {\n return realpathSync(target)\n } catch {\n return target\n }\n}\n\ninterface OptimizeDepsWithInclude {\n include?: Array<string>\n}\n\nfunction pruneOptimizeDepsInclude(\n optimizeDeps: OptimizeDepsWithInclude | undefined,\n blocked: ReadonlySet<string>,\n): void {\n if (!optimizeDeps?.include) return\n\n optimizeDeps.include = optimizeDeps.include.filter((id) => {\n const tailSpecifier = id.split('>').pop()?.trim() ?? id\n return !blocked.has(id) && !blocked.has(tailSpecifier)\n })\n}\n\nexport function redact(options: RedactOptions = {}): any {\n const skip = new Set(options.skip ?? [])\n const entries = Object.entries(ALIASES).filter(([k]) => !skip.has(k))\n const excludeList = entries.map(([k]) => k)\n const optimizeDepsBlocked = new Set(excludeList)\n const features = resolveFeatures(options.preset ?? 'full', options.features ?? {})\n\n const resolvedMap: Record<string, string> = {}\n let done = false\n\n function resolveAll(root: string): void {\n if (done) return\n const fromDir = options.resolveFrom ?? root\n const packageRoots = options.packageRoots ?? {}\n for (const [from, to] of entries) {\n const resolved = resolveSpecifier(to, fromDir, packageRoots)\n if (resolved) resolvedMap[from] = resolved\n }\n done = true\n }\n\n return [{\n name: 'redact',\n enforce: 'pre',\n\n config() {\n // Single package \u2014 only one name to dedupe / no-external.\n const noExt = ['@tanstack/redact']\n const aliasMap = Object.fromEntries(entries.filter(([from, to]) => from !== to))\n // Dedupe `@tanstack/redact` so Vite resolves it to a single instance\n // even when multiple packages (e.g. @tanstack/react-router and user\n // code) drag it into different parts of the module graph.\n const dedupe = noExt\n // Scope `resolve.alias` to client + ssr environments ONLY. Do NOT set\n // a top-level alias: it would apply to the `rsc` environment too,\n // where `@vitejs/plugin-rsc`'s vendored `react-server-dom-server`\n // imports `react` and needs the *real* React (with the `.d` field on\n // ReactSharedInternals that our shim deliberately doesn't have).\n // Aliasing `react` \u2192 `@tanstack/redact` in the RSC env crashes Flight\n // serialization. The Cloudflare vite-plugin's rolldown worker-runner\n // also pre-scans bare specifiers via Vite's alias map (not plugin\n // hooks), but it scans within the *ssr* environment specifically \u2014\n // so per-env `environments.ssr.resolve.alias` covers it. The\n // `enforce: 'pre'` resolveId hook below already skips RSC, so the\n // remaining concern is alias placement. Object form is required \u2014\n // array form is silently ignored by rolldown's worker-runner.\n return {\n environments: {\n client: {\n optimizeDeps: { exclude: excludeList },\n resolve: { alias: aliasMap, dedupe },\n },\n ssr: {\n optimizeDeps: { exclude: excludeList },\n resolve: { alias: aliasMap, dedupe, noExternal: noExt },\n },\n },\n ssr: { noExternal: noExt },\n }\n },\n\n configResolved(config: any) {\n resolveAll(config.root)\n // With `packageRoots`, package sources live outside the consumer's Vite\n // project root, so the default server.fs.allow list blocks them. Append\n // to the resolved allow list rather than replacing via `config()`, so we\n // keep Vite's defaults (root + node_modules + client runtime).\n const fsAllow = Object.values(options.packageRoots ?? {})\n if (fsAllow.length && config.server?.fs?.allow) {\n for (const p of fsAllow) {\n if (!config.server.fs.allow.includes(p)) {\n config.server.fs.allow.push(p)\n }\n }\n }\n },\n\n async resolveId(this: any, id: string, importer?: string, opts?: any) {\n // Skip the RSC environment \u2014 it relies on real React internals via\n // @vitejs/plugin-rsc's vendored react-server-dom. Substituting our\n // shim there breaks Flight serialization. Client + SSR envs still swap.\n const envName = this?.environment?.name\n if (envName === 'rsc') return null\n\n // Feature-flag swap: when the reconciler's `features/index` module\n // imports a feature by relative path, redirect to that feature's stub\n // if the flag is off. The stub registers a graceful-degradation\n // matcher (e.g. Portal \u2192 Fragment) so user code keeps working.\n if (importer && /[\\\\/]features[\\\\/]index\\.[jt]sx?$/.test(importer)) {\n const m = id.match(/^\\.\\/([a-z-]+)$/)\n if (m) {\n const name = m[1] as keyof ResolvedFeatures\n if (name in features && !features[name]) {\n const r = await this.resolve(`./${name}/stub`, importer, {\n ...opts,\n skipSelf: true,\n })\n if (r) return r.id\n }\n }\n }\n\n // Hydration swap: hydration isn't self-registering, so it's imported\n // from reconcile.ts, root.ts, and the Suspense/Lazy feature modules.\n // Any specifier ending in `/hydration` that resolves to our feature\n // module gets redirected to the stub when the flag is off.\n if (!features.hydration && importer && /[\\\\/]hydration$/.test(id)) {\n const r = await this.resolve(id, importer, { ...opts, skipSelf: true })\n if (r && /features[\\\\/]hydration[\\\\/]index\\.(ts|js)$/.test(r.id)) {\n return r.id.replace(/index\\.(ts|js)$/, 'stub.$1')\n }\n }\n\n return resolvedMap[id] ?? null\n },\n }, {\n name: 'redact:optimize-deps-guard',\n enforce: 'post',\n\n configResolved(config: any) {\n // `optimizeDeps.exclude` loses when another plugin force-adds the same\n // ids to `include`. That lets Vite pre-bundle real React next to Redact,\n // producing duplicate dispatcher state. Prune after config settles so\n // Redact's client/SSR shims stay canonical.\n pruneOptimizeDepsInclude(config.optimizeDeps, optimizeDepsBlocked)\n pruneOptimizeDepsInclude(config.environments?.client?.optimizeDeps, optimizeDepsBlocked)\n pruneOptimizeDepsInclude(config.environments?.ssr?.optimizeDeps, optimizeDepsBlocked)\n // Leave `environments.rsc` untouched. RSC depends on real React internals.\n },\n }]\n}\n\nexport default redact\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tanstack/redact",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.14",
|
|
4
4
|
"description": "React, redacted. A minimal React-API-compatible drop-in replacement.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/react/index.js",
|
|
@@ -78,10 +78,10 @@
|
|
|
78
78
|
"optional": true
|
|
79
79
|
}
|
|
80
80
|
},
|
|
81
|
-
"scripts": {
|
|
82
|
-
"build": "echo done-by-root-build"
|
|
83
|
-
},
|
|
84
81
|
"publishConfig": {
|
|
85
82
|
"access": "public"
|
|
83
|
+
},
|
|
84
|
+
"scripts": {
|
|
85
|
+
"build": "echo done-by-root-build"
|
|
86
86
|
}
|
|
87
|
-
}
|
|
87
|
+
}
|
package/src/dom/dispatcher.ts
CHANGED
|
@@ -226,6 +226,16 @@ function makeDispatcherImpl() {
|
|
|
226
226
|
): T {
|
|
227
227
|
const fiber = getCurrentFiber()
|
|
228
228
|
const hook = nextHook()
|
|
229
|
+
const store: {
|
|
230
|
+
getSnapshot: () => T
|
|
231
|
+
getServerSnapshot: (() => T) | undefined
|
|
232
|
+
} = hook.queue ?? {
|
|
233
|
+
getSnapshot,
|
|
234
|
+
getServerSnapshot,
|
|
235
|
+
}
|
|
236
|
+
hook.queue = store
|
|
237
|
+
store.getSnapshot = getSnapshot
|
|
238
|
+
store.getServerSnapshot = getServerSnapshot
|
|
229
239
|
|
|
230
240
|
// During hydration, use the server snapshot (if provided) so the tree
|
|
231
241
|
// matches the SSR output. Components like TanStack Router's ClientOnly
|
|
@@ -238,37 +248,67 @@ function makeDispatcherImpl() {
|
|
|
238
248
|
isHydrating && getServerSnapshot ? getServerSnapshot() : getSnapshot()
|
|
239
249
|
hook.state = value
|
|
240
250
|
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
251
|
+
const deps = [subscribe]
|
|
252
|
+
if (hook.deps === undefined || !depsEqual(hook.deps, deps)) {
|
|
253
|
+
hook.deps = deps
|
|
254
|
+
const effect: Effect = {
|
|
255
|
+
tag: 'layout',
|
|
256
|
+
deps,
|
|
257
|
+
destroy: undefined,
|
|
258
|
+
create: () => {
|
|
259
|
+
if (hook.cleanup) {
|
|
260
|
+
try {
|
|
261
|
+
hook.cleanup()
|
|
262
|
+
} catch {
|
|
263
|
+
// ignore cleanup failures
|
|
264
|
+
}
|
|
265
|
+
if (fiber.cleanups) {
|
|
266
|
+
const i = fiber.cleanups.indexOf(hook.cleanup)
|
|
267
|
+
if (i >= 0) fiber.cleanups.splice(i, 1)
|
|
268
|
+
}
|
|
269
|
+
hook.cleanup = null
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
let unsubscribed = false
|
|
273
|
+
const cleanup = () => {
|
|
274
|
+
unsubscribed = true
|
|
275
|
+
if (typeof unsubscribe === 'function') {
|
|
276
|
+
unsubscribe()
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
const forceUpdate = () => {
|
|
280
|
+
if (unsubscribed || fiber.unmounted) {
|
|
281
|
+
return
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
let next: T
|
|
285
|
+
try {
|
|
286
|
+
next = store.getSnapshot()
|
|
287
|
+
} catch {
|
|
288
|
+
scheduleUpdate(fiber)
|
|
289
|
+
return
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
if (!Object.is(hook.state, next)) {
|
|
293
|
+
hook.state = next
|
|
294
|
+
scheduleUpdate(fiber)
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
const unsubscribe = subscribe(forceUpdate)
|
|
298
|
+
|
|
299
|
+
// If we served the server snapshot, run a post-hydration check so
|
|
300
|
+
// components like `useHydrated()` flip from false → true after the
|
|
301
|
+
// initial render commits. Queued late so hydration finishes first.
|
|
302
|
+
if (isHydrating && store.getServerSnapshot) {
|
|
303
|
+
queueMicrotask(() => queueMicrotask(forceUpdate))
|
|
304
|
+
}
|
|
265
305
|
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
queueMicrotask(() => queueMicrotask(forceUpdate))
|
|
306
|
+
forceUpdate()
|
|
307
|
+
hook.cleanup = cleanup
|
|
308
|
+
return cleanup
|
|
309
|
+
},
|
|
271
310
|
}
|
|
311
|
+
enqueueEffect(fiber, effect)
|
|
272
312
|
}
|
|
273
313
|
return value
|
|
274
314
|
},
|
package/src/vite/index.ts
CHANGED
|
@@ -283,9 +283,27 @@ function resolveSpecifier(
|
|
|
283
283
|
}
|
|
284
284
|
}
|
|
285
285
|
|
|
286
|
+
interface OptimizeDepsWithInclude {
|
|
287
|
+
include?: Array<string>
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
function pruneOptimizeDepsInclude(
|
|
291
|
+
optimizeDeps: OptimizeDepsWithInclude | undefined,
|
|
292
|
+
blocked: ReadonlySet<string>,
|
|
293
|
+
): void {
|
|
294
|
+
if (!optimizeDeps?.include) return
|
|
295
|
+
|
|
296
|
+
optimizeDeps.include = optimizeDeps.include.filter((id) => {
|
|
297
|
+
const tailSpecifier = id.split('>').pop()?.trim() ?? id
|
|
298
|
+
return !blocked.has(id) && !blocked.has(tailSpecifier)
|
|
299
|
+
})
|
|
300
|
+
}
|
|
301
|
+
|
|
286
302
|
export function redact(options: RedactOptions = {}): any {
|
|
287
303
|
const skip = new Set(options.skip ?? [])
|
|
288
304
|
const entries = Object.entries(ALIASES).filter(([k]) => !skip.has(k))
|
|
305
|
+
const excludeList = entries.map(([k]) => k)
|
|
306
|
+
const optimizeDepsBlocked = new Set(excludeList)
|
|
289
307
|
const features = resolveFeatures(options.preset ?? 'full', options.features ?? {})
|
|
290
308
|
|
|
291
309
|
const resolvedMap: Record<string, string> = {}
|
|
@@ -302,12 +320,11 @@ export function redact(options: RedactOptions = {}): any {
|
|
|
302
320
|
done = true
|
|
303
321
|
}
|
|
304
322
|
|
|
305
|
-
return {
|
|
323
|
+
return [{
|
|
306
324
|
name: 'redact',
|
|
307
325
|
enforce: 'pre',
|
|
308
326
|
|
|
309
327
|
config() {
|
|
310
|
-
const excludeList = entries.map(([k]) => k)
|
|
311
328
|
// Single package — only one name to dedupe / no-external.
|
|
312
329
|
const noExt = ['@tanstack/redact']
|
|
313
330
|
const aliasMap = Object.fromEntries(entries.filter(([from, to]) => from !== to))
|
|
@@ -397,7 +414,21 @@ export function redact(options: RedactOptions = {}): any {
|
|
|
397
414
|
|
|
398
415
|
return resolvedMap[id] ?? null
|
|
399
416
|
},
|
|
400
|
-
}
|
|
417
|
+
}, {
|
|
418
|
+
name: 'redact:optimize-deps-guard',
|
|
419
|
+
enforce: 'post',
|
|
420
|
+
|
|
421
|
+
configResolved(config: any) {
|
|
422
|
+
// `optimizeDeps.exclude` loses when another plugin force-adds the same
|
|
423
|
+
// ids to `include`. That lets Vite pre-bundle real React next to Redact,
|
|
424
|
+
// producing duplicate dispatcher state. Prune after config settles so
|
|
425
|
+
// Redact's client/SSR shims stay canonical.
|
|
426
|
+
pruneOptimizeDepsInclude(config.optimizeDeps, optimizeDepsBlocked)
|
|
427
|
+
pruneOptimizeDepsInclude(config.environments?.client?.optimizeDeps, optimizeDepsBlocked)
|
|
428
|
+
pruneOptimizeDepsInclude(config.environments?.ssr?.optimizeDeps, optimizeDepsBlocked)
|
|
429
|
+
// Leave `environments.rsc` untouched. RSC depends on real React internals.
|
|
430
|
+
},
|
|
431
|
+
}]
|
|
401
432
|
}
|
|
402
433
|
|
|
403
434
|
export default redact
|