Skip to content

Commit a209b35

Browse files
ryansolidpaoloricciutiedemaineotonashixavlxsmnsyc
authored
Solid 1.5 (#1176)
* new batching, fix #1001, fix #1062 * fix #1019, resource state * pluggable storage on resource * Fix createMutable to handle reactivity in case element is undefined * Added tests * better fixes, ssr spread improvements * Add `has` trap for accurate `in` with stores and mutables (#1109) * Add `has` trap for accurate `in` with stores and mutables Fixes #1107 * Fix ?. typo * Remove optional chaining ?. * fix(types): fix mergeProps type when spreading array as params (#1028) This fixes the return type of mergeProps when an array is spread as params: `mergeProps(...propsArray)`, `mergeProps(...propsArray, props)`, and `mergeProps(props1, ...propsArray, props2)`. Previously these calls would ignore the type of the array being spread and all props after the spread e.g.: ```ts const merged = mergeProps({ a: 1 }, ...[{ b: 2 }], { c: 3 }); // { a: 1 } ``` - Allow mergeProps to be called with all manner of spread params and return the correct type. - As a consequence of the above, mergeProps' type allows calling it with no params. - Brought back `Simplify`, since it doesn't interfere with generics and improves readability of the result type. - Simplified and added comments for component.ts type tests. Additionally: - Improved types when generic props are present. Issues: - This doesn't correctly type spreading multiple arrays however, since typescript doesn't allow two "rest" params: `someFn(...[1], ...["2"], 3)` is inferred as `T = [...(string | number)[], number]` and not `T = [...number[], ...string[], number]`. In this case the union of types in the array is merged into a single type, which may not be entirely accurate. * Fix `Dynamic` types (#1116) * Fix `Dynamic` types * Fix `component` type * Fix `DynamicProps`, `ComponentProps`; Add `ValidComponent` * Fix `Dynamic` test for type fix * Fix `Dynamic` test to use `id` instead of `title` for DOM compatibility * Fix `component` to be required property * fix #1112 fix built in functions on proxy failing pass through * v1.5.0-beta.0 * cleanups on the server * update and rework build system * tweak turbo commands * remove clean command * update ci * decrease dependency on symlink * update lockfile * more type issues * fix build * SSR performance improvement * fix bug with ssr resolve * bump * Add build instructions to CONTRIBUTING (#1136) * Add pnpm build instructions to CONTRIBUTING * Fix Turbo link * fix: add explicit extensions and exports fields * errors on server while not flushed, many bug fixes * feat(types): createResource improvements (#1130) * feat(types): createResource improvements - Add typable `refetching`/`refetch` with default type `unknown` for backwards compatibility. - Remove unneeded generics. - Refactor `createResource` parameters to reduce casting. - Remove unneeded instances of casting, non-null assertations and `any`. - Fix `onHydrated` type, removing `refetching`. - Add `InitializedResource` types for overloads which define `initialValue`. - Changed `Error` to return `never` instead of `undefined`, since reading resources in such a state throws, so the values will never be used. - Updated docs slightly. - Fixed a test slightly (type of an unused parameter from `string` to `unknown`). Potential Issues: - Adding the initialized types might slightly break userland functions. However adding them is necessary to differentiate `{ initialValue: undefined }` from omitting `initialValue`, and for cases where `T` includes `undefined` to be typed correctly. - `store` should not need to accept `undefined` if `initialValue` is provided, but in order to make passing a generic `createSignal`-typed function work without an error, `init` and the type of the signal returned must be the same. - In various places `undefined` can still appear if a resource errors and refetches. As such `mutate` and `store` also need to handle `undefined` correctly. This might break typing for existing `mutate` calls which are typed without `undefined`. * test(types): add tests for createResource types * refactor(types): fix and clean up createResource types - Add `NoInfer` for options so that only the fetcher is used to infer the type of the resource - Remove some unneeded casting * feat(types): export initialized resource types Co-authored-by: Ryan Carniato <[email protected]> * simplify batching, reduce createComputed, fix #1122 enable transitions. * bump * remove computed from SuspenseList * Remove computed from createProvider * Remove a console.log (#1146) * fixes to suspenselist * useInitialValue on resources * fix #1138 dialog type, fix #1147 untrack ref, fix #1151 untrack cleanup * keyed control flow updates * bump * improve createSelector perf * draft 1.5 changelog * fix falsy check * faster asset rendering * children.toArray * refactor(types): change `createStore` types for a clearer error message (#1157) Specifically, this change targets these differences: - Initializing a store with a generic type which is not restricted to `object` now shows `Argument of type 'T' is not assignable to parameter of type 'object | undefined'. Type 'T' is not assignable to type 'object'` instead of `Argument of type '[T]' is not assignable to parameter of type '{} extends T ? [store?: T | undefined, options?: { name?: string | undefined; } | undefined] : [store: object & T, options?: { name?: string | undefined; } | undefined]'`. - Initializing a store with a non-generic, non-object type now shows that the expected parameter type is `object | undefined` instead of `never` (or `{} | undefiend` if trying to use `null`). * `resource.value` and small tweaks to resources * bump * experimenting with nodenext * fix * delete resource.value, defer to further deliberation * small naming tweaks * bump * update packages * bump * docs: add quotes to snippets (#1153) * better option naming for resource * add missing deps * Update Readme (#1137) * add missing type exports * bump * small updates * untrack JSON.stringify to avoid reactive side-effects on serialization. (#1177) * untrack JSON.stringify to avoid reactive side-effects on serialization. * untrack JSON.stringify to avoid reactive side-effects on serialization. * keep immdiately evaluated module code, below its indirect declared let dependencies. Co-authored-by: Ryan Carniato <[email protected]> Co-authored-by: Paolo Ricciuti <[email protected]> Co-authored-by: Erik Demaine <[email protected]> Co-authored-by: Xavier Loh <[email protected]> Co-authored-by: Alexis H. Munsayac <[email protected]> Co-authored-by: modderme123 <[email protected]> Co-authored-by: Kirill Mironov <[email protected]> Co-authored-by: Milo <[email protected]> Co-authored-by: Seanghay Yath <[email protected]> Co-authored-by: Mathieu Decaffmeyer <[email protected]> Co-authored-by: LiQuidProQuo <[email protected]>
1 parent 12b969d commit a209b35

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

92 files changed

+8470
-35947
lines changed

.github/workflows/main-ci.yml

+8-4
Original file line numberDiff line numberDiff line change
@@ -13,20 +13,24 @@ jobs:
1313
runs-on: ubuntu-latest
1414
steps:
1515
- uses: actions/checkout@v2
16+
- uses: pnpm/[email protected]
17+
with:
18+
version: 7
1619
- uses: actions/setup-node@v2
1720
with:
1821
node-version: 14
22+
cache: 'pnpm'
1923

2024
- name: Installing deps
21-
run: npm install
25+
run: pnpm install
2226

2327
- name: Building
24-
run: npm run build
28+
run: pnpm run build
2529

2630
- name: Testing & Coverage
2731
run: |
28-
npm run test
29-
npm run test:coverage
32+
pnpm run test
33+
pnpm run coverage
3034
3135
- name: Coveralls
3236
uses: coverallsapp/github-action@master

.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ lib/
55
coverage/
66
types/
77
.DS_Store
8+
.turbo/
89

910
packages/solid/src/jsx.d.ts
1011
packages/solid/web/server/server.d.ts

CHANGELOG.md

+125-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,125 @@
11
# Changelog
22

3+
## 1.5.0 - 2022-08-26
4+
5+
### Key Highlights
6+
7+
#### New Batching Behavior
8+
9+
Solid 1.4 patched a long time hole in Solid's behavior. Until that point Stores did not obey batching. However, it shone a light on something that should maybe have been obvious before. Batching behavior which stays in the past is basically broken for mutable data, No Solid only has `createMutable` and `produce` but with these sort of primitives the sole purpose is that you perform a sequence of actions, and batching not making this properly was basically broken. Adding an element to an array then removing another item shouldn't just skip the first operation.
10+
11+
```js
12+
const store = createMutable(["a", "b", "c"]);
13+
14+
const move = store.splice(1, 1);
15+
store.splice(0, 0, ...move);
16+
17+
// solid 1.4
18+
// ["b", "a", "b", "c"];
19+
20+
// solid 1.5
21+
// ["b", "a", "c"];
22+
```
23+
24+
After a bunch of careful thought and auditting we decided that Solid's `batch` function should behave the same as how reactivity propagates in the system once a signal is set. As in we just add observers to a queue to run, but if we read from a derived value that is stale it will evaluate eagerly. In so signals will update immediately in a batch now and any derived value will be on read. The only purpose of it is to group writes that begin outside of the reactive system, like in event handlers.
25+
26+
#### More Powerful Resources
27+
28+
Resources continue to get improvements. A common pattern in Islands frameworks like Astro is to fetch the data from the out side and pass it in. In this case you wouldn't want Solid to do the fetching on initial render or the serialization, but you still may want to pass it to a resource so it updates on any change. For that to work reactivity needs to run in the browser. The whole thing has been awkward to wire up but no longer.
29+
30+
`ssrLoadFrom` field lets you specify where the value comes from during ssr. The default is `server` which fetches on the server and serializes it for client hydration. But `initial` will use the `initialValue` instead and not do any fetching or addtional serialization.
31+
32+
```js
33+
const [user] = createResource(fetchUser, {
34+
initialValue: globalThis.DATA.user,
35+
ssrLoadFrom: "initial"
36+
});
37+
```
38+
39+
We've improved TypeScript by adding a new `state` field which covers a more detailed view of the Resource state beyond `loading` and `error`. You can now check whether a Resource is `"unresolved"`, `"pending"`, `"ready"`, `"refreshing"`, or `"error"`.
40+
41+
| state | value resolved | loading | has error |
42+
| ---------- | -------------- | ------- | --------- |
43+
| unresolved | No | No | No |
44+
| pending | No | Yes | No |
45+
| ready | Yes | No | No |
46+
| refreshing | Yes | Yes | No |
47+
| errored | No | No | Yes |
48+
49+
A widely requested feature has been allowing them to be stores. While higher level APIs are still being determined we now have a way to plugin the internal storage by passing something with the signature of a signal to the new _Experimental_ `storage` option.
50+
51+
```js
52+
function createDeepSignal<T>(value: T): Signal<T> {
53+
const [store, setStore] = createStore({
54+
value
55+
});
56+
return [
57+
() => store.value,
58+
(v: T) => {
59+
const unwrapped = unwrap(store.value);
60+
typeof v === "function" && (v = v(unwrapped));
61+
setStore("value", reconcile(v));
62+
return store.value;
63+
}
64+
] as Signal<T>;
65+
}
66+
67+
const [resource] = createResource(fetcher, {
68+
storage: createDeepSignal
69+
});
70+
```
71+
72+
#### Consolidated SSR
73+
74+
This release marks the end of years long effort to merge async and streaming mechanism. Since pre 1.0 these were seperate. Solid's original SSR efforts used reactivity on the server with different compilation. It was easiest to migrate synchronous and streaming rendering and for a time async had a different compilation. We got them on the same compilation 2 years ago but runtimes were different. Piece by piece things have progressed until finally async is now just streaming if flushed at the end.
75+
76+
This means some things have improved across the board. Async triggered Error Boundaries previously were only ever client rendered (throwing an error across the network), but now if they happen any time before sending to the browser they are server rendered. `onCleanup` now runs on the server if a branch changes. Keep in mind this is for rendering effects (like setting a status code) and not true side effects as not all rendering cleans up.
77+
78+
Finally we've had a chance to do a bunch of SSR rendering performance improvements. Including replacing our data serializer with an early copy of Dylan Piercey from [Marko](https://markojs.com)'s upcoming serializer for Marko 6. Which boasts performance improvements of up to 6x `devalue` which we used previously.
79+
80+
#### Keyed Control Flow
81+
82+
Solid's `<Show>` and `<Match>` control flow originally re-rendered based on value change rather than truthy-ness changing. This allowed the children to be "keyed" to the value but lead to over rendering in common cases. Pre 1.0 it was decided to make these only re-render when statement changed from `true` to `false` or vice versa, except for the callback form that was still keyed.
83+
84+
This worked pretty well except it was not obvious that a callback was keyed. So in 1.5 we are making this behavior explicit. If you want keyed you should specify it via attribute:
85+
86+
```js
87+
// re-render whenever user changes
88+
89+
// normal
90+
<Show when={user()} keyed>
91+
<div>{user().name}</div>
92+
</Show>
93+
94+
// callback
95+
<Show when={user()} keyed>
96+
{user => <div>{user.name}</div>}
97+
</Show>
98+
```
99+
100+
However, to not be breaking if a callback is present we will assume it's keyed. We still recommend you start adding these attributes (and TS will fail without them).
101+
102+
In the future we will introduce a non-keyed callback form as well so users can benefit from type narrowing in that case as well.
103+
104+
### Other Improvements
105+
106+
### `children.toArray`
107+
108+
Children helper now has the ability to be coerced to an array:
109+
110+
```js
111+
const resolved = children(() => props.children);
112+
resolved.toArray(); // definitely an array
113+
```
114+
115+
#### Better SSR Spreads
116+
117+
Finally fixed spread merging with non-spread properties during SSR, including the ability to merge children.
118+
119+
#### Better Error Handling
120+
121+
We weren't handling falsey errors previously. Now when Solid receives an error that isn't an `Error` object or a string it will coerce it into an `Unknown Error`.
122+
3123
## 1.4.0 - 2022-05-12
4124

5125
### New Features
@@ -19,6 +139,7 @@ const [user] = createResource(() => params.id, fetchUser);
19139
// fetches a user but only streams content after this resource has loaded
20140
const [user] = createResource(() => params.id, fetchUser, { deferStream: true });
21141
```
142+
22143
#### Top Level Arrays in Stores
23144

24145
Since Stores were first introduced it has always bugged me that the most common case, creating a list required nesting it under a property to track properly. Thanks to some exploration into proxy traps and iteration we now support top level arrays. In addition to its other modes, the Store setter will accept an array which allows for common operations.
@@ -39,7 +160,7 @@ setTodos([...todos, { id: 3, title: "New Todo", done: false }])
39160
<For each={todos}>{todo => <Todo todo={todo} />}</For>;
40161
```
41162

42-
Through this change we also stopped over execution when listening to specific properties. To support iteration Solid previously would notify the owning object of any array when an was index added/removed or object new property created or deleted on any object.
163+
Through this change we also stopped over execution when listening to specific properties. To support iteration Solid previously would notify the owning object of any array when an was index added/removed or object new property created or deleted on any object.
43164

44165
The one caveat is downstream optimized control flow that untrack index reads on arrays will now need to track the iterated object explicity. Solid exports a `$TRACK` symbol used to subscribe to the object and all its properties.
45166

@@ -50,7 +171,7 @@ Suspense and Transitions are amazingly powerful feature but occasionally you wan
50171
Solid's Resources now support being able to read the value without triggering Suspense. As long as it has loaded previously `latest` property won't cause fallback appear or Transitions to hold. This will always return the `latest` value regardless whether it is stale (ie.. a new value is being fetched) and will reactively update. This is super powerful in Transitions as you can use the Resources own `loading` state to know if it is stale. Since the Transition will hold while the critical data is loading, the loading state will not be applied to the in view screen until that Transition has ended. If the resource is still loading now you can show that it is stale.
51172

52173
```js
53-
const [resource] = createResource(source, fetcher)
174+
const [resource] = createResource(source, fetcher);
54175

55176
// read it as usual
56177
resource();
@@ -115,12 +236,14 @@ Writing to a store or mutable within `batch` (including effects) no longer immed
115236
#### Better Support for React JSX transform
116237

117238
We have added support to `solid-js/h` to support the new React JSX transform. You can use it directly in TypeScript by using:
239+
118240
```json
119241
{
120242
"jsx": "react-jsx",
121243
"jsxImportSource": "solid-js/h"
122244
}
123245
```
246+
124247
Keep in mind this has all the consequences of not using the custom transform. It means larger library code, slower performance, and worse ergonomics. Remember to wrap your reactive expressions in functions.
125248

126249
#### HyperScript now returns functions

CONTRIBUTING.md

+11
Original file line numberDiff line numberDiff line change
@@ -85,3 +85,14 @@ Contributing to ecosystem projects is just as important as contributing to Solid
8585
If you haven't found any interesting information on this page then we encourage you to start hacking at a Solid related utility or package that does. Building useful tools for fellow OSS ecosystem and Solid users enhances the whole platform.
8686

8787
We can't wait to see what you build!
88+
89+
## Building Solid
90+
91+
This repository uses [pnpm](https://pnpm.io/) and
92+
[Turborepo](https://turborepo.org/).
93+
If you want to build Solid from scratch, use the following steps:
94+
95+
1. `pnpm install` (install all dependencies)
96+
2. `pnpm run build`
97+
98+
You can then run all tests via `pnpm test`.

README.md

+2-1
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,8 @@ This will create a minimal, client-rendered application powered by [Vite](https:
5656
Or you can install the dependencies in your own setup. To use Solid with JSX (_recommended_), run:
5757

5858
```sh
59-
> npm install solid-js babel-preset-solid
59+
> npm i -D babel-preset-solid
60+
> npm i solid-js
6061
```
6162

6263
The easiest way to get set up is to add `babel-preset-solid` to your `.babelrc`, babel config for webpack, or rollup configuration:

lerna.json

-6
This file was deleted.

0 commit comments

Comments
 (0)