@tanstack/solid-router 1.166.6 → 2.0.0-alpha.1

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.
Files changed (182) hide show
  1. package/dist/cjs/Asset.cjs +111 -68
  2. package/dist/cjs/Asset.cjs.map +1 -1
  3. package/dist/cjs/CatchBoundary.cjs +15 -15
  4. package/dist/cjs/CatchBoundary.cjs.map +1 -1
  5. package/dist/cjs/ClientOnly.cjs +2 -2
  6. package/dist/cjs/ClientOnly.cjs.map +1 -1
  7. package/dist/cjs/HeadContent.cjs +16 -8
  8. package/dist/cjs/HeadContent.cjs.map +1 -1
  9. package/dist/cjs/HeadContent.dev.cjs +18 -10
  10. package/dist/cjs/HeadContent.dev.cjs.map +1 -1
  11. package/dist/cjs/Match.cjs +125 -81
  12. package/dist/cjs/Match.cjs.map +1 -1
  13. package/dist/cjs/Matches.cjs +23 -16
  14. package/dist/cjs/Matches.cjs.map +1 -1
  15. package/dist/cjs/RouterProvider.cjs +3 -2
  16. package/dist/cjs/RouterProvider.cjs.map +1 -1
  17. package/dist/cjs/SafeFragment.cjs +1 -1
  18. package/dist/cjs/ScriptOnce.cjs +4 -2
  19. package/dist/cjs/ScriptOnce.cjs.map +1 -1
  20. package/dist/cjs/Scripts.cjs +6 -2
  21. package/dist/cjs/Scripts.cjs.map +1 -1
  22. package/dist/cjs/Transitioner.cjs +11 -16
  23. package/dist/cjs/Transitioner.cjs.map +1 -1
  24. package/dist/cjs/awaited.cjs +20 -16
  25. package/dist/cjs/awaited.cjs.map +1 -1
  26. package/dist/cjs/lazyRouteComponent.cjs +3 -3
  27. package/dist/cjs/lazyRouteComponent.cjs.map +1 -1
  28. package/dist/cjs/link.cjs +40 -22
  29. package/dist/cjs/link.cjs.map +1 -1
  30. package/dist/cjs/not-found.cjs +1 -1
  31. package/dist/cjs/renderRouteNotFound.cjs +1 -1
  32. package/dist/cjs/route.cjs +1 -1
  33. package/dist/cjs/scroll-restoration.cjs +1 -1
  34. package/dist/cjs/ssr/RouterClient.cjs +4 -23
  35. package/dist/cjs/ssr/RouterClient.cjs.map +1 -1
  36. package/dist/cjs/ssr/RouterServer.cjs +4 -47
  37. package/dist/cjs/ssr/RouterServer.cjs.map +1 -1
  38. package/dist/cjs/ssr/RouterServer.d.cts +0 -1
  39. package/dist/cjs/ssr/defaultRenderHandler.cjs +1 -1
  40. package/dist/cjs/ssr/defaultStreamHandler.cjs +1 -1
  41. package/dist/cjs/ssr/renderRouterToStream.cjs +2 -3
  42. package/dist/cjs/ssr/renderRouterToStream.cjs.map +1 -1
  43. package/dist/cjs/ssr/renderRouterToString.cjs +2 -2
  44. package/dist/cjs/ssr/renderRouterToString.cjs.map +1 -1
  45. package/dist/cjs/ssr/renderRouterToString.d.cts +1 -1
  46. package/dist/cjs/useBlocker.cjs +9 -5
  47. package/dist/cjs/useBlocker.cjs.map +1 -1
  48. package/dist/cjs/useMatch.cjs +3 -6
  49. package/dist/cjs/useMatch.cjs.map +1 -1
  50. package/dist/cjs/useNavigate.cjs +1 -1
  51. package/dist/cjs/useNavigate.cjs.map +1 -1
  52. package/dist/cjs/useRouterState.cjs +15 -9
  53. package/dist/cjs/useRouterState.cjs.map +1 -1
  54. package/dist/cjs/utils.cjs +2 -4
  55. package/dist/cjs/utils.cjs.map +1 -1
  56. package/dist/cjs/utils.d.cts +1 -0
  57. package/dist/esm/Asset.js +111 -68
  58. package/dist/esm/Asset.js.map +1 -1
  59. package/dist/esm/CatchBoundary.js +15 -15
  60. package/dist/esm/CatchBoundary.js.map +1 -1
  61. package/dist/esm/ClientOnly.js +2 -2
  62. package/dist/esm/ClientOnly.js.map +1 -1
  63. package/dist/esm/HeadContent.dev.js +18 -10
  64. package/dist/esm/HeadContent.dev.js.map +1 -1
  65. package/dist/esm/HeadContent.js +16 -8
  66. package/dist/esm/HeadContent.js.map +1 -1
  67. package/dist/esm/Match.js +89 -45
  68. package/dist/esm/Match.js.map +1 -1
  69. package/dist/esm/Matches.js +23 -16
  70. package/dist/esm/Matches.js.map +1 -1
  71. package/dist/esm/RouterProvider.js +3 -2
  72. package/dist/esm/RouterProvider.js.map +1 -1
  73. package/dist/esm/SafeFragment.js +1 -1
  74. package/dist/esm/ScriptOnce.js +4 -2
  75. package/dist/esm/ScriptOnce.js.map +1 -1
  76. package/dist/esm/Scripts.js +6 -2
  77. package/dist/esm/Scripts.js.map +1 -1
  78. package/dist/esm/Transitioner.js +11 -16
  79. package/dist/esm/Transitioner.js.map +1 -1
  80. package/dist/esm/awaited.js +18 -14
  81. package/dist/esm/awaited.js.map +1 -1
  82. package/dist/esm/lazyRouteComponent.js +3 -3
  83. package/dist/esm/lazyRouteComponent.js.map +1 -1
  84. package/dist/esm/link.js +39 -21
  85. package/dist/esm/link.js.map +1 -1
  86. package/dist/esm/not-found.js +1 -1
  87. package/dist/esm/renderRouteNotFound.js +1 -1
  88. package/dist/esm/route.js +1 -1
  89. package/dist/esm/scroll-restoration.js +1 -1
  90. package/dist/esm/ssr/RouterClient.js +4 -23
  91. package/dist/esm/ssr/RouterClient.js.map +1 -1
  92. package/dist/esm/ssr/RouterServer.d.ts +0 -1
  93. package/dist/esm/ssr/RouterServer.js +5 -48
  94. package/dist/esm/ssr/RouterServer.js.map +1 -1
  95. package/dist/esm/ssr/defaultRenderHandler.js +1 -1
  96. package/dist/esm/ssr/defaultStreamHandler.js +1 -1
  97. package/dist/esm/ssr/renderRouterToStream.js +2 -4
  98. package/dist/esm/ssr/renderRouterToStream.js.map +1 -1
  99. package/dist/esm/ssr/renderRouterToString.d.ts +1 -1
  100. package/dist/esm/ssr/renderRouterToString.js +2 -2
  101. package/dist/esm/ssr/renderRouterToString.js.map +1 -1
  102. package/dist/esm/useBlocker.js +9 -5
  103. package/dist/esm/useBlocker.js.map +1 -1
  104. package/dist/esm/useMatch.js +3 -6
  105. package/dist/esm/useMatch.js.map +1 -1
  106. package/dist/esm/useNavigate.js +1 -1
  107. package/dist/esm/useNavigate.js.map +1 -1
  108. package/dist/esm/useRouterState.js +15 -9
  109. package/dist/esm/useRouterState.js.map +1 -1
  110. package/dist/esm/utils.d.ts +1 -0
  111. package/dist/esm/utils.js +2 -4
  112. package/dist/esm/utils.js.map +1 -1
  113. package/dist/source/Asset.jsx +58 -35
  114. package/dist/source/Asset.jsx.map +1 -1
  115. package/dist/source/CatchBoundary.jsx +9 -5
  116. package/dist/source/CatchBoundary.jsx.map +1 -1
  117. package/dist/source/ClientOnly.jsx +1 -1
  118. package/dist/source/ClientOnly.jsx.map +1 -1
  119. package/dist/source/HeadContent.dev.jsx +8 -6
  120. package/dist/source/HeadContent.dev.jsx.map +1 -1
  121. package/dist/source/HeadContent.jsx +6 -4
  122. package/dist/source/HeadContent.jsx.map +1 -1
  123. package/dist/source/Match.jsx +76 -35
  124. package/dist/source/Match.jsx.map +1 -1
  125. package/dist/source/Matches.jsx +25 -17
  126. package/dist/source/Matches.jsx.map +1 -1
  127. package/dist/source/RouterProvider.jsx +2 -3
  128. package/dist/source/RouterProvider.jsx.map +1 -1
  129. package/dist/source/Scripts.jsx +4 -3
  130. package/dist/source/Scripts.jsx.map +1 -1
  131. package/dist/source/Transitioner.jsx +15 -16
  132. package/dist/source/Transitioner.jsx.map +1 -1
  133. package/dist/source/awaited.jsx +7 -8
  134. package/dist/source/awaited.jsx.map +1 -1
  135. package/dist/source/lazyRouteComponent.jsx +3 -3
  136. package/dist/source/lazyRouteComponent.jsx.map +1 -1
  137. package/dist/source/link.jsx +53 -48
  138. package/dist/source/link.jsx.map +1 -1
  139. package/dist/source/ssr/RouterClient.jsx +1 -13
  140. package/dist/source/ssr/RouterClient.jsx.map +1 -1
  141. package/dist/source/ssr/RouterServer.d.ts +0 -1
  142. package/dist/source/ssr/RouterServer.jsx +1 -34
  143. package/dist/source/ssr/RouterServer.jsx.map +1 -1
  144. package/dist/source/ssr/renderRouterToStream.jsx +2 -6
  145. package/dist/source/ssr/renderRouterToStream.jsx.map +1 -1
  146. package/dist/source/ssr/renderRouterToString.d.ts +1 -1
  147. package/dist/source/ssr/renderRouterToString.jsx +2 -2
  148. package/dist/source/ssr/renderRouterToString.jsx.map +1 -1
  149. package/dist/source/useBlocker.jsx +8 -4
  150. package/dist/source/useBlocker.jsx.map +1 -1
  151. package/dist/source/useMatch.jsx +3 -8
  152. package/dist/source/useMatch.jsx.map +1 -1
  153. package/dist/source/useNavigate.jsx +1 -1
  154. package/dist/source/useNavigate.jsx.map +1 -1
  155. package/dist/source/useRouterState.jsx +23 -10
  156. package/dist/source/useRouterState.jsx.map +1 -1
  157. package/dist/source/utils.d.ts +1 -0
  158. package/dist/source/utils.js +3 -4
  159. package/dist/source/utils.js.map +1 -1
  160. package/package.json +8 -7
  161. package/src/Asset.tsx +123 -95
  162. package/src/CatchBoundary.tsx +9 -7
  163. package/src/ClientOnly.tsx +8 -3
  164. package/src/HeadContent.dev.tsx +16 -11
  165. package/src/HeadContent.tsx +6 -4
  166. package/src/Match.tsx +112 -44
  167. package/src/Matches.tsx +39 -30
  168. package/src/RouterProvider.tsx +7 -4
  169. package/src/Scripts.tsx +4 -3
  170. package/src/Transitioner.tsx +51 -58
  171. package/src/awaited.tsx +11 -12
  172. package/src/lazyRouteComponent.tsx +3 -3
  173. package/src/link.tsx +68 -60
  174. package/src/ssr/RouterClient.tsx +1 -22
  175. package/src/ssr/RouterServer.tsx +1 -53
  176. package/src/ssr/renderRouterToStream.tsx +5 -15
  177. package/src/ssr/renderRouterToString.tsx +2 -2
  178. package/src/useBlocker.tsx +8 -4
  179. package/src/useMatch.tsx +6 -11
  180. package/src/useNavigate.tsx +1 -1
  181. package/src/useRouterState.tsx +34 -22
  182. package/src/utils.ts +5 -4
@@ -1 +1 @@
1
- {"version":3,"file":"utils.js","sourceRoot":"","sources":["../../src/utils.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,UAAU,CAAA;AAEjC,MAAM,CAAC,MAAM,WAAW,GAAG,CAAC,EAAiB,EAAE,EAAE;IAC/C,OAAO,KAAK,CAAC,UAAU,CACrB,CACE,OAA8D;QAC5D,OAAO,EAAE,IAAI;QACb,QAAQ,EAAE,IAAI;KACf,EACD,EAAE;QACF,MAAM,OAAO,GAAG,EAAE,EAAE,CAAA;QAEpB,IAAI,IAAI,CAAC,OAAO,KAAK,OAAO,EAAE,CAAC;YAC7B,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC,OAAO,CAAA;YAC5B,IAAI,CAAC,OAAO,GAAG,OAAO,CAAA;QACxB,CAAC;QAED,OAAO,IAAI,CAAA;IACb,CAAC,CACF,CAAA;AACH,CAAC,CAAA;AAED;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,MAAM,UAAU,uBAAuB,CACrC,GAA6B,EAC7B,QAAgE,EAChE,8BAAwD,EAAE,EAC1D,UAAkC,EAAE;IAEpC,MAAM,+BAA+B,GACnC,OAAO,oBAAoB,KAAK,UAAU,CAAA;IAC5C,IAAI,WAAW,GAAgC,IAAI,CAAA;IAEnD,KAAK,CAAC,YAAY,CAAC,GAAG,EAAE;QACtB,MAAM,CAAC,GAAG,GAAG,EAAE,CAAA;QACf,IAAI,CAAC,CAAC,IAAI,CAAC,+BAA+B,IAAI,OAAO,CAAC,QAAQ,EAAE,CAAC;YAC/D,OAAM;QACR,CAAC;QAED,WAAW,GAAG,IAAI,oBAAoB,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE,EAAE;YACjD,QAAQ,CAAC,KAAK,CAAC,CAAA;QACjB,CAAC,EAAE,2BAA2B,CAAC,CAAA;QAE/B,WAAW,CAAC,OAAO,CAAC,CAAC,CAAC,CAAA;QAEtB,KAAK,CAAC,SAAS,CAAC,GAAG,EAAE;YACnB,WAAW,EAAE,UAAU,EAAE,CAAA;QAC3B,CAAC,CAAC,CAAA;IACJ,CAAC,CAAC,CAAA;IAEF,OAAO,GAAG,EAAE,CAAC,WAAW,CAAA;AAC1B,CAAC"}
1
+ {"version":3,"file":"utils.js","sourceRoot":"","sources":["../../src/utils.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,UAAU,CAAA;AAEjC,MAAM,CAAC,MAAM,eAAe,GAC1B,OAAO,MAAM,KAAK,WAAW,CAAC,CAAC,CAAC,KAAK,CAAC,YAAY,CAAC,CAAC,CAAC,KAAK,CAAC,YAAY,CAAA;AAEzE,MAAM,CAAC,MAAM,WAAW,GAAG,CAAC,EAAiB,EAAE,EAAE;IAC/C,OAAO,KAAK,CAAC,UAAU,CACrB,CACE,OAA8D;QAC5D,OAAO,EAAE,IAAI;QACb,QAAQ,EAAE,IAAI;KACf,EACD,EAAE;QACF,MAAM,OAAO,GAAG,EAAE,EAAE,CAAA;QAEpB,IAAI,IAAI,CAAC,OAAO,KAAK,OAAO,EAAE,CAAC;YAC7B,OAAO,EAAE,QAAQ,EAAE,IAAI,CAAC,OAAO,EAAE,OAAO,EAAE,CAAA;QAC5C,CAAC;QAED,OAAO,IAAI,CAAA;IACb,CAAC,CACF,CAAA;AACH,CAAC,CAAA;AAED;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,MAAM,UAAU,uBAAuB,CACrC,GAA6B,EAC7B,QAAgE,EAChE,8BAAwD,EAAE,EAC1D,UAAkC,EAAE;IAEpC,MAAM,+BAA+B,GACnC,OAAO,oBAAoB,KAAK,UAAU,CAAA;IAC5C,IAAI,WAAW,GAAgC,IAAI,CAAA;IAEnD,KAAK,CAAC,YAAY,CAAC,GAAG,EAAE,CAAC,CAAC,EAAE,EAAE;QAC5B,IAAI,CAAC,CAAC,IAAI,CAAC,+BAA+B,IAAI,OAAO,CAAC,QAAQ,EAAE,CAAC;YAC/D,OAAM;QACR,CAAC;QAED,WAAW,GAAG,IAAI,oBAAoB,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE,EAAE;YACjD,QAAQ,CAAC,KAAK,CAAC,CAAA;QACjB,CAAC,EAAE,2BAA2B,CAAC,CAAA;QAE/B,WAAW,CAAC,OAAO,CAAC,CAAC,CAAC,CAAA;QAEtB,KAAK,CAAC,SAAS,CAAC,GAAG,EAAE;YACnB,WAAW,EAAE,UAAU,EAAE,CAAA;QAC3B,CAAC,CAAC,CAAA;IACJ,CAAC,CAAC,CAAA;IAEF,OAAO,GAAG,EAAE,CAAC,WAAW,CAAA;AAC1B,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tanstack/solid-router",
3
- "version": "1.166.6",
3
+ "version": "2.0.0-alpha.1",
4
4
  "description": "Modern and scalable routing for Solid applications",
5
5
  "author": "Tanner Linsley",
6
6
  "license": "MIT",
@@ -85,27 +85,28 @@
85
85
  },
86
86
  "dependencies": {
87
87
  "@solid-devtools/logger": "^0.9.4",
88
- "@solid-primitives/refs": "^1.0.8",
89
88
  "@solidjs/meta": "^0.29.4",
90
- "@tanstack/solid-store": "^0.9.1",
89
+ "@solidjs/web": "2.0.0-beta.2",
91
90
  "isbot": "^5.1.22",
92
91
  "tiny-invariant": "^1.3.3",
93
92
  "tiny-warning": "^1.0.3",
94
93
  "@tanstack/history": "1.161.4",
95
- "@tanstack/router-core": "1.166.6"
94
+ "@tanstack/router-core": "1.166.7"
96
95
  },
97
96
  "devDependencies": {
98
97
  "@solidjs/testing-library": "^0.8.10",
99
98
  "@testing-library/jest-dom": "^6.6.3",
100
99
  "combinate": "^1.1.11",
101
100
  "eslint-plugin-solid": "^0.14.5",
102
- "solid-js": "^1.9.10",
101
+ "solid-js": "2.0.0-beta.2",
102
+ "@solidjs/web": "2.0.0-beta.2",
103
103
  "vite": "*",
104
- "vite-plugin-solid": "^2.11.10",
104
+ "vite-plugin-solid": "3.0.0-next.2",
105
105
  "zod": "^3.23.8"
106
106
  },
107
107
  "peerDependencies": {
108
- "solid-js": "^1.9.10"
108
+ "solid-js": "2.0.0-beta.2",
109
+ "@solidjs/web": "2.0.0-beta.2"
109
110
  },
110
111
  "scripts": {
111
112
  "clean": "rimraf ./dist && rimraf ./coverage",
package/src/Asset.tsx CHANGED
@@ -1,6 +1,5 @@
1
- import { Link, Meta, Style, Title } from '@solidjs/meta'
2
- import { onCleanup, onMount } from 'solid-js'
3
1
  import { isServer } from '@tanstack/router-core/isServer'
2
+ import { createEffect, onCleanup } from 'solid-js'
4
3
  import { useRouter } from './useRouter'
5
4
  import type { RouterManagedTag } from '@tanstack/router-core'
6
5
  import type { JSX } from 'solid-js'
@@ -12,105 +11,114 @@ export function Asset({
12
11
  }: RouterManagedTag): JSX.Element | null {
13
12
  switch (tag) {
14
13
  case 'title':
15
- return <Title {...attrs}>{children}</Title>
14
+ return <Title attrs={attrs} children={children} />
16
15
  case 'meta':
17
- return <Meta {...attrs} />
16
+ return <meta {...attrs} />
18
17
  case 'link':
19
- return <Link {...attrs} />
18
+ return <link {...attrs} />
20
19
  case 'style':
21
- return <Style {...attrs}>{children}</Style>
20
+ if (typeof children === 'string') {
21
+ return <style {...attrs} innerHTML={children} />
22
+ }
23
+ return <style {...attrs} />
22
24
  case 'script':
23
- return <Script attrs={attrs}>{children}</Script>
25
+ return <Script attrs={attrs} children={children} />
24
26
  default:
25
27
  return null
26
28
  }
27
29
  }
28
30
 
29
- interface ScriptAttrs {
30
- [key: string]: string | boolean | undefined
31
- src?: string
31
+ function Title(props: {
32
+ attrs?: Record<string, any>
33
+ children?: unknown
34
+ }): JSX.Element | null {
35
+ const router = useRouter()
36
+ const attrs = props.attrs
37
+ const children = props.children
38
+
39
+ // Server: render <title> normally
40
+ if (isServer ?? router.isServer) {
41
+ return <title {...attrs}>{children as string}</title>
42
+ }
43
+
44
+ // Client: imperatively set document.title so it updates during
45
+ // client-side navigation (JSX <title> in <head> doesn't reliably
46
+ // update the browser's document.title).
47
+ createEffect(
48
+ () => children,
49
+ (titleText) => {
50
+ document.title = typeof titleText === 'string' ? titleText : ''
51
+ },
52
+ )
53
+
54
+ // Still render the <title> element in the DOM for consistency,
55
+ // but the imperative assignment above is what actually drives the update.
56
+ return <title {...attrs}>{children as string}</title>
32
57
  }
33
58
 
34
- function Script({
35
- attrs,
36
- children,
37
- }: {
38
- attrs?: ScriptAttrs
39
- children?: string
59
+ function Script(props: {
60
+ attrs?: Record<string, any>
61
+ children?: unknown
40
62
  }): JSX.Element | null {
41
63
  const router = useRouter()
64
+ const attrs = props.attrs
65
+ const children = props.children
66
+
42
67
  const dataScript =
43
68
  typeof attrs?.type === 'string' &&
44
69
  attrs.type !== '' &&
45
70
  attrs.type !== 'text/javascript' &&
46
71
  attrs.type !== 'module'
47
72
 
48
- onMount(() => {
49
- if (dataScript) return
50
-
73
+ // --- Server rendering ---
74
+ if (isServer ?? router.isServer) {
51
75
  if (attrs?.src) {
52
- const normSrc = (() => {
53
- try {
54
- const base = document.baseURI || window.location.href
55
- return new URL(attrs.src, base).href
56
- } catch {
57
- return attrs.src
58
- }
59
- })()
60
- const existingScript = Array.from(
61
- document.querySelectorAll('script[src]'),
62
- ).find((el) => (el as HTMLScriptElement).src === normSrc)
63
-
64
- if (existingScript) {
65
- return
66
- }
76
+ return <script {...attrs} />
77
+ }
67
78
 
68
- const script = document.createElement('script')
79
+ if (typeof children === 'string') {
80
+ return <script {...attrs} innerHTML={children} />
81
+ }
69
82
 
70
- for (const [key, value] of Object.entries(attrs)) {
71
- if (value !== undefined && value !== false) {
72
- script.setAttribute(
73
- key,
74
- typeof value === 'boolean' ? '' : String(value),
75
- )
76
- }
77
- }
83
+ return null
84
+ }
78
85
 
79
- document.head.appendChild(script)
86
+ // --- Client rendering ---
80
87
 
81
- onCleanup(() => {
82
- if (script.parentNode) {
83
- script.parentNode.removeChild(script)
84
- }
85
- })
86
- }
88
+ // Data scripts (e.g. application/ld+json) are rendered in the tree;
89
+ // they don't need to execute.
90
+ if (dataScript && typeof children === 'string') {
91
+ return <script {...attrs} innerHTML={children} />
92
+ }
87
93
 
88
- if (typeof children === 'string') {
89
- const typeAttr =
90
- typeof attrs?.type === 'string' ? attrs.type : 'text/javascript'
91
- const nonceAttr =
92
- typeof attrs?.nonce === 'string' ? attrs.nonce : undefined
93
- const existingScript = Array.from(
94
- document.querySelectorAll('script:not([src])'),
95
- ).find((el) => {
96
- if (!(el instanceof HTMLScriptElement)) return false
97
- const sType = el.getAttribute('type') ?? 'text/javascript'
98
- const sNonce = el.getAttribute('nonce') ?? undefined
99
- return (
100
- el.textContent === children &&
101
- sType === typeAttr &&
102
- sNonce === nonceAttr
103
- )
104
- })
94
+ // For executable scripts, use imperative DOM injection so the browser
95
+ // actually executes them during client-side navigation.
96
+ createEffect(
97
+ () => ({ attrs, children, dataScript }) as const,
98
+ ({ attrs, children, dataScript }) => {
99
+ if (dataScript) return
100
+
101
+ let script: HTMLScriptElement | undefined
102
+
103
+ if (attrs?.src) {
104
+ const normSrc = (() => {
105
+ try {
106
+ const base = document.baseURI || window.location.href
107
+ return new URL(attrs.src, base).href
108
+ } catch {
109
+ return attrs.src
110
+ }
111
+ })()
112
+ const existingScript = Array.from(
113
+ document.querySelectorAll('script[src]'),
114
+ ).find((el) => (el as HTMLScriptElement).src === normSrc)
105
115
 
106
- if (existingScript) {
107
- return
108
- }
116
+ if (existingScript) {
117
+ return
118
+ }
109
119
 
110
- const script = document.createElement('script')
111
- script.textContent = children
120
+ script = document.createElement('script')
112
121
 
113
- if (attrs) {
114
122
  for (const [key, value] of Object.entries(attrs)) {
115
123
  if (value !== undefined && value !== false) {
116
124
  script.setAttribute(
@@ -119,34 +127,54 @@ function Script({
119
127
  )
120
128
  }
121
129
  }
122
- }
123
130
 
124
- document.head.appendChild(script)
131
+ document.head.appendChild(script)
132
+ } else if (typeof children === 'string') {
133
+ const typeAttr =
134
+ typeof attrs?.type === 'string' ? attrs.type : 'text/javascript'
135
+ const nonceAttr =
136
+ typeof attrs?.nonce === 'string' ? attrs.nonce : undefined
137
+ const existingScript = Array.from(
138
+ document.querySelectorAll('script:not([src])'),
139
+ ).find((el) => {
140
+ if (!(el instanceof HTMLScriptElement)) return false
141
+ const sType = el.getAttribute('type') ?? 'text/javascript'
142
+ const sNonce = el.getAttribute('nonce') ?? undefined
143
+ return (
144
+ el.textContent === children &&
145
+ sType === typeAttr &&
146
+ sNonce === nonceAttr
147
+ )
148
+ })
125
149
 
126
- onCleanup(() => {
127
- if (script.parentNode) {
128
- script.parentNode.removeChild(script)
150
+ if (existingScript) {
151
+ return
129
152
  }
130
- })
131
- }
132
- })
133
153
 
134
- if (!(isServer ?? router.isServer)) {
135
- if (dataScript && typeof children === 'string') {
136
- return <script {...attrs} innerHTML={children} />
137
- }
138
-
139
- // render an empty script on the client just to avoid hydration errors
140
- return null
141
- }
154
+ script = document.createElement('script')
155
+ script.textContent = children
156
+
157
+ if (attrs) {
158
+ for (const [key, value] of Object.entries(attrs)) {
159
+ if (value !== undefined && value !== false) {
160
+ script.setAttribute(
161
+ key,
162
+ typeof value === 'boolean' ? '' : String(value),
163
+ )
164
+ }
165
+ }
166
+ }
142
167
 
143
- if (attrs?.src && typeof attrs.src === 'string') {
144
- return <script {...attrs} />
145
- }
168
+ document.head.appendChild(script)
169
+ }
146
170
 
147
- if (typeof children === 'string') {
148
- return <script {...attrs} innerHTML={children} />
149
- }
171
+ onCleanup(() => {
172
+ if (script?.parentNode) {
173
+ script.parentNode.removeChild(script)
174
+ }
175
+ })
176
+ },
177
+ )
150
178
 
151
179
  return null
152
180
  }
@@ -1,5 +1,5 @@
1
1
  import * as Solid from 'solid-js'
2
- import { Dynamic } from 'solid-js/web'
2
+ import { Dynamic } from '@solidjs/web'
3
3
  import type { ErrorRouteComponent } from './route'
4
4
 
5
5
  export function CatchBoundary(
@@ -11,13 +11,15 @@ export function CatchBoundary(
11
11
  } & Solid.ParentProps,
12
12
  ) {
13
13
  return (
14
- <Solid.ErrorBoundary
14
+ <Solid.Errored
15
15
  fallback={(error, reset) => {
16
16
  props.onCatch?.(error)
17
17
 
18
- Solid.createEffect(
19
- Solid.on([props.getResetKey], () => reset(), { defer: true }),
20
- )
18
+ Solid.createEffect(props.getResetKey, () => {
19
+ // We trigger reset here. For a fully deferred effect we might need usePrevious,
20
+ // but calling reset on key change is the main goal.
21
+ reset()
22
+ })
21
23
 
22
24
  return (
23
25
  <Dynamic
@@ -29,7 +31,7 @@ export function CatchBoundary(
29
31
  }}
30
32
  >
31
33
  {props.children}
32
- </Solid.ErrorBoundary>
34
+ </Solid.Errored>
33
35
  )
34
36
  }
35
37
 
@@ -41,7 +43,7 @@ export function ErrorComponent({ error }: { error: any }) {
41
43
  return (
42
44
  <div style={{ padding: '.5rem', 'max-width': '100%' }}>
43
45
  <div style={{ display: 'flex', 'align-items': 'center', gap: '.5rem' }}>
44
- <strong style={{ 'font-size': '1rem' }}>Something went wrong!</strong>
46
+ ∂<strong style={{ 'font-size': '1rem' }}>Something went wrong!</strong>
45
47
  <button
46
48
  style={{
47
49
  appearance: 'none',
@@ -58,8 +58,13 @@ export function ClientOnly(props: ClientOnlyProps) {
58
58
  */
59
59
  export function useHydrated(): Solid.Accessor<boolean> {
60
60
  const [hydrated, setHydrated] = Solid.createSignal(false)
61
- Solid.onMount(() => {
62
- setHydrated(true)
63
- })
61
+
62
+ Solid.createEffect(
63
+ () => true,
64
+ () => {
65
+ setHydrated(true)
66
+ },
67
+ )
68
+
64
69
  return hydrated
65
70
  }
@@ -1,4 +1,3 @@
1
- import { MetaProvider } from '@solidjs/meta'
2
1
  import { For, createEffect, createMemo } from 'solid-js'
3
2
  import { Asset } from './Asset'
4
3
  import { useHydrated } from './ClientOnly'
@@ -21,13 +20,16 @@ export function HeadContent() {
21
20
 
22
21
  // Fallback cleanup for hydration mismatch cases
23
22
  // Runs when hydration completes to remove any orphaned dev styles links from DOM
24
- createEffect(() => {
25
- if (hydrated()) {
26
- document
27
- .querySelectorAll(`link[${DEV_STYLES_ATTR}]`)
28
- .forEach((el) => el.remove())
29
- }
30
- })
23
+ createEffect(
24
+ () => [hydrated()] as const,
25
+ ([hydrated]) => {
26
+ if (hydrated) {
27
+ document
28
+ .querySelectorAll(`link[${DEV_STYLES_ATTR}]`)
29
+ .forEach((el) => el.remove())
30
+ }
31
+ },
32
+ )
31
33
 
32
34
  // Filter out dev styles after hydration
33
35
  const filteredTags = createMemo(() => {
@@ -38,8 +40,11 @@ export function HeadContent() {
38
40
  })
39
41
 
40
42
  return (
41
- <MetaProvider>
42
- <For each={filteredTags()}>{(tag) => <Asset {...tag} />}</For>
43
- </MetaProvider>
43
+ <For each={filteredTags()}>
44
+ {(tag) => {
45
+ const t = tag() as any
46
+ return <Asset tag={t.tag} attrs={t.attrs} children={t.children} />
47
+ }}
48
+ </For>
44
49
  )
45
50
  }
@@ -1,4 +1,3 @@
1
- import { MetaProvider } from '@solidjs/meta'
2
1
  import { For } from 'solid-js'
3
2
  import { Asset } from './Asset'
4
3
  import { useTags } from './headContentUtils'
@@ -13,8 +12,11 @@ export function HeadContent() {
13
12
  const tags = useTags()
14
13
 
15
14
  return (
16
- <MetaProvider>
17
- <For each={tags()}>{(tag) => <Asset {...tag} />}</For>
18
- </MetaProvider>
15
+ <For each={tags()}>
16
+ {(tag) => {
17
+ const t = tag() as any
18
+ return <Asset tag={t.tag} attrs={t.attrs} children={t.children} />
19
+ }}
20
+ </For>
19
21
  )
20
22
  }