one 1.1.391 → 1.1.393

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 (188) hide show
  1. package/dist/cjs/Root.cjs +25 -18
  2. package/dist/cjs/Root.js +7 -9
  3. package/dist/cjs/Root.js.map +1 -1
  4. package/dist/cjs/Root.native.js +44 -39
  5. package/dist/cjs/Root.native.js.map +2 -2
  6. package/dist/cjs/cli/build.cjs +21 -18
  7. package/dist/cjs/cli/build.js +16 -12
  8. package/dist/cjs/cli/build.js.map +1 -1
  9. package/dist/cjs/cli/build.native.js +21 -17
  10. package/dist/cjs/cli/build.native.js.map +2 -2
  11. package/dist/cjs/constants.cjs +9 -1
  12. package/dist/cjs/constants.js +7 -1
  13. package/dist/cjs/constants.js.map +1 -1
  14. package/dist/cjs/constants.native.js +9 -1
  15. package/dist/cjs/constants.native.js.map +2 -2
  16. package/dist/cjs/createApp.cjs +21 -6
  17. package/dist/cjs/createApp.js +23 -6
  18. package/dist/cjs/createApp.js.map +1 -1
  19. package/dist/cjs/fork/_shared.cjs +42 -0
  20. package/dist/cjs/fork/_shared.js +37 -0
  21. package/dist/cjs/fork/_shared.js.map +6 -0
  22. package/dist/cjs/fork/_shared.native.js +49 -0
  23. package/dist/cjs/fork/_shared.native.js.map +6 -0
  24. package/dist/cjs/fork/getPathFromState-mods.cjs +8 -10
  25. package/dist/cjs/fork/getPathFromState-mods.js +7 -6
  26. package/dist/cjs/fork/getPathFromState-mods.js.map +1 -1
  27. package/dist/cjs/fork/getPathFromState-mods.native.js +10 -14
  28. package/dist/cjs/fork/getPathFromState-mods.native.js.map +2 -2
  29. package/dist/cjs/fork/getPathFromState.cjs +19 -8
  30. package/dist/cjs/fork/getPathFromState.js +14 -6
  31. package/dist/cjs/fork/getPathFromState.js.map +1 -1
  32. package/dist/cjs/fork/getPathFromState.native.js +14 -8
  33. package/dist/cjs/fork/getPathFromState.native.js.map +2 -2
  34. package/dist/cjs/fork/getStateFromPath-mods.cjs +0 -8
  35. package/dist/cjs/fork/getStateFromPath-mods.js +0 -8
  36. package/dist/cjs/fork/getStateFromPath-mods.js.map +1 -1
  37. package/dist/cjs/fork/getStateFromPath-mods.native.js +0 -11
  38. package/dist/cjs/fork/getStateFromPath-mods.native.js.map +2 -2
  39. package/dist/cjs/fork/getStateFromPath.cjs +6 -5
  40. package/dist/cjs/fork/getStateFromPath.js +5 -5
  41. package/dist/cjs/fork/getStateFromPath.js.map +1 -1
  42. package/dist/cjs/fork/getStateFromPath.native.js +5 -5
  43. package/dist/cjs/fork/getStateFromPath.native.js.map +2 -2
  44. package/dist/cjs/index.cjs +2 -0
  45. package/dist/cjs/index.js +2 -1
  46. package/dist/cjs/index.js.map +1 -1
  47. package/dist/cjs/index.native.js +3 -1
  48. package/dist/cjs/index.native.js.map +1 -1
  49. package/dist/cjs/server/oneServe.cjs +31 -3
  50. package/dist/cjs/server/oneServe.js +24 -3
  51. package/dist/cjs/server/oneServe.js.map +1 -1
  52. package/dist/cjs/server/oneServe.native.js +37 -3
  53. package/dist/cjs/server/oneServe.native.js.map +2 -2
  54. package/dist/cjs/useServerHeadInsertion.cjs +40 -0
  55. package/dist/cjs/useServerHeadInsertion.js +32 -0
  56. package/dist/cjs/useServerHeadInsertion.js.map +6 -0
  57. package/dist/cjs/useServerHeadInsertion.native.js +38 -0
  58. package/dist/cjs/useServerHeadInsertion.native.js.map +6 -0
  59. package/dist/cjs/utils/serverContext.cjs +7 -7
  60. package/dist/cjs/utils/serverContext.js +7 -7
  61. package/dist/cjs/utils/serverContext.js.map +1 -1
  62. package/dist/cjs/utils/serverContext.native.js +5 -5
  63. package/dist/cjs/utils/serverContext.native.js.map +2 -2
  64. package/dist/cjs/vite/plugins/fileSystemRouterPlugin.cjs +6 -6
  65. package/dist/cjs/vite/plugins/fileSystemRouterPlugin.js +3 -4
  66. package/dist/cjs/vite/plugins/fileSystemRouterPlugin.js.map +2 -2
  67. package/dist/cjs/vite/plugins/fileSystemRouterPlugin.native.js +3 -4
  68. package/dist/cjs/vite/plugins/fileSystemRouterPlugin.native.js.map +2 -2
  69. package/dist/esm/Root.js +8 -9
  70. package/dist/esm/Root.js.map +1 -1
  71. package/dist/esm/Root.mjs +26 -19
  72. package/dist/esm/Root.mjs.map +1 -1
  73. package/dist/esm/Root.native.js +45 -39
  74. package/dist/esm/Root.native.js.map +2 -2
  75. package/dist/esm/cli/build.js +16 -12
  76. package/dist/esm/cli/build.js.map +1 -1
  77. package/dist/esm/cli/build.mjs +21 -18
  78. package/dist/esm/cli/build.mjs.map +1 -1
  79. package/dist/esm/cli/build.native.js +21 -17
  80. package/dist/esm/cli/build.native.js.map +2 -2
  81. package/dist/esm/constants.js +7 -1
  82. package/dist/esm/constants.js.map +1 -1
  83. package/dist/esm/constants.mjs +8 -2
  84. package/dist/esm/constants.mjs.map +1 -1
  85. package/dist/esm/constants.native.js +7 -1
  86. package/dist/esm/constants.native.js.map +2 -2
  87. package/dist/esm/createApp.js +25 -6
  88. package/dist/esm/createApp.js.map +1 -1
  89. package/dist/esm/createApp.mjs +22 -7
  90. package/dist/esm/createApp.mjs.map +1 -1
  91. package/dist/esm/fork/_shared.js +21 -0
  92. package/dist/esm/fork/_shared.js.map +6 -0
  93. package/dist/esm/fork/_shared.mjs +16 -0
  94. package/dist/esm/fork/_shared.mjs.map +1 -0
  95. package/dist/esm/fork/_shared.native.js +25 -0
  96. package/dist/esm/fork/_shared.native.js.map +6 -0
  97. package/dist/esm/fork/getPathFromState-mods.js +6 -4
  98. package/dist/esm/fork/getPathFromState-mods.js.map +1 -1
  99. package/dist/esm/fork/getPathFromState-mods.mjs +7 -8
  100. package/dist/esm/fork/getPathFromState-mods.mjs.map +1 -1
  101. package/dist/esm/fork/getPathFromState-mods.native.js +9 -11
  102. package/dist/esm/fork/getPathFromState-mods.native.js.map +2 -2
  103. package/dist/esm/fork/getPathFromState.js +4 -3
  104. package/dist/esm/fork/getPathFromState.js.map +1 -1
  105. package/dist/esm/fork/getPathFromState.mjs +4 -4
  106. package/dist/esm/fork/getPathFromState.mjs.map +1 -1
  107. package/dist/esm/fork/getPathFromState.native.js +4 -5
  108. package/dist/esm/fork/getPathFromState.native.js.map +2 -2
  109. package/dist/esm/fork/getStateFromPath-mods.js +0 -8
  110. package/dist/esm/fork/getStateFromPath-mods.js.map +1 -1
  111. package/dist/esm/fork/getStateFromPath-mods.mjs +1 -8
  112. package/dist/esm/fork/getStateFromPath-mods.mjs.map +1 -1
  113. package/dist/esm/fork/getStateFromPath-mods.native.js +0 -10
  114. package/dist/esm/fork/getStateFromPath-mods.native.js.map +2 -2
  115. package/dist/esm/fork/getStateFromPath.js +4 -4
  116. package/dist/esm/fork/getStateFromPath.js.map +1 -1
  117. package/dist/esm/fork/getStateFromPath.mjs +5 -4
  118. package/dist/esm/fork/getStateFromPath.mjs.map +1 -1
  119. package/dist/esm/fork/getStateFromPath.native.js +5 -4
  120. package/dist/esm/fork/getStateFromPath.native.js.map +2 -2
  121. package/dist/esm/index.js +2 -0
  122. package/dist/esm/index.js.map +1 -1
  123. package/dist/esm/index.mjs +2 -1
  124. package/dist/esm/index.mjs.map +1 -1
  125. package/dist/esm/index.native.js +2 -0
  126. package/dist/esm/index.native.js.map +2 -2
  127. package/dist/esm/server/oneServe.js +24 -3
  128. package/dist/esm/server/oneServe.js.map +1 -1
  129. package/dist/esm/server/oneServe.mjs +31 -3
  130. package/dist/esm/server/oneServe.mjs.map +1 -1
  131. package/dist/esm/server/oneServe.native.js +37 -3
  132. package/dist/esm/server/oneServe.native.js.map +2 -2
  133. package/dist/esm/useServerHeadInsertion.js +16 -0
  134. package/dist/esm/useServerHeadInsertion.js.map +6 -0
  135. package/dist/esm/useServerHeadInsertion.mjs +15 -0
  136. package/dist/esm/useServerHeadInsertion.mjs.map +1 -0
  137. package/dist/esm/useServerHeadInsertion.native.js +16 -0
  138. package/dist/esm/useServerHeadInsertion.native.js.map +6 -0
  139. package/dist/esm/utils/serverContext.js +2 -1
  140. package/dist/esm/utils/serverContext.js.map +1 -1
  141. package/dist/esm/utils/serverContext.mjs +1 -1
  142. package/dist/esm/utils/serverContext.mjs.map +1 -1
  143. package/dist/esm/utils/serverContext.native.js +2 -1
  144. package/dist/esm/utils/serverContext.native.js.map +2 -2
  145. package/dist/esm/vite/plugins/fileSystemRouterPlugin.js +3 -3
  146. package/dist/esm/vite/plugins/fileSystemRouterPlugin.js.map +1 -1
  147. package/dist/esm/vite/plugins/fileSystemRouterPlugin.mjs +3 -3
  148. package/dist/esm/vite/plugins/fileSystemRouterPlugin.mjs.map +1 -1
  149. package/dist/esm/vite/plugins/fileSystemRouterPlugin.native.js +3 -3
  150. package/dist/esm/vite/plugins/fileSystemRouterPlugin.native.js.map +2 -2
  151. package/package.json +8 -8
  152. package/src/Root.tsx +44 -40
  153. package/src/cli/build.ts +17 -14
  154. package/src/constants.ts +8 -0
  155. package/src/createApp.tsx +35 -4
  156. package/src/fork/_shared.ts +22 -0
  157. package/src/fork/getPathFromState-mods.ts +22 -7
  158. package/src/fork/getPathFromState.ts +3 -2
  159. package/src/fork/getStateFromPath-mods.ts +0 -9
  160. package/src/fork/getStateFromPath.ts +8 -5
  161. package/src/index.ts +1 -0
  162. package/src/server/oneServe.ts +47 -4
  163. package/src/useServerHeadInsertion.tsx +25 -0
  164. package/src/utils/serverContext.tsx +3 -1
  165. package/src/vite/plugins/fileSystemRouterPlugin.tsx +3 -3
  166. package/types/Root.d.ts +1 -0
  167. package/types/Root.d.ts.map +1 -1
  168. package/types/cli/build.d.ts.map +1 -1
  169. package/types/constants.d.ts +2 -0
  170. package/types/constants.d.ts.map +1 -1
  171. package/types/createApp.d.ts.map +1 -1
  172. package/types/fork/_shared.d.ts +8 -0
  173. package/types/fork/_shared.d.ts.map +1 -0
  174. package/types/fork/getPathFromState-mods.d.ts +0 -1
  175. package/types/fork/getPathFromState-mods.d.ts.map +1 -1
  176. package/types/fork/getPathFromState.d.ts.map +1 -1
  177. package/types/fork/getStateFromPath-mods.d.ts +0 -1
  178. package/types/fork/getStateFromPath-mods.d.ts.map +1 -1
  179. package/types/fork/getStateFromPath.d.ts.map +1 -1
  180. package/types/index.d.ts +1 -0
  181. package/types/index.d.ts.map +1 -1
  182. package/types/serve.d.ts +6 -6
  183. package/types/serve.d.ts.map +1 -1
  184. package/types/server/oneServe.d.ts.map +1 -1
  185. package/types/useServerHeadInsertion.d.ts +5 -0
  186. package/types/useServerHeadInsertion.d.ts.map +1 -0
  187. package/types/utils/serverContext.d.ts.map +1 -1
  188. package/types/vite/plugins/fileSystemRouterPlugin.d.ts.map +1 -1
package/src/Root.tsx CHANGED
@@ -5,7 +5,7 @@ import {
5
5
  type NavigationContainerProps,
6
6
  } from '@react-navigation/native'
7
7
  import { useColorScheme } from '@vxrn/universal-color-scheme'
8
- import { useEffect, useState, type FunctionComponent, type ReactNode } from 'react'
8
+ import { useEffect, useId, useState, type FunctionComponent, type ReactNode } from 'react'
9
9
  import { NavigationContainer as UpstreamNavigationContainer } from './fork/NavigationContainer'
10
10
  import { getURL } from './getURL'
11
11
  import { ServerLocationContext } from './router/serverLocationContext'
@@ -17,18 +17,16 @@ import { PreloadLinks } from './views/PreloadLinks'
17
17
  import { RootErrorBoundary } from './views/RootErrorBoundary'
18
18
  import { ScrollRestoration } from './views/ScrollRestoration'
19
19
  import type { One } from './vite/types'
20
+ import { ServerRenderID } from './useServerHeadInsertion'
20
21
  // import { SplashScreen } from './views/Splash'
21
22
 
22
23
  if (typeof window !== 'undefined') {
23
24
  // @ts-ignore TODO: hard coded for demo app
24
- window.__getReactRefreshIgnoredExports = () => [
25
- 'feedCardQuery',
26
- 'feedCardReplyQuery',
27
- 'loader',
28
- ]
25
+ window.__getReactRefreshIgnoredExports = () => ['feedCardQuery', 'feedCardReplyQuery', 'loader']
29
26
  }
30
27
 
31
28
  type RootProps = Omit<InnerProps, 'context'> & {
29
+ onRenderId?: (id: string) => void
32
30
  path: string
33
31
  isClient?: boolean
34
32
  routes: GlobbedRouteImports
@@ -55,7 +53,7 @@ type InnerProps = {
55
53
  }
56
54
 
57
55
  export function Root(props: RootProps) {
58
- const { path, routes, routeOptions, isClient, navigationContainerProps } = props
56
+ const { path, routes, routeOptions, isClient, navigationContainerProps, onRenderId } = props
59
57
 
60
58
  // ⚠️ <StrictMode> breaks routing!
61
59
  const context = useViteRoutes(routes, routeOptions, globalThis['__vxrnVersion'])
@@ -75,41 +73,47 @@ export function Root(props: RootProps) {
75
73
  throw new Error(`No root component found`)
76
74
  }
77
75
 
76
+ const id = useId()
77
+
78
+ onRenderId?.(id)
79
+
78
80
  const contents = (
79
81
  // <StrictMode>
80
- <RootErrorBoundary>
81
- {/* for some reason warning if no key here */}
82
- <UpstreamNavigationContainer
83
- ref={store.navigationRef}
84
- initialState={store.initialState}
85
- linking={store.linking}
86
- onUnhandledAction={onUnhandledAction}
87
- theme={colorScheme === 'dark' ? DarkTheme : DefaultTheme}
88
- documentTitle={{
89
- enabled: false,
90
- }}
91
- {...navigationContainerProps}
92
- >
93
- <ServerLocationContext.Provider value={location}>
94
- {/* <GestureHandlerRootView> */}
95
- {/*
96
- * Due to static rendering we need to wrap these top level views in second wrapper
97
- * View's like <GestureHandlerRootView /> generate a <div> so if the parent wrapper
98
- * is a HTML document, we need to ensure its inside the <body>
99
- */}
100
- <>
101
- {/* default scroll restoration to on, but users can configure it by importing and using themselves */}
102
- <ScrollRestoration />
103
- <Component />
104
-
105
- {/* Users can override this by adding another StatusBar element anywhere higher in the component tree. */}
106
- </>
107
- {/* {!hasViewControllerBasedStatusBarAppearance && <StatusBar style="auto" />} */}
108
- {/* </GestureHandlerRootView> */}
109
- </ServerLocationContext.Provider>
110
- </UpstreamNavigationContainer>
111
- <PreloadLinks key="preload-links" />
112
- </RootErrorBoundary>
82
+ <ServerRenderID.Provider value={id}>
83
+ <RootErrorBoundary>
84
+ {/* for some reason warning if no key here */}
85
+ <UpstreamNavigationContainer
86
+ ref={store.navigationRef}
87
+ initialState={store.initialState}
88
+ linking={store.linking}
89
+ onUnhandledAction={onUnhandledAction}
90
+ theme={colorScheme === 'dark' ? DarkTheme : DefaultTheme}
91
+ documentTitle={{
92
+ enabled: false,
93
+ }}
94
+ {...navigationContainerProps}
95
+ >
96
+ <ServerLocationContext.Provider value={location}>
97
+ {/* <GestureHandlerRootView> */}
98
+ {/*
99
+ * Due to static rendering we need to wrap these top level views in second wrapper
100
+ * View's like <GestureHandlerRootView /> generate a <div> so if the parent wrapper
101
+ * is a HTML document, we need to ensure its inside the <body>
102
+ */}
103
+ <>
104
+ {/* default scroll restoration to on, but users can configure it by importing and using themselves */}
105
+ <ScrollRestoration />
106
+ <Component />
107
+
108
+ {/* Users can override this by adding another StatusBar element anywhere higher in the component tree. */}
109
+ </>
110
+ {/* {!hasViewControllerBasedStatusBarAppearance && <StatusBar style="auto" />} */}
111
+ {/* </GestureHandlerRootView> */}
112
+ </ServerLocationContext.Provider>
113
+ </UpstreamNavigationContainer>
114
+ <PreloadLinks key="preload-links" />
115
+ </RootErrorBoundary>
116
+ </ServerRenderID.Provider>
113
117
  // </StrictMode>
114
118
  )
115
119
 
package/src/cli/build.ts CHANGED
@@ -12,10 +12,10 @@ import {
12
12
  build as vxrnBuild,
13
13
  type ClientManifestEntry,
14
14
  } from 'vxrn'
15
- import { getLoaderPath, getPreloadPath } from '../utils/cleanUrl'
16
15
  import * as constants from '../constants'
17
16
  import type { RouteInfo } from '../server/createRoutesManifest'
18
17
  import type { LoaderProps, RenderApp } from '../types'
18
+ import { getLoaderPath, getPreloadPath } from '../utils/cleanUrl'
19
19
  import { toAbsolute } from '../utils/toAbsolute'
20
20
  import { getManifest } from '../vite/getManifest'
21
21
  import { loadUserOneOptions } from '../vite/loadConfig'
@@ -462,6 +462,21 @@ export async function build(args: {
462
462
  preloads,
463
463
  })
464
464
 
465
+ if (exported.loader) {
466
+ loaderData = (await exported.loader?.({ path, params })) ?? null
467
+ const code = await readFile(clientJsPath, 'utf-8')
468
+ const withLoader =
469
+ // super dirty to quickly make ssr loaders work until we have better
470
+ `
471
+ if (typeof document === 'undefined') globalThis.document = {}
472
+ ` + replaceLoader({
473
+ code,
474
+ loaderData,
475
+ })
476
+ const loaderPartialPath = join(clientDir, getLoaderPath(path))
477
+ await outputFile(loaderPartialPath, withLoader)
478
+ }
479
+
465
480
  // ssr, we basically skip at build-time and just compile it the js we need
466
481
  if (foundRoute.type !== 'ssr') {
467
482
  const loaderProps: LoaderProps = { path, params }
@@ -469,17 +484,6 @@ export async function build(args: {
469
484
  // importing resetState causes issues :/
470
485
  globalThis['__vxrnresetState']?.()
471
486
 
472
- if (exported.loader) {
473
- loaderData = (await exported.loader?.({ path, params })) ?? null
474
- const code = await readFile(clientJsPath, 'utf-8')
475
- const withLoader = replaceLoader({
476
- code,
477
- loaderData,
478
- })
479
- const loaderPartialPath = join(clientDir, getLoaderPath(path))
480
- await outputFile(loaderPartialPath, withLoader)
481
- }
482
-
483
487
  if (foundRoute.type === 'ssg') {
484
488
  const html = await render({
485
489
  path,
@@ -497,8 +501,7 @@ export async function build(args: {
497
501
  await outputFile(
498
502
  htmlOutPath,
499
503
  `<html><head>
500
- <script>globalThis['global'] = globalThis</script>
501
- <script>globalThis['__vxrnIsSPA'] = true</script>
504
+ ${constants.SPA_HEADER_ELEMENTS}
502
505
  ${preloads
503
506
  .map((preload) => ` <script type="module" src="${preload}"></script>`)
504
507
  .join('\n')}
package/src/constants.ts CHANGED
@@ -14,3 +14,11 @@ export const PRELOAD_JS_POSTFIX = `_${CACHE_KEY}_preload.js`
14
14
  // safari insanely aggressive caching
15
15
  export const VIRTUAL_SSR_CSS_ENTRY = `virtual:ssr-css.css`
16
16
  export const VIRTUAL_SSR_CSS_HREF = `/@id/__x00__${VIRTUAL_SSR_CSS_ENTRY}`
17
+
18
+ export const SERVER_CONTEXT_KEY = '__one_server_context__'
19
+
20
+ export const SPA_HEADER_ELEMENTS = `
21
+ <script>globalThis['global'] = globalThis</script>
22
+ <script>globalThis['__vxrnIsSPA'] = true</script>
23
+ <script>globalThis["${SERVER_CONTEXT_KEY}"] = {}</script>
24
+ `
package/src/createApp.tsx CHANGED
@@ -13,6 +13,9 @@ import {
13
13
  SERVER_CONTEXT_POST_RENDER_STRING,
14
14
  setServerContext,
15
15
  } from './utils/serverContext'
16
+ import { cloneElement, useId } from 'react'
17
+ import { ensureExists } from './utils/ensureExists'
18
+ import { getServerHeadInsertions } from './useServerHeadInsertion'
16
19
 
17
20
  export type CreateAppProps = { routes: Record<string, () => Promise<unknown>> }
18
21
 
@@ -31,8 +34,18 @@ export function createApp(options: CreateAppProps) {
31
34
  css,
32
35
  })
33
36
 
37
+ let renderId: string | undefined
38
+
34
39
  const App = () => {
35
- return <Root routes={options.routes} {...props} />
40
+ return (
41
+ <Root
42
+ onRenderId={(id) => {
43
+ renderId = id
44
+ }}
45
+ routes={options.routes}
46
+ {...props}
47
+ />
48
+ )
36
49
  }
37
50
 
38
51
  AppRegistry.registerComponent('App', () => App)
@@ -48,11 +61,29 @@ export function createApp(options: CreateAppProps) {
48
61
  })
49
62
 
50
63
  try {
64
+ const extraHeadElements: React.ReactElement[] = []
65
+
51
66
  const styleTag = Application.getStyleElement({ nonce: process.env.ONE_NONCE })
52
67
  if (styleTag) {
53
- const rnwStyleHTML = ReactDOMServer.renderToStaticMarkup(styleTag)
54
- if (rnwStyleHTML) {
55
- html = html.replace(`</head>`, `${rnwStyleHTML}</head>`)
68
+ extraHeadElements.push(styleTag)
69
+ }
70
+
71
+ ensureExists(renderId)
72
+ const insertions = getServerHeadInsertions(renderId)
73
+ if (insertions) {
74
+ for (const insertion of insertions) {
75
+ const out = insertion()
76
+ if (out) {
77
+ extraHeadElements.push(out)
78
+ }
79
+ }
80
+ }
81
+
82
+ if (extraHeadElements.length) {
83
+ const extraHeadHTML = ReactDOMServer.renderToStaticMarkup(<>{extraHeadElements}</>)
84
+
85
+ if (extraHeadHTML) {
86
+ html = html.replace(`</head>`, `${extraHeadHTML}</head>`)
56
87
  }
57
88
  }
58
89
  } catch (err) {
@@ -0,0 +1,22 @@
1
+ /**
2
+ * Shared utilities for modifications in the fork.
3
+ */
4
+
5
+ export const getParamName = (pattern: string) => pattern.replace(/^[:*]/, '').replace(/\?$/, '')
6
+
7
+ export function getParamValue(p: string, value: string) {
8
+ if (p.startsWith('*')) {
9
+ const values = value.split('/').filter((v) => v !== '')
10
+ return values.length === 0 && p.endsWith('?') ? undefined : values
11
+ }
12
+
13
+ return value
14
+ }
15
+
16
+ export function isDynamicPart(p: string) {
17
+ return p.length > 1 && (p.startsWith(':') || p.startsWith('*'))
18
+ }
19
+
20
+ export function replacePart(p: string) {
21
+ return p.replace(/^[:*]/, '').replace(/\?$/, '')
22
+ }
@@ -7,6 +7,7 @@
7
7
  import type { Route } from '@react-navigation/core'
8
8
 
9
9
  import { matchDeepDynamicRouteName, matchDynamicName, matchGroupName } from '../router/matchers'
10
+ import { getParamName } from './_shared'
10
11
 
11
12
  export type AdditionalOptions = {
12
13
  preserveDynamicRoutes?: boolean
@@ -33,12 +34,12 @@ export function getPathWithConventionsCollapsed({
33
34
  params: Record<string, any>
34
35
  initialRouteName?: string
35
36
  }) {
36
- const segments = pattern.split('/');
37
-
37
+ const segments = pattern.split('/')
38
38
  return segments
39
39
  .map((p, i) => {
40
40
  const name = getParamName(p)
41
41
 
42
+ // We don't know what to show for wildcard patterns
42
43
  // Showing the route name seems ok, though whatever we show here will be incorrect
43
44
  // Since the page doesn't actually exist
44
45
  if (p.startsWith('*')) {
@@ -61,11 +62,21 @@ export function getPathWithConventionsCollapsed({
61
62
  return ''
62
63
  }
63
64
 
65
+ if (i === 0) {
66
+ // This can occur when a wildcard matches all routes and the given path was `/`.
67
+ return route
68
+ }
69
+
64
70
  if (p === '*not-found') {
65
71
  return ''
66
72
  }
67
-
73
+ // remove existing segments from route.path and return it
74
+ // this is used for nested wildcard routes. Without this, the path would add
75
+ // all nested segments to the beginning of the wildcard route.
68
76
  return route.name
77
+ ?.split('/')
78
+ .slice(i + 1)
79
+ .join('/')
69
80
  }
70
81
 
71
82
  // If the path has a pattern for a param, put the param in the path
@@ -79,6 +90,7 @@ export function getPathWithConventionsCollapsed({
79
90
  return
80
91
  }
81
92
 
93
+ // return params[name]
82
94
  return (shouldEncodeURISegment ? encodeURISegment(value) : value) ?? 'undefined'
83
95
  }
84
96
 
@@ -92,21 +104,24 @@ export function getPathWithConventionsCollapsed({
92
104
  if (segmentMatchesConvention(initialRouteName)) {
93
105
  return ''
94
106
  }
107
+
95
108
  return shouldEncodeURISegment
96
- ? encodeURISegment(initialRouteName, { preserveBrackets: true })
109
+ ? encodeURIComponentPreservingBrackets(initialRouteName)
97
110
  : initialRouteName
98
111
  }
99
112
  }
100
113
  return ''
101
114
  }
102
- // Preserve dynamic syntax for rehydration
103
- return shouldEncodeURISegment ? encodeURISegment(p, { preserveBrackets: true }) : p
115
+
116
+ return shouldEncodeURISegment ? encodeURIComponentPreservingBrackets(p) : p
104
117
  })
105
118
  .map((v) => v ?? '')
106
119
  .join('/')
107
120
  }
108
121
 
109
- export const getParamName = (pattern: string) => pattern.replace(/^[:*]/, '').replace(/\?$/, '')
122
+ function encodeURIComponentPreservingBrackets(str: string) {
123
+ return encodeURIComponent(str).replace(/%5B/g, '[').replace(/%5D/g, ']')
124
+ }
110
125
 
111
126
  export function appendBaseUrl(
112
127
  path: string,
@@ -13,6 +13,7 @@ import {
13
13
  appendBaseUrl,
14
14
  type AdditionalOptions,
15
15
  } from './getPathFromState-mods'
16
+ import * as sharedModUtils from './_shared'
16
17
  // @modified - end
17
18
 
18
19
  import type { NavigationState, PartialState, Route } from '@react-navigation/routers'
@@ -198,10 +199,10 @@ export function getPathDataFromState<ParamList extends {}>(
198
199
 
199
200
  pattern
200
201
  ?.split('/')
201
- .filter((p) => p.startsWith(':'))
202
+ .filter((p) => sharedModUtils.isDynamicPart(p)) // @modified
202
203
  // eslint-disable-next-line no-loop-func
203
204
  .forEach((p) => {
204
- const name = getParamName(p)
205
+ const name = sharedModUtils.getParamName(p) // @modified: use our customized `getParamName`
205
206
 
206
207
  // Remove the params present in the pattern since we'll only use the rest for query string
207
208
  if (focusedParams) {
@@ -291,15 +291,6 @@ export function decodeURIComponentSafe(str: string) {
291
291
  }
292
292
  }
293
293
 
294
- export function getParamValue(p: string, value: string) {
295
- if (p.startsWith('*')) {
296
- const values = value.split('/').filter((v) => v !== '')
297
- return values.length === 0 && p.endsWith('?') ? undefined : values
298
- }
299
-
300
- return value
301
- }
302
-
303
294
  /**
304
295
  * In One, the params are available at all levels of the routing config
305
296
  */
@@ -20,13 +20,13 @@ import {
20
20
  createConfigItemAdditionalProperties,
21
21
  decodeURIComponentSafe,
22
22
  formatRegexPattern,
23
- getParamValue,
24
23
  getRouteConfigSorter,
25
24
  getUrlWithReactNavigationConcessions,
26
25
  matchForEmptyPath,
27
26
  parseQueryParamsExtended,
28
27
  populateParams,
29
28
  } from './getStateFromPath-mods'
29
+ import { getParamValue, isDynamicPart, replacePart } from './_shared'
30
30
 
31
31
  type Options<ParamList extends {}> = {
32
32
  path?: string
@@ -263,7 +263,7 @@ function getNormalizedConfigs(
263
263
  createNormalizedConfigs(key, screens as PathConfigMap<object>, [], initialRoutes, [])
264
264
  )
265
265
  )
266
- /* @modified - start */
266
+ /* @modified - start */
267
267
  // .sort((a, b) => {
268
268
  // // Sort config so that:
269
269
  // // - the most exhaustive ones are always at the beginning
@@ -391,7 +391,7 @@ const matchAgainstConfigs = (remaining: string, configs: RouteConfig[]) => {
391
391
  matchedParams: Record<string, Record<string, string>> // The extracted params
392
392
  }>(
393
393
  (acc, p, index) => {
394
- if (!p.startsWith(':')) {
394
+ if (!isDynamicPart(p) /* @modified */) {
395
395
  return acc
396
396
  }
397
397
 
@@ -437,7 +437,7 @@ const matchAgainstConfigs = (remaining: string, configs: RouteConfig[]) => {
437
437
  const params = normalizedPath
438
438
  ?.split('/')
439
439
  .reduce<Record<string, unknown>>((acc, p, index) => {
440
- if (!p.startsWith(':')) {
440
+ if (!isDynamicPart(p) /* @modified */) {
441
441
  return acc
442
442
  }
443
443
 
@@ -450,7 +450,10 @@ const matchAgainstConfigs = (remaining: string, configs: RouteConfig[]) => {
450
450
  // @modified - end
451
451
 
452
452
  if (value) {
453
- const key = p.replace(/^:/, '').replace(/\?$/, '')
453
+ // @modified - start
454
+ // const key = p.replace(/^:/, '').replace(/\?$/, '')
455
+ const key = replacePart(p)
456
+ // @modified - end
454
457
  acc[key] = routeConfig?.parse?.[key] ? routeConfig.parse[key](value as any) : value
455
458
  }
456
459
 
package/src/index.ts CHANGED
@@ -38,6 +38,7 @@ export { Head } from './head'
38
38
 
39
39
  // hooks
40
40
  export { useLinkTo } from './link/useLinkTo'
41
+ export { useServerHeadInsertion, type ServerHeadInsertionCallback } from './useServerHeadInsertion'
41
42
  export {
42
43
  useRouter,
43
44
  useUnstableGlobalHref,
@@ -3,7 +3,7 @@ import type { BlankEnv } from 'hono/types'
3
3
  import { extname, join } from 'node:path'
4
4
  import { getServerEntry } from 'vxrn/serve'
5
5
  import { getPathFromLoaderPath } from '../utils/cleanUrl'
6
- import { LOADER_JS_POSTFIX_UNCACHED } from '../constants'
6
+ import { LOADER_JS_POSTFIX_REGEX, LOADER_JS_POSTFIX_UNCACHED } from '../constants'
7
7
  import { compileManifest, getURLfromRequestURL, type RequestHandlers } from '../createHandleRequest'
8
8
  import type { RenderAppProps } from '../types'
9
9
  import { toAbsolute } from '../utils/toAbsolute'
@@ -71,6 +71,11 @@ export async function oneServe(
71
71
  return await import(toAbsolute(route.contextKey))
72
72
  },
73
73
 
74
+ async handleLoader({ request, route, url, loaderProps }) {
75
+ // TODO this shouldn't be in dist/client right? we should build a dist/server version?
76
+ return await import(toAbsolute(join('./', 'dist/client', route.file)))
77
+ },
78
+
74
79
  async handlePage({ route, url, loaderProps }) {
75
80
  const buildInfo = routeToBuildInfo[route.file]
76
81
 
@@ -125,7 +130,7 @@ url: ${url}`)
125
130
  return async (context, next) => {
126
131
  // assets we ignore
127
132
  if (extname(context.req.path)) {
128
- return await next()
133
+ return next()
129
134
  }
130
135
 
131
136
  try {
@@ -133,6 +138,7 @@ url: ${url}`)
133
138
  const url = getURLfromRequestURL(request)
134
139
 
135
140
  const response = await (() => {
141
+ // this handles the ...rest style routes
136
142
  // where to put this best? can likely be after some of the switch?
137
143
  if (url.pathname.endsWith(LOADER_JS_POSTFIX_UNCACHED)) {
138
144
  const originalUrl = getPathFromLoaderPath(url.pathname)
@@ -182,13 +188,13 @@ url: ${url}`)
182
188
  return response as Response
183
189
  }
184
190
 
185
- return await next()
191
+ return next()
186
192
  }
187
193
  } catch (err) {
188
194
  console.error(` [one] Error handling request: ${(err as any)['stack']}`)
189
195
  }
190
196
 
191
- return await next()
197
+ return next()
192
198
  }
193
199
  }
194
200
 
@@ -205,4 +211,41 @@ url: ${url}`)
205
211
  for (const route of compiledManifest.pageRoutes) {
206
212
  app.get(route.honoPath, createHonoHandler(route))
207
213
  }
214
+
215
+ // TODO make this inside each page, need to make loader urls just be REGULAR_URL + loaderpostfix
216
+ app.get('*', async (c, next) => {
217
+ if (
218
+ c.req.path.endsWith(LOADER_JS_POSTFIX_UNCACHED) &&
219
+ // if it includes /assets its a static loader
220
+ !c.req.path.includes('/assets/')
221
+ ) {
222
+ const request = c.req.raw
223
+ const url = getURLfromRequestURL(request)
224
+ const originalUrl = getPathFromLoaderPath(c.req.path)
225
+
226
+ for (const route of compiledManifest.pageRoutes) {
227
+ if (route.file === '') {
228
+ // ignore not found route
229
+ continue
230
+ }
231
+
232
+ if (!route.compiledRegex.test(originalUrl)) {
233
+ continue
234
+ }
235
+
236
+ // for now just change this
237
+ route.file = c.req.path
238
+
239
+ const finalUrl = new URL(originalUrl, url.origin)
240
+ try {
241
+ return resolveLoaderRoute(requestHandlers, request, finalUrl, route)
242
+ } catch (err) {
243
+ console.error(`Error running loader: ${err}`)
244
+ return next()
245
+ }
246
+ }
247
+ }
248
+
249
+ return next()
250
+ })
208
251
  }
@@ -0,0 +1,25 @@
1
+ import { createContext, useContext, useId } from 'react'
2
+
3
+ export type ServerHeadInsertionCallback = () => React.ReactElement
4
+
5
+ const ServerHeadInsertions: Record<
6
+ string,
7
+ undefined | Record<string, ServerHeadInsertionCallback>
8
+ > = {}
9
+
10
+ export const getServerHeadInsertions = (id: string) => {
11
+ if (ServerHeadInsertions[id]) {
12
+ return Object.values(ServerHeadInsertions[id])
13
+ }
14
+ }
15
+
16
+ export const ServerRenderID = createContext('')
17
+
18
+ export const useServerHeadInsertion = (callback: ServerHeadInsertionCallback) => {
19
+ if (typeof window == 'undefined') {
20
+ const insertionID = useId()
21
+ const id = useContext(ServerRenderID)
22
+ ServerHeadInsertions[id] ||= {}
23
+ ServerHeadInsertions[id][insertionID] = callback
24
+ }
25
+ }
@@ -1,3 +1,5 @@
1
+ import { SERVER_CONTEXT_KEY } from '../constants'
2
+
1
3
  type ServerContext = {
2
4
  css?: string[]
3
5
  postRenderData?: any
@@ -9,7 +11,7 @@ type ServerContext = {
9
11
  type MaybeServerContext = null | ServerContext
10
12
 
11
13
  export const SERVER_CONTEXT_POST_RENDER_STRING = `_one_post_render_data_`
12
- const SERVER_CONTEXT_KEY = '__one_server_context__'
14
+
13
15
  const isClient = typeof document !== 'undefined'
14
16
 
15
17
  let serverContext: MaybeServerContext = globalThis[SERVER_CONTEXT_KEY] || null
@@ -3,16 +3,17 @@ import { debounce } from 'perfect-debounce'
3
3
  import type { Connect, Plugin, ViteDevServer } from 'vite'
4
4
  import { createServerModuleRunner } from 'vite'
5
5
  import type { ModuleRunner } from 'vite/module-runner'
6
+ import { SPA_HEADER_ELEMENTS } from '../../constants'
6
7
  import { createHandleRequest } from '../../createHandleRequest'
7
8
  import type { RenderAppProps } from '../../types'
8
9
  import { isResponse } from '../../utils/isResponse'
9
10
  import { isStatusRedirect } from '../../utils/isStatus'
10
11
  import { promiseWithResolvers } from '../../utils/promiseWithResolvers'
12
+ import { setServerContext } from '../../utils/serverContext'
11
13
  import { LoaderDataCache } from '../../vite/constants'
12
14
  import { replaceLoader } from '../../vite/replaceLoader'
13
15
  import type { One } from '../../vite/types'
14
16
  import { virtalEntryIdClient, virtualEntryId } from './virtualEntryConstants'
15
- import { setServerContext } from '../../utils/serverContext'
16
17
 
17
18
  // server needs better dep optimization
18
19
  const USE_SERVER_ENV = false //!!process.env.USE_SERVER_ENV
@@ -37,8 +38,7 @@ export function createFileSystemRouterPlugin(options: One.PluginOptions): Plugin
37
38
  if (route.type === 'spa') {
38
39
  // render just the layouts? route.layouts
39
40
  return `<html><head>
40
- <script>globalThis['global'] = globalThis</script>
41
- <script>globalThis['__vxrnIsSPA'] = true</script>
41
+ ${SPA_HEADER_ELEMENTS}
42
42
  <script type="module">
43
43
  import { injectIntoGlobalHook } from "/@react-refresh";
44
44
  injectIntoGlobalHook(window);
package/types/Root.d.ts CHANGED
@@ -3,6 +3,7 @@ import { type FunctionComponent, type ReactNode } from 'react';
3
3
  import type { GlobbedRouteImports } from './types';
4
4
  import type { One } from './vite/types';
5
5
  type RootProps = Omit<InnerProps, 'context'> & {
6
+ onRenderId?: (id: string) => void;
6
7
  path: string;
7
8
  isClient?: boolean;
8
9
  routes: GlobbedRouteImports;
@@ -1 +1 @@
1
- {"version":3,"file":"Root.d.ts","sourceRoot":"","sources":["../src/Root.tsx"],"names":[],"mappings":"AAAA,OAAO,EAIL,KAAK,wBAAwB,EAC9B,MAAM,0BAA0B,CAAA;AAEjC,OAAO,EAAuB,KAAK,iBAAiB,EAAE,KAAK,SAAS,EAAE,MAAM,OAAO,CAAA;AAMnF,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,SAAS,CAAA;AAKlD,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,cAAc,CAAA;AAYvC,KAAK,SAAS,GAAG,IAAI,CAAC,UAAU,EAAE,SAAS,CAAC,GAAG;IAC7C,IAAI,EAAE,MAAM,CAAA;IACZ,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,MAAM,EAAE,mBAAmB,CAAA;IAC3B,YAAY,CAAC,EAAE,GAAG,CAAC,YAAY,CAAA;CAChC,CAAA;AAED,KAAK,UAAU,GAAG;IAChB,OAAO,EAAE,GAAG,CAAC,YAAY,CAAA;IACzB,QAAQ,CAAC,EAAE,GAAG,CAAA;IACd,OAAO,CAAC,EAAE,iBAAiB,CAAC;QAAE,QAAQ,EAAE,SAAS,CAAA;KAAE,CAAC,CAAA;IACpD,wBAAwB,CAAC,EAAE,wBAAwB,GAAG;QACpD,KAAK,CAAC,EAAE;YACN,IAAI,EAAE,OAAO,CAAA;YACb,MAAM,EAAE;gBACN,OAAO,EAAE,MAAM,CAAA;gBACf,UAAU,EAAE,MAAM,CAAA;gBAClB,IAAI,EAAE,MAAM,CAAA;gBACZ,IAAI,EAAE,MAAM,CAAA;gBACZ,MAAM,EAAE,MAAM,CAAA;gBACd,YAAY,EAAE,MAAM,CAAA;aACrB,CAAA;SACF,CAAA;KACF,CAAA;CACF,CAAA;AAED,wBAAgB,IAAI,CAAC,KAAK,EAAE,SAAS,kDA2EpC"}
1
+ {"version":3,"file":"Root.d.ts","sourceRoot":"","sources":["../src/Root.tsx"],"names":[],"mappings":"AAAA,OAAO,EAIL,KAAK,wBAAwB,EAC9B,MAAM,0BAA0B,CAAA;AAEjC,OAAO,EAA8B,KAAK,iBAAiB,EAAE,KAAK,SAAS,EAAE,MAAM,OAAO,CAAA;AAM1F,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,SAAS,CAAA;AAKlD,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,cAAc,CAAA;AASvC,KAAK,SAAS,GAAG,IAAI,CAAC,UAAU,EAAE,SAAS,CAAC,GAAG;IAC7C,UAAU,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAA;IACjC,IAAI,EAAE,MAAM,CAAA;IACZ,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,MAAM,EAAE,mBAAmB,CAAA;IAC3B,YAAY,CAAC,EAAE,GAAG,CAAC,YAAY,CAAA;CAChC,CAAA;AAED,KAAK,UAAU,GAAG;IAChB,OAAO,EAAE,GAAG,CAAC,YAAY,CAAA;IACzB,QAAQ,CAAC,EAAE,GAAG,CAAA;IACd,OAAO,CAAC,EAAE,iBAAiB,CAAC;QAAE,QAAQ,EAAE,SAAS,CAAA;KAAE,CAAC,CAAA;IACpD,wBAAwB,CAAC,EAAE,wBAAwB,GAAG;QACpD,KAAK,CAAC,EAAE;YACN,IAAI,EAAE,OAAO,CAAA;YACb,MAAM,EAAE;gBACN,OAAO,EAAE,MAAM,CAAA;gBACf,UAAU,EAAE,MAAM,CAAA;gBAClB,IAAI,EAAE,MAAM,CAAA;gBACZ,IAAI,EAAE,MAAM,CAAA;gBACZ,MAAM,EAAE,MAAM,CAAA;gBACd,YAAY,EAAE,MAAM,CAAA;aACrB,CAAA;SACF,CAAA;KACF,CAAA;CACF,CAAA;AAED,wBAAgB,IAAI,CAAC,KAAK,EAAE,SAAS,kDAiFpC"}
@@ -1 +1 @@
1
- {"version":3,"file":"build.d.ts","sourceRoot":"","sources":["../../src/cli/build.ts"],"names":[],"mappings":"AA+BA,wBAAsB,KAAK,CAAC,IAAI,EAAE;IAChC,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,IAAI,CAAC,EAAE,MAAM,CAAA;CACd,iBAslBA"}
1
+ {"version":3,"file":"build.d.ts","sourceRoot":"","sources":["../../src/cli/build.ts"],"names":[],"mappings":"AA+BA,wBAAsB,KAAK,CAAC,IAAI,EAAE;IAChC,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,IAAI,CAAC,EAAE,MAAM,CAAA;CACd,iBAylBA"}
@@ -9,4 +9,6 @@ export declare const LOADER_JS_POSTFIX: string;
9
9
  export declare const PRELOAD_JS_POSTFIX: string;
10
10
  export declare const VIRTUAL_SSR_CSS_ENTRY = "virtual:ssr-css.css";
11
11
  export declare const VIRTUAL_SSR_CSS_HREF = "/@id/__x00__virtual:ssr-css.css";
12
+ export declare const SERVER_CONTEXT_KEY = "__one_server_context__";
13
+ export declare const SPA_HEADER_ELEMENTS = "\n <script>globalThis['global'] = globalThis</script>\n <script>globalThis['__vxrnIsSPA'] = true</script>\n <script>globalThis[\"__one_server_context__\"] = {}</script>\n";
12
14
  //# sourceMappingURL=constants.d.ts.map