Skip to content

Commit 2815390

Browse files
committed
fix: fix issue with solid start
1 parent 5372697 commit 2815390

3 files changed

Lines changed: 177 additions & 129 deletions

File tree

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
import { createMemo, createSignal, onMount, sharedConfig, splitProps, untrack } from "solid-js";
2+
import { isServer } from "solid-js/web";
3+
import type { Component, ComponentProps, JSX, Setter } from "solid-js";
4+
5+
/**
6+
*
7+
* Read more: https://docs.solidjs.com/solid-start/reference/client/client-only
8+
*/
9+
// not using Suspense
10+
export default function clientOnly<T extends Component<any>>(
11+
fn: () => Promise<{
12+
default: T;
13+
}>,
14+
options: { lazy?: boolean } = {}
15+
) {
16+
if (isServer) return (props: ComponentProps<T> & { fallback?: JSX.Element }) => props.fallback;
17+
18+
const [comp, setComp] = createSignal<T>();
19+
!options.lazy && load(fn, setComp);
20+
return (props: ComponentProps<T>) => {
21+
let Comp: T | undefined;
22+
let m: boolean;
23+
const [, rest] = splitProps(props, ["fallback"]);
24+
options.lazy && load(fn, setComp);
25+
if ((Comp = comp()) && !sharedConfig.context) return Comp(rest);
26+
const [mounted, setMounted] = createSignal(!sharedConfig.context);
27+
onMount(() => setMounted(true));
28+
return createMemo(
29+
() => (
30+
(Comp = comp()), (m = mounted()), untrack(() => (Comp && m ? Comp(rest) : props.fallback))
31+
)
32+
);
33+
};
34+
}
35+
36+
function load<T>(
37+
fn: () => Promise<{
38+
default: T;
39+
}>,
40+
setComp: Setter<T>
41+
) {
42+
fn().then(m => setComp(() => m.default));
43+
}
Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
1+
import { TanStackDevtoolsCore } from '@tanstack/devtools'
2+
import { createEffect, createSignal, onCleanup, onMount } from 'solid-js'
3+
import { Portal } from 'solid-js/web'
4+
import type { JSX } from 'solid-js'
5+
import type {
6+
ClientEventBusConfig,
7+
TanStackDevtoolsConfig,
8+
TanStackDevtoolsPlugin,
9+
} from '@tanstack/devtools'
10+
11+
type SolidPluginRender = JSX.Element | (() => JSX.Element)
12+
const convertRender = (
13+
el: HTMLDivElement | HTMLHeadingElement,
14+
Component: SolidPluginRender,
15+
) => (
16+
<Portal mount={el}>
17+
{typeof Component === 'function' ? <Component /> : Component}
18+
</Portal>
19+
)
20+
21+
export type TanStackDevtoolsSolidPlugin = Omit<
22+
TanStackDevtoolsPlugin,
23+
'render' | 'name'
24+
> & {
25+
/**
26+
* The render function can be a SolidJS element or a function that returns a SolidJS element.
27+
* If it's a function, it will be called to render the plugin, otherwise it will be rendered directly.
28+
*
29+
* Example:
30+
* ```ts
31+
* {
32+
* render: () => <CustomPluginComponent />,
33+
* }
34+
* ```
35+
* or
36+
* ```ts
37+
* {
38+
* render: <CustomPluginComponent />,
39+
* }
40+
* ```
41+
*/
42+
render: SolidPluginRender
43+
/**
44+
* Name to be displayed in the devtools UI.
45+
* If a string, it will be used as the plugin name.
46+
* If a function, it will be called with the mount element.
47+
*
48+
* Example:
49+
* ```ts
50+
* {
51+
* name: "Your Plugin",
52+
* render: () => <CustomPluginComponent />,
53+
* }
54+
* ```
55+
* or
56+
* ```ts
57+
* {
58+
* name: <h1>Your Plugin title</h1>,
59+
* render: () => <CustomPluginComponent />,
60+
* }
61+
* ```
62+
*/
63+
name: string | SolidPluginRender
64+
}
65+
export interface TanstackDevtoolsInit {
66+
/**
67+
* Array of plugins to be used in the devtools.
68+
* Each plugin should have a `render` function that returns a React element or a function
69+
*
70+
* Example:
71+
* ```jsx
72+
* <TanstackDevtools
73+
* plugins={[
74+
* {
75+
* id: "your-plugin-id",
76+
* name: "Your Plugin",
77+
* render: <CustomPluginComponent />,
78+
* }
79+
* ]}
80+
* />
81+
* ```
82+
*/
83+
plugins?: Array<TanStackDevtoolsSolidPlugin>
84+
/**
85+
* Configuration for the devtools shell. These configuration options are used to set the
86+
* initial state of the devtools when it is started for the first time. Afterwards,
87+
* the settings are persisted in local storage and changed through the settings panel.
88+
*/
89+
config?: Partial<TanStackDevtoolsConfig>
90+
/**
91+
* Configuration for the TanStack Devtools client event bus.
92+
*/
93+
eventBusConfig?: ClientEventBusConfig
94+
}
95+
96+
export default function SolidDevtoolsCore({
97+
config,
98+
plugins,
99+
eventBusConfig,
100+
}: TanstackDevtoolsInit) {
101+
const [devtools] = createSignal(
102+
new TanStackDevtoolsCore({
103+
config,
104+
eventBusConfig,
105+
plugins: plugins?.map((plugin) => ({
106+
...plugin,
107+
name:
108+
typeof plugin.name === 'string'
109+
? plugin.name
110+
: // The check above confirms that `plugin.name` is of Render type
111+
(el) => convertRender(el, plugin.name as SolidPluginRender),
112+
render: (el: HTMLDivElement) => convertRender(el, plugin.render),
113+
})),
114+
}),
115+
)
116+
let devToolRef: HTMLDivElement | undefined
117+
createEffect(() => {
118+
devtools().setConfig({ config })
119+
})
120+
onMount(() => {
121+
if (devToolRef) {
122+
devtools().mount(devToolRef)
123+
124+
onCleanup(() => {
125+
devtools().unmount()
126+
})
127+
}
128+
})
129+
return <div style={{ height: '100%' }} ref={devToolRef} />
130+
}
Lines changed: 4 additions & 129 deletions
Original file line numberDiff line numberDiff line change
@@ -1,130 +1,5 @@
1-
import { TanStackDevtoolsCore } from '@tanstack/devtools'
2-
import { createEffect, createSignal, onCleanup, onMount } from 'solid-js'
3-
import { Portal } from 'solid-js/web'
4-
import type { JSX } from 'solid-js'
5-
import type {
6-
ClientEventBusConfig,
7-
TanStackDevtoolsConfig,
8-
TanStackDevtoolsPlugin,
9-
} from '@tanstack/devtools'
1+
import clientOnly from "./client-only";
102

11-
type SolidPluginRender = JSX.Element | (() => JSX.Element)
12-
const convertRender = (
13-
el: HTMLDivElement | HTMLHeadingElement,
14-
Component: SolidPluginRender,
15-
) => (
16-
<Portal mount={el}>
17-
{typeof Component === 'function' ? <Component /> : Component}
18-
</Portal>
19-
)
20-
21-
export type TanStackDevtoolsSolidPlugin = Omit<
22-
TanStackDevtoolsPlugin,
23-
'render' | 'name'
24-
> & {
25-
/**
26-
* The render function can be a SolidJS element or a function that returns a SolidJS element.
27-
* If it's a function, it will be called to render the plugin, otherwise it will be rendered directly.
28-
*
29-
* Example:
30-
* ```ts
31-
* {
32-
* render: () => <CustomPluginComponent />,
33-
* }
34-
* ```
35-
* or
36-
* ```ts
37-
* {
38-
* render: <CustomPluginComponent />,
39-
* }
40-
* ```
41-
*/
42-
render: SolidPluginRender
43-
/**
44-
* Name to be displayed in the devtools UI.
45-
* If a string, it will be used as the plugin name.
46-
* If a function, it will be called with the mount element.
47-
*
48-
* Example:
49-
* ```ts
50-
* {
51-
* name: "Your Plugin",
52-
* render: () => <CustomPluginComponent />,
53-
* }
54-
* ```
55-
* or
56-
* ```ts
57-
* {
58-
* name: <h1>Your Plugin title</h1>,
59-
* render: () => <CustomPluginComponent />,
60-
* }
61-
* ```
62-
*/
63-
name: string | SolidPluginRender
64-
}
65-
interface TanstackDevtoolsInit {
66-
/**
67-
* Array of plugins to be used in the devtools.
68-
* Each plugin should have a `render` function that returns a React element or a function
69-
*
70-
* Example:
71-
* ```jsx
72-
* <TanstackDevtools
73-
* plugins={[
74-
* {
75-
* id: "your-plugin-id",
76-
* name: "Your Plugin",
77-
* render: <CustomPluginComponent />,
78-
* }
79-
* ]}
80-
* />
81-
* ```
82-
*/
83-
plugins?: Array<TanStackDevtoolsSolidPlugin>
84-
/**
85-
* Configuration for the devtools shell. These configuration options are used to set the
86-
* initial state of the devtools when it is started for the first time. Afterwards,
87-
* the settings are persisted in local storage and changed through the settings panel.
88-
*/
89-
config?: Partial<TanStackDevtoolsConfig>
90-
/**
91-
* Configuration for the TanStack Devtools client event bus.
92-
*/
93-
eventBusConfig?: ClientEventBusConfig
94-
}
95-
96-
export const TanstackDevtools = ({
97-
config,
98-
plugins,
99-
eventBusConfig,
100-
}: TanstackDevtoolsInit) => {
101-
const [devtools] = createSignal(
102-
new TanStackDevtoolsCore({
103-
config,
104-
eventBusConfig,
105-
plugins: plugins?.map((plugin) => ({
106-
...plugin,
107-
name:
108-
typeof plugin.name === 'string'
109-
? plugin.name
110-
: // The check above confirms that `plugin.name` is of Render type
111-
(el) => convertRender(el, plugin.name as SolidPluginRender),
112-
render: (el: HTMLDivElement) => convertRender(el, plugin.render),
113-
})),
114-
}),
115-
)
116-
let devToolRef: HTMLDivElement | undefined
117-
createEffect(() => {
118-
devtools().setConfig({ config })
119-
})
120-
onMount(() => {
121-
if (devToolRef) {
122-
devtools().mount(devToolRef)
123-
124-
onCleanup(() => {
125-
devtools().unmount()
126-
})
127-
}
128-
})
129-
return <div style={{ height: '100%' }} ref={devToolRef} />
130-
}
3+
export const TanstackDevtools = clientOnly(() =>
4+
import("./core").then((m) => m),
5+
);

0 commit comments

Comments
 (0)