@automerge/automerge-repo-solid-primitives 2.2.0

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.
@@ -0,0 +1,183 @@
1
+ import {
2
+ type AutomergeUrl,
3
+ type DocHandle,
4
+ type PeerId,
5
+ Repo,
6
+ } from "@automerge/automerge-repo"
7
+ import { render, renderHook, waitFor } from "@solidjs/testing-library"
8
+ import { afterEach, describe, expect, it, vi } from "vitest"
9
+ import useDocHandle from "../src/useDocHandle.js"
10
+ import { RepoContext } from "../src/context.js"
11
+ import {
12
+ createEffect,
13
+ createSignal,
14
+ on,
15
+ Suspense,
16
+ untrack,
17
+ type ParentComponent,
18
+ } from "solid-js"
19
+ import type { UseDocHandleOptions } from "../src/types.js"
20
+
21
+ interface ExampleDoc {
22
+ foo: string
23
+ }
24
+
25
+ function getRepoWrapper(repo: Repo): ParentComponent {
26
+ return props => (
27
+ <RepoContext.Provider value={repo}>{props.children}</RepoContext.Provider>
28
+ )
29
+ }
30
+
31
+ describe("useDocHandle", () => {
32
+ afterEach(() => {
33
+ document.body.innerHTML = ""
34
+ })
35
+ const repo = new Repo({
36
+ peerId: "bob" as PeerId,
37
+ })
38
+
39
+ function setup() {
40
+ const handleA = repo.create<ExampleDoc>()
41
+ handleA.change(doc => (doc.foo = "A"))
42
+
43
+ const handleB = repo.create<ExampleDoc>()
44
+ handleB.change(doc => (doc.foo = "B"))
45
+
46
+ return {
47
+ repo,
48
+ handleA,
49
+ handleB,
50
+ wrapper: getRepoWrapper(repo),
51
+ }
52
+ }
53
+
54
+ const Component = (props: {
55
+ url: AutomergeUrl | undefined
56
+ onHandle: (handle: DocHandle<unknown> | undefined) => void
57
+ options?: UseDocHandleOptions
58
+ }) => {
59
+ const handle = useDocHandle(
60
+ () => props.url,
61
+ untrack(() => props.options)
62
+ )
63
+ createEffect(
64
+ on([handle], () => {
65
+ props.onHandle(handle())
66
+ })
67
+ )
68
+
69
+ return (
70
+ <Suspense fallback={<div>fallback</div>}>
71
+ <button>{handle.latest?.url ?? "🕯️🕯️🕯️🕯️"}</button>
72
+ </Suspense>
73
+ )
74
+ }
75
+
76
+ it("loads a handle", async () => {
77
+ const { handleA, wrapper } = setup()
78
+ const onHandle = vi.fn()
79
+
80
+ render(() => <Component url={handleA.url} onHandle={onHandle} />, {
81
+ wrapper,
82
+ })
83
+ await waitFor(() => expect(onHandle).toHaveBeenLastCalledWith(handleA))
84
+ })
85
+
86
+ it("throws if called without any kinda repo", async () => {
87
+ const { handleA } = setup()
88
+ const onHandle = vi.fn()
89
+
90
+ expect(() =>
91
+ render(() => <Component url={handleA.url} onHandle={onHandle} />, {})
92
+ ).toThrowErrorMatchingInlineSnapshot(
93
+ `[Error: use outside <RepoContext> requires options.repo]`
94
+ )
95
+ })
96
+
97
+ it("works without a context if given a repo in options", async () => {
98
+ const { handleA } = setup()
99
+ const onHandle = vi.fn()
100
+
101
+ render(
102
+ () => (
103
+ <Component url={handleA.url} onHandle={onHandle} options={{ repo }} />
104
+ ),
105
+ {}
106
+ )
107
+ await waitFor(() => expect(onHandle).toHaveBeenLastCalledWith(handleA))
108
+ })
109
+
110
+ it("returns undefined when no url given", async () => {
111
+ const { wrapper } = setup()
112
+ const onHandle = vi.fn()
113
+
114
+ render(() => <Component url={undefined} onHandle={onHandle} />, { wrapper })
115
+ await waitFor(() => expect(onHandle).toHaveBeenLastCalledWith(undefined))
116
+ })
117
+
118
+ it("updates the handle when the url changes", async () => {
119
+ const { handleA, handleB, wrapper } = setup()
120
+ const onHandle = vi.fn()
121
+ const [url, updateURL] = createSignal<AutomergeUrl | undefined>(undefined)
122
+
123
+ let hookResult = renderHook(useDocHandle, {
124
+ initialProps: [url],
125
+ wrapper,
126
+ })
127
+
128
+ let componentResult = render(
129
+ () => <Component url={url()} onHandle={onHandle} />,
130
+ { wrapper }
131
+ )
132
+ let button = componentResult.getByRole("button")
133
+
134
+ // set url to doc A
135
+ updateURL(handleA.url)
136
+ await waitFor(() => expect(hookResult.result.latest).toBe(handleA))
137
+ await waitFor(() => expect(onHandle).toHaveBeenLastCalledWith(handleA))
138
+
139
+ await waitFor(() => expect(button).toHaveTextContent(handleA.url))
140
+
141
+ // set url to doc B
142
+ updateURL(handleB.url)
143
+ await waitFor(() => expect(hookResult.result.latest?.url).toBe(handleB.url))
144
+
145
+ await waitFor(() => expect(button).toHaveTextContent(handleB.url))
146
+
147
+ // set url to undefined
148
+ updateURL(undefined)
149
+ await waitFor(() => expect(hookResult.result.latest?.url).toBe(undefined))
150
+
151
+ await waitFor(() => expect(button).toHaveTextContent("🕯️🕯️🕯️🕯️"))
152
+ })
153
+
154
+ it("does not return undefined after the url is updated", async () => {
155
+ const { wrapper, handleA, handleB } = setup()
156
+ const onHandle = vi.fn()
157
+ const [url, updateURL] = createSignal<AutomergeUrl | undefined>(handleA.url)
158
+
159
+ render(() => <Component url={url()} onHandle={onHandle} />, { wrapper })
160
+ await waitFor(() => expect(onHandle).toHaveBeenLastCalledWith(handleA))
161
+
162
+ const onHandle2 = vi.fn()
163
+
164
+ // set url to doc B
165
+ updateURL(handleB.url)
166
+ await waitFor(() => expect(onHandle2).not.toHaveBeenCalledWith(undefined))
167
+ })
168
+
169
+ it("does not return a handle for a different url after the url is updated", async () => {
170
+ const { wrapper, handleA, handleB } = setup()
171
+ const onHandle = vi.fn()
172
+ const [url, updateURL] = createSignal<AutomergeUrl | undefined>(handleA.url)
173
+
174
+ render(() => <Component url={url()} onHandle={onHandle} />, { wrapper })
175
+ await waitFor(() => expect(onHandle).toHaveBeenLastCalledWith(handleA))
176
+
177
+ const onHandle2 = vi.fn()
178
+
179
+ // set url to doc B
180
+ updateURL(handleB.url)
181
+ await waitFor(() => expect(onHandle2).not.toHaveBeenCalledWith(handleA))
182
+ })
183
+ })
@@ -0,0 +1,337 @@
1
+ import { type PeerId, Repo, type AutomergeUrl } from "@automerge/automerge-repo"
2
+ import { render, renderHook, testEffect } from "@solidjs/testing-library"
3
+ import { describe, expect, it, vi } from "vitest"
4
+ import { RepoContext } from "../src/context.js"
5
+ import {
6
+ createEffect,
7
+ createSignal,
8
+ type Accessor,
9
+ type ParentComponent,
10
+ } from "solid-js"
11
+ import useDocument from "../src/useDocument.js"
12
+
13
+ describe("useDocument", () => {
14
+ function setup() {
15
+ const repo = new Repo({
16
+ peerId: "bob" as PeerId,
17
+ })
18
+
19
+ const create = () =>
20
+ repo.create<ExampleDoc>({
21
+ key: "value",
22
+ array: [1, 2, 3],
23
+ hellos: [{ hello: "world" }, { hello: "hedgehog" }],
24
+ projects: [
25
+ { title: "one", items: [{ title: "go shopping" }] },
26
+ { title: "two", items: [] },
27
+ ],
28
+ })
29
+
30
+ const handle = create()
31
+ const wrapper: ParentComponent = props => {
32
+ return (
33
+ <RepoContext.Provider value={repo}>
34
+ {props.children}
35
+ </RepoContext.Provider>
36
+ )
37
+ }
38
+
39
+ return {
40
+ repo,
41
+ handle,
42
+ wrapper,
43
+ create,
44
+ options: { repo },
45
+ }
46
+ }
47
+
48
+ it("should notify on a property change", async () => {
49
+ const { create, options } = setup()
50
+
51
+ await testEffect(done => {
52
+ const [doc, handle] = useDocument<ExampleDoc>(create().url, options)
53
+ createEffect((run: number = 0) => {
54
+ if (run == 0) {
55
+ expect(doc()?.key).toBe("value")
56
+ handle()?.change(doc => (doc.key = "hello world!"))
57
+ } else if (run == 1) {
58
+ expect(doc()?.key).toBe("hello world!")
59
+ handle()?.change(doc => (doc.key = "friday night!"))
60
+ } else if (run == 2) {
61
+ expect(doc()?.key).toBe("friday night!")
62
+ done()
63
+ }
64
+ return run + 1
65
+ })
66
+ })
67
+ })
68
+
69
+ it("should not apply patches multiple times just because there are multiple projections", async () => {
70
+ const {
71
+ handle: { url },
72
+ options,
73
+ } = setup()
74
+
75
+ const done2 = testEffect(done => {
76
+ const [two, handle] = useDocument<ExampleDoc>(url, options)
77
+ createEffect((run: number = 0) => {
78
+ if (run == 0) {
79
+ expect(two()?.array).toEqual([1, 2, 3])
80
+ } else if (run == 1) {
81
+ expect(two()?.array).toEqual([1, 2, 3, 4])
82
+ handle()?.change(doc => doc.array.push(5))
83
+ } else if (run == 2) {
84
+ expect(two()?.array).toEqual([1, 2, 3, 4, 5])
85
+ done()
86
+ }
87
+ return run + 1
88
+ })
89
+ })
90
+
91
+ const done1 = testEffect(done => {
92
+ const [one, handle] = useDocument<ExampleDoc>(url, options)
93
+ createEffect((run: number = 0) => {
94
+ if (run == 0) {
95
+ expect(one()?.array).toEqual([1, 2, 3])
96
+ handle()?.change(doc => doc.array.push(4))
97
+ } else if (run == 1) {
98
+ expect(one()?.array).toEqual([1, 2, 3, 4])
99
+ } else if (run == 2) {
100
+ expect(one()?.array).toEqual([1, 2, 3, 4, 5])
101
+ done()
102
+ }
103
+ return run + 1
104
+ })
105
+ })
106
+
107
+ return Promise.allSettled([done1, done2])
108
+ })
109
+
110
+ it("should work with a signal url", async () => {
111
+ const { create, wrapper } = setup()
112
+ const [url, setURL] = createSignal<AutomergeUrl>()
113
+ const {
114
+ result: [doc, handle],
115
+ owner,
116
+ } = renderHook(useDocument<ExampleDoc>, {
117
+ initialProps: [url],
118
+ wrapper,
119
+ })
120
+ const done = testEffect(done => {
121
+ createEffect((run: number = 0) => {
122
+ if (run == 0) {
123
+ expect(doc()?.key).toBe(undefined)
124
+ setURL(create().url)
125
+ } else if (run == 1) {
126
+ expect(doc()?.key).toBe("value")
127
+ handle()?.change(doc => (doc.key = "hello world!"))
128
+ } else if (run == 2) {
129
+ expect(doc()?.key).toBe("hello world!")
130
+ setURL(create().url)
131
+ } else if (run == 3) {
132
+ expect(doc()?.key).toBe("value")
133
+ handle()?.change(doc => (doc.key = "friday night!"))
134
+ } else if (run == 4) {
135
+ expect(doc()?.key).toBe("friday night!")
136
+ done()
137
+ }
138
+
139
+ return run + 1
140
+ })
141
+ }, owner!)
142
+ return done
143
+ })
144
+
145
+ it("should clear the store when the url signal returns to nothing", async () => {
146
+ const { create, options } = setup()
147
+ const [url, setURL] = createSignal<AutomergeUrl>()
148
+
149
+ const done = testEffect(done => {
150
+ const [doc, handle] = useDocument<ExampleDoc>(url, options)
151
+ createEffect((run: number = 0) => {
152
+ if (run == 0) {
153
+ expect(doc()?.key).toBe(undefined)
154
+ expect(handle()).toBe(undefined)
155
+ setURL(create().url)
156
+ } else if (run == 1) {
157
+ expect(doc()?.key).toBe("value")
158
+ expect(handle()).not.toBe(undefined)
159
+ setURL(undefined)
160
+ } else if (run == 2) {
161
+ expect(doc()?.key).toBe(undefined)
162
+ expect(handle()).toBe(undefined)
163
+ setURL(create().url)
164
+ } else if (run == 3) {
165
+ expect(doc()?.key).toBe("value")
166
+ expect(handle()).not.toBe(undefined)
167
+ done()
168
+ }
169
+
170
+ return run + 1
171
+ })
172
+ })
173
+ return done
174
+ })
175
+
176
+ it("should not return the wrong store when url changes", async () => {
177
+ const { create, repo } = setup()
178
+ const h1 = create()
179
+ const h2 = create()
180
+ const u1 = h1.url
181
+ const u2 = h2.url
182
+
183
+ const [stableURL] = createSignal(u1)
184
+ const [changingURL, setChangingURL] = createSignal(u1)
185
+
186
+ await testEffect(async done => {
187
+ const result = render(() => {
188
+ function Component(props: {
189
+ stableURL: Accessor<AutomergeUrl>
190
+ changingURL: Accessor<AutomergeUrl>
191
+ }) {
192
+ const [stableDoc] = useDocument<ExampleDoc>(() => props.stableURL())
193
+
194
+ const [changingDoc] = useDocument<ExampleDoc>(() =>
195
+ props.changingURL()
196
+ )
197
+
198
+ return (
199
+ <>
200
+ <div data-testid="key-stable">{stableDoc()?.key}</div>
201
+ <div data-testid="key-changing">{changingDoc()?.key}</div>
202
+ </>
203
+ )
204
+ }
205
+
206
+ return (
207
+ <RepoContext.Provider value={repo}>
208
+ <Component stableURL={stableURL} changingURL={changingURL} />
209
+ </RepoContext.Provider>
210
+ )
211
+ })
212
+
213
+ h2.change(doc => (doc.key = "document-2"))
214
+ expect(result.getByTestId("key-stable").textContent).toBe("value")
215
+ expect(result.getByTestId("key-changing").textContent).toBe("value")
216
+
217
+ h1.change(doc => (doc.key = "hello"))
218
+ await new Promise(yay => setImmediate(yay))
219
+
220
+ expect(result.getByTestId("key-stable").textContent).toBe("hello")
221
+ expect(result.getByTestId("key-changing").textContent).toBe("hello")
222
+
223
+ setChangingURL(u2)
224
+ await new Promise(yay => setImmediate(yay))
225
+ expect(result.getByTestId("key-stable").textContent).toBe("hello")
226
+ expect(result.getByTestId("key-changing").textContent).toBe("document-2")
227
+ h2.change(doc => (doc.key = "world"))
228
+
229
+ setChangingURL(u1)
230
+ await new Promise(yay => setImmediate(yay))
231
+ expect(result.getByTestId("key-stable").textContent).toBe("hello")
232
+ expect(result.getByTestId("key-changing").textContent).toBe("hello")
233
+
234
+ setChangingURL(u2)
235
+ await new Promise(yay => setImmediate(yay))
236
+
237
+ expect(result.getByTestId("key-stable").textContent).toBe("hello")
238
+ expect(result.getByTestId("key-changing").textContent).toBe("world")
239
+
240
+ done()
241
+ })
242
+ })
243
+
244
+ it("should work with a slow handle", async () => {
245
+ const { repo } = setup()
246
+
247
+ const slowHandle = repo.create({ im: "slow" })
248
+ const originalFind = repo.find.bind(repo)
249
+ repo.find = vi.fn().mockImplementation(async (...args) => {
250
+ await new Promise(resolve => setTimeout(resolve, 100))
251
+ // @ts-expect-error i'm ok i promise
252
+ return await originalFind(...args)
253
+ })
254
+
255
+ const done = testEffect(done => {
256
+ const [doc] = useDocument<{ im: "slow" }>(() => slowHandle.url, {
257
+ repo,
258
+ "~skipInitialValue": true,
259
+ })
260
+ createEffect((run: number = 0) => {
261
+ if (run == 0) {
262
+ expect(doc()?.im).toBe(undefined)
263
+ } else if (run == 1) {
264
+ expect(doc()?.im).toBe("slow")
265
+ done()
266
+ }
267
+ return run + 1
268
+ })
269
+ })
270
+ repo.find = originalFind
271
+ return done
272
+ })
273
+
274
+ it("should not notify on properties nobody cares about", async () => {
275
+ const {
276
+ handle: { url },
277
+ options,
278
+ } = setup()
279
+
280
+ let fn = vi.fn()
281
+
282
+ const [doc, handle] = useDocument<ExampleDoc>(url, options)
283
+
284
+ testEffect(() => {
285
+ createEffect(() => {
286
+ fn(doc()?.projects[1].title)
287
+ })
288
+ })
289
+ const arrayDotThree = testEffect(done => {
290
+ createEffect((run: number = 0) => {
291
+ if (run == 0) {
292
+ expect(doc()?.array[3]).toBeUndefined()
293
+ handle()?.change(doc => (doc.array[2] = 22))
294
+ handle()?.change(doc => (doc.key = "hello world!"))
295
+ handle()?.change(doc => (doc.array[1] = 11))
296
+ handle()?.change(doc => (doc.array[3] = 145))
297
+ } else if (run == 1) {
298
+ expect(doc()?.array[3]).toBe(145)
299
+ handle()?.change(doc => (doc.projects[0].title = "hello world!"))
300
+ handle()?.change(
301
+ doc => (doc.projects[0].items[0].title = "hello world!")
302
+ )
303
+ handle()?.change(doc => (doc.array[3] = 147))
304
+ } else if (run == 2) {
305
+ expect(doc()?.array[3]).toBe(147)
306
+ done()
307
+ }
308
+ return run + 1
309
+ })
310
+ })
311
+
312
+ const projectZeroItemZeroTitle = testEffect(done => {
313
+ createEffect((run: number = 0) => {
314
+ if (run == 0) {
315
+ expect(doc()?.projects[0].items[0].title).toBe("hello world!")
316
+ done()
317
+ }
318
+ return run + 1
319
+ })
320
+ })
321
+
322
+ expect(fn).toHaveBeenCalledOnce()
323
+ expect(fn).toHaveBeenCalledWith("two")
324
+
325
+ return Promise.all([arrayDotThree, projectZeroItemZeroTitle])
326
+ })
327
+ })
328
+
329
+ interface ExampleDoc {
330
+ key: string
331
+ array: number[]
332
+ hellos: { hello: string }[]
333
+ projects: {
334
+ title: string
335
+ items: { title: string; complete?: number }[]
336
+ }[]
337
+ }
@@ -0,0 +1,34 @@
1
+ import { Repo } from "@automerge/automerge-repo"
2
+ import { render } from "@solidjs/testing-library"
3
+ import { describe, expect, test, vi } from "vitest"
4
+ import type { ParentComponent } from "solid-js"
5
+ import useRepo from "../src/useRepo.js"
6
+ import { RepoContext } from "../src/context.js"
7
+
8
+ describe("useRepo", () => {
9
+ const Component = ({ onRepo }: { onRepo: (repo: Repo) => void }) => {
10
+ const repo = useRepo()
11
+ onRepo(repo)
12
+ return null
13
+ }
14
+
15
+ test("should error when context unavailable", () => {
16
+ // Prevent console spam by swallowing console.error "uncaught error" message
17
+ const spy = vi.spyOn(console, "error")
18
+ spy.mockImplementation(() => {})
19
+ expect(() => render(() => <Component onRepo={() => {}} />)).toThrow(
20
+ /RepoContext/
21
+ )
22
+ spy.mockRestore()
23
+ })
24
+
25
+ test("should return repo from context", () => {
26
+ const repo = new Repo()
27
+ const wrapper: ParentComponent = props => (
28
+ <RepoContext.Provider value={repo}>{props.children}</RepoContext.Provider>
29
+ )
30
+ const onRepo = vi.fn()
31
+ render(() => <Component onRepo={onRepo} />, { wrapper })
32
+ expect(onRepo).toHaveBeenLastCalledWith(repo)
33
+ })
34
+ })
@@ -0,0 +1,21 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ESNext",
4
+ "module": "ESNext",
5
+ "moduleResolution": "Bundler",
6
+ "emitDeclarationOnly": true,
7
+ "allowImportingTsExtensions": true,
8
+ "esModuleInterop": true,
9
+ "forceConsistentCasingInFileNames": true,
10
+ "isolatedModules": true,
11
+ "isolatedDeclarations": true,
12
+ "strict": true,
13
+ "skipLibCheck": true,
14
+ "composite": true,
15
+ "pretty": true,
16
+ "rootDir": "./src",
17
+ "rewriteRelativeImportExtensions": true,
18
+ "outDir": "./out"
19
+ },
20
+ "include": ["src"]
21
+ }
package/tsconfig.json ADDED
@@ -0,0 +1,11 @@
1
+ {
2
+ "compilerOptions": {
3
+ "noEmit": true
4
+ },
5
+ "include": [],
6
+ "files": [],
7
+ "references": [
8
+ { "path": "./tsconfig.build.json" },
9
+ { "path": "./tsconfig.test.json" }
10
+ ]
11
+ }
@@ -0,0 +1,20 @@
1
+ {
2
+ "compilerOptions": {
3
+ "jsx": "preserve",
4
+ "jsxImportSource": "solid-js",
5
+ "types": ["@testing-library/jest-dom"],
6
+ "target": "ESNext",
7
+ "module": "ESNext",
8
+ "moduleResolution": "Bundler",
9
+ "declaration": true,
10
+ "declarationMap": true,
11
+ "esModuleInterop": true,
12
+ "forceConsistentCasingInFileNames": true,
13
+ "strict": true,
14
+ "skipLibCheck": true,
15
+ "isolatedModules": true,
16
+ "composite": true,
17
+ "noEmit": true
18
+ },
19
+ "include": ["test/**/*.tsx", "src/**/*.ts"]
20
+ }
package/typedoc.json ADDED
@@ -0,0 +1,5 @@
1
+ {
2
+ "extends": ["../../typedoc.base.json"],
3
+ "entryPoints": ["src/index.ts"],
4
+ "readme": "none"
5
+ }
package/vite.config.ts ADDED
@@ -0,0 +1,41 @@
1
+ import { defineConfig } from "vitest/config"
2
+ import solid from "vite-plugin-solid"
3
+ import { resolve } from "path"
4
+ import dts from "vite-plugin-dts"
5
+ import wasm from "vite-plugin-wasm"
6
+ import { visualizer } from "rollup-plugin-visualizer"
7
+
8
+ export default defineConfig({
9
+ plugins: [
10
+ solid(),
11
+ wasm(),
12
+ dts({
13
+ insertTypesEntry: true,
14
+ tsconfigPath: "./tsconfig.build.json",
15
+ }),
16
+ process.env.VISUALIZE && visualizer(),
17
+ ],
18
+ build: {
19
+ lib: {
20
+ entry: resolve(__dirname, "src/index.ts"),
21
+ formats: ["es"],
22
+ fileName: "index",
23
+ },
24
+ target: "esnext",
25
+ rollupOptions: {
26
+ external: [
27
+ "solid-js",
28
+ "@automerge/automerge",
29
+ "cabbages",
30
+ "solid-js/store",
31
+ ],
32
+ },
33
+ },
34
+ resolve: {
35
+ conditions: ["solid", "browser", "module", "import"],
36
+ mainFields: ["browser", "module", "main"],
37
+ },
38
+ worker: {
39
+ plugins: () => [wasm()],
40
+ },
41
+ })
@@ -0,0 +1,25 @@
1
+ import { defineConfig, mergeConfig } from "vitest/config"
2
+ import rootConfig from "../../vitest.config"
3
+ import solid from "vite-plugin-solid"
4
+
5
+ export default mergeConfig(
6
+ rootConfig,
7
+ defineConfig({
8
+ plugins: [solid()],
9
+ test: {
10
+ environment: "jsdom",
11
+ deps: {
12
+ optimizer: {
13
+ web: {
14
+ enabled: true,
15
+ },
16
+ },
17
+ },
18
+ server: {
19
+ deps: {
20
+ inline: [/solid-js/],
21
+ },
22
+ },
23
+ },
24
+ })
25
+ )