Skip to content

Commit

Permalink
Add more info to solid-usage.md
Browse files Browse the repository at this point in the history
  • Loading branch information
thetarnav committed Jan 24, 2025
1 parent b908bbd commit ffcb1e8
Showing 1 changed file with 70 additions and 64 deletions.
134 changes: 70 additions & 64 deletions solid-usage.md
Original file line number Diff line number Diff line change
@@ -1,38 +1,48 @@
# Current usage
# Usage of Solid internals and dev-apis in solid-devtools

## Node types
## Current usage

By node I mean any solid internal object, like owners, signals, roots, store-nodes, and anything user registers with `solid.DEV.registerGraph()`.
### Detecting Solid

There are many internal owner properties that are inspected to determine kind of node. — [source code](https://github.com/thetarnav/solid-devtools/blob/main/packages/debugger/src/main/utils.ts#L5-L86)
- This one cannot use internals nor dev-only apis because the goal is to detect solid on any page. — [source code](https://github.com/thetarnav/solid-devtools/blob/main/packages/shared/src/detect.ts)

### Issues
#### Issues

This is super brittle, some properties are set some time after the owner is created, most of the properties accessed are not used for anything else.
- The test is complicated, brittle, might have false-positives and doesn't tell you the solid version.

## Node names
### Node types

- `owner.name` or `signal.name` or `owner.component.name` or `owner.component.displayName`
By node I mean any solid internal object, like owners, signals, roots, store-nodes, and anything user registers with `solid.DEV.registerGraph()`.

### Issues
- There are many internal owner properties that are inspected to determine kind of node. — [source code](https://github.com/thetarnav/solid-devtools/blob/main/packages/debugger/src/main/utils.ts#L5-L86)

No one good way to give custom names to components.
#### Issues

This works but it's a side-effect.
- This is super brittle, some properties are set some time after the owner is created, most of the properties accessed are not used for anything else.

### Node names

- `owner.name` or `signal.name` or `owner.component.name` or `owner.component.displayName`

```js
Bar.displayName = "Foo.Bar"
```
#### Issues

While this is ugly
- No one good way to give custom names to components.

```ts
if (isDev) {
getOwner()!.name = "Foo.Bar"
}
```
This works but it's a side-effect.

## Roots
```js
Bar.displayName = "Foo.Bar"
```

While this is ugly

```ts
if (isDev) {
getOwner()!.name = "Foo.Bar"
}
```

### Roots

- `solid.DEV.hooks.afterCreateOwner()` for attaching the debugger to roots
- to gather top-level roots like `render()`
Expand All @@ -42,41 +52,45 @@ if (isDev) {
- so that if the root's parent disposes before the root, the root will need to be "reattached" to first found "alive" owner
- this is rather uncommon

### Issues
#### Issues

Any root created before `solid.DEV.hooks.afterCreateOwner` is set will be missed.\
This is annoying because the extension's content-script isn't garanteed to run before user scripts. Making the `solid-devtools` npm package and `import "solid-devtools"` required to capture all the roots.\
If there was access to any unowned root, the extension would work with any solid app with no setup.
- Any root created before `solid.DEV.hooks.afterCreateOwner` is set will be missed.\
This is annoying because the extension's content-script isn't garanteed to run before user scripts. Making the `solid-devtools` npm package and `import "solid-devtools"` required to capture all the roots.\
If there was access to any unowned root, the extension would work with any solid app with no setup.

## Computation updates
### Owners tree

- `owner.fn` is patched to observe when the computration reruns — [source code](https://github.com/thetarnav/solid-devtools/blob/main/packages/debugger/src/main/observe.ts#L50-L88)
- Reads `owner.owner` and `owner.owned` to walk the tree in both directions

- `owner.value` is read to get the current owner value and patched to listen to changes — [source code](https://github.com/thetarnav/solid-devtools/blob/main/packages/debugger/src/main/observe.ts#L98-L123)
- signals are being observed the same way
- this is also separate from observing `owner.fn` because not every rerun will cause the value to update *(thanks to `equals` option)*
### Owner disposing

- `owner.sources` — by listening to each of the sources, I'm able to tell which source caused the computation to rerun. — [source code](https://github.com/thetarnav/solid-devtools/blob/main/packages/logger/src/index.ts#L117-L180)
- Patching `owner.cleanups` to listen to cleanup of any owner — [source code](https://github.com/thetarnav/solid-devtools/blob/main/packages/debugger/src/main/utils.ts#L205-L227)

#### Issues

## Owners tree
- The cleanups are executed depth first—if I try to walk the tree on child's cleanup, I cannot tell if the parent is getting cleaned up as well or not. There is no `isDisposed` property.

Reads `owner.owner` and `owner.owned` to walk the tree in both directions
- There is no difference between disposing and rerunning—I have to listen to parents cleanup to when targetting disposal.

## Owner disposing
### Computation updates

Patching `owner.cleanups` to listen to cleanup of any owner [source code](https://github.com/thetarnav/solid-devtools/blob/main/packages/debugger/src/main/utils.ts#L205-L227)
- `owner.fn` is patched to observe when the computration reruns [source code](https://github.com/thetarnav/solid-devtools/blob/main/packages/debugger/src/main/observe.ts#L50-L88)

### Issues
- `owner.value` is read to get the current owner value and patched to listen to changes — [source code](https://github.com/thetarnav/solid-devtools/blob/main/packages/debugger/src/main/observe.ts#L98-L123)
- signals are being observed the same way
- this is also separate from observing `owner.fn` because not every rerun will cause the value to update *(thanks to `equals` option)*

The cleanups are executed depth first—if I try to walk the tree on child's cleanup, I cannot tell if the parent is getting cleaned up as well or not. There is no `isDisposed` property.
- `owner.sources` — by listening to each of the sources, I'm able to tell which source caused the computation to rerun. — [source code](https://github.com/thetarnav/solid-devtools/blob/main/packages/logger/src/index.ts#L117-L180)

## Dependency graph
### Dependency graph

- `owner.sources` and `owner.observers`
- `owner.sources` and `owner.observers` to crawl the graph

- `sourceValue.graph` — for signals to know to which owner they "belong to"

## Props
- `solid.DEV.hooks.afterUpdate()` is used as a trigger to update the dependency graph

### Props

- `solid.$PROXY` is used to check if the props object is a proxy

Expand All @@ -86,7 +100,7 @@ The cleanups are executed depth first—if I try to walk the tree on child's cle

- For proxy props I can only get keys with `Object.keys(props)`

### Issues
#### Issues

- I cannot intercept proxy props—users just see `foo: unknown` without the value

Expand All @@ -98,42 +112,34 @@ The cleanups are executed depth first—if I try to walk the tree on child's cle
- I would have to do `Object.defineProperty(owner, "props", {set})` to be able to patch props before component function executes probably
- [source code](https://github.com/solidjs/solid/blob/main/packages/solid/src/reactive/signal.ts#L1115-L1133)

## Store
### Store

- `store.unwrap()` with type reflection when serializing and reading stores

- `store.isWrappable()`

- `store.DEV.hooks.onStoreNodeUpdate()` for observing changes to stores — [source code](https://github.com/thetarnav/solid-devtools/blob/main/packages/debugger/src/inspector/store.ts#L27-L49)

### Issues
#### Issues

There is no connection between signals and the store-nodes they are being used in.\
- There is no connection between signals and the store-nodes they are being used in.\
So if there is an effect that listens to some store property *(e.g. `createEffect(() => store.foo)`)*, from devtools perspective this is just some random signal being observed in `owner.sources`.

## Source Map
### Signals and other values

- `owner.sourceMap` for getting which signals, stores or custom values belong to an owner.

- `solid.DEV.hooks.afterCreateSignal()` is useful for getting unowned signals
- which is important for the `export const [state, setState] = solid.createSignal({...})` style of state management — [source code](https://github.com/thetarnav/solid-devtools/blob/main/packages/debugger/src/setup.ts#L123-L136)

- `owner.sourceMap`
#### Issues

## Source Map
- The two issues with `afterCreateSignal` are addressed by https://github.com/solidjs/solid/pull/2396 and https://github.com/solidjs/solid/pull/2393

- `solid.DEV.hooks.afterCreateSignal()`
- `solid.DEV.registerGraph()`
- `owner.sourceMap`
- The other is similar to `afterCreateOwner` — signals created before the hook callback is set will be missed. This one is trickier to solve because signals don't have a clear lifecycle unlike roots.

## List
## Additional issues

- `solid.$PROXY` in [props](#props)
- `Object.defineProperty(props, key, {get})` in [props](#props)
- `solid.getListener() + solid.onCleanup()` in [props](#props)
- `store.unwrap()` in [store](#store)
- `store.isWrappable()` in [store](#store)
- `store.DEV.hooks.onStoreNodeUpdate()` in [store](#store)
- `solid.DEV.hooks.afterCreateOwner()` in [owners](#owners)
- `owner.owner` in [owners](#owners)
- `owner.cleanups` in [owners](#owners)
- There is no way to connect a render effect to the dom property it updates, so I cannot give any meaningfull info about them, or to which element they even belong.

# Future
- `onOwnerCleanup` - to not patch `owner.cleanups`
- it probably would be useful to have both `onBeforeOwnerCleanup` and `onAfterOwnerCleanup`
as the cleanups are executed depth first—if I try to walk the tree on child's cleanup, I cannot tell if the parent is getting cleaned up as well or not.
- There is no connection between a signal accessor and the signal object it belongs to.

0 comments on commit ffcb1e8

Please sign in to comment.