houdini-react 2.0.0-next.4 → 2.0.0-next.40
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.
- package/bin/houdini-react +173 -0
- package/package.json +63 -39
- package/postInstall.js +360 -0
- package/runtime/Link.tsx +81 -0
- package/runtime/client.ts +5 -0
- package/runtime/clientPlugin.ts +17 -0
- package/runtime/componentFields.ts +79 -0
- package/runtime/hooks/index.ts +9 -0
- package/runtime/hooks/recycleNodesInto.ts +60 -0
- package/runtime/hooks/useDeepCompareEffect.ts +93 -0
- package/runtime/hooks/useDocumentHandle.ts +238 -0
- package/runtime/hooks/useDocumentStore.ts +112 -0
- package/runtime/hooks/useDocumentSubscription.ts +65 -0
- package/runtime/hooks/useFragment.ts +101 -0
- package/runtime/hooks/useFragmentHandle.ts +191 -0
- package/runtime/hooks/useIsMounted.ts +14 -0
- package/runtime/hooks/useMutation.ts +70 -0
- package/runtime/hooks/useQuery.ts +12 -0
- package/runtime/hooks/useQueryHandle.ts +194 -0
- package/runtime/hooks/useSubscription.ts +12 -0
- package/runtime/hooks/useSubscriptionHandle.ts +38 -0
- package/runtime/hydration.tsx +155 -0
- package/runtime/index.tsx +66 -0
- package/runtime/manifest.ts +6 -0
- package/runtime/package.json +1 -0
- package/runtime/resolve-href.ts +14 -0
- package/runtime/routing/Router.tsx +959 -0
- package/runtime/routing/cache.ts +57 -0
- package/runtime/routing/errors.tsx +145 -0
- package/runtime/routing/index.ts +17 -0
- package/runtime/tsconfig.json +39 -0
- package/server/index.d.ts +1 -0
- package/server/index.js +4 -0
- package/server/react-streaming.d.js +0 -0
- package/vite/index.d.ts +3 -0
- package/vite/index.js +384 -0
- package/vite/transform.d.ts +11 -0
- package/vite/transform.js +90 -0
- package/README.md +0 -36
- package/build/plugin/codegen/entries/documentWrappers.d.ts +0 -6
- package/build/plugin/codegen/entries/fallbacks.d.ts +0 -5
- package/build/plugin/codegen/entries/index.d.ts +0 -16
- package/build/plugin/codegen/entries/pages.d.ts +0 -2
- package/build/plugin/codegen/index.d.ts +0 -17
- package/build/plugin/codegen/manifest.d.ts +0 -5
- package/build/plugin/codegen/render.d.ts +0 -7
- package/build/plugin/codegen/router.d.ts +0 -7
- package/build/plugin/codegen/typeRoot.d.ts +0 -5
- package/build/plugin/config.d.ts +0 -4
- package/build/plugin/dedent.d.ts +0 -1
- package/build/plugin/extract.d.ts +0 -6
- package/build/plugin/index.d.ts +0 -5
- package/build/plugin/state.d.ts +0 -3
- package/build/plugin/transform.d.ts +0 -6
- package/build/plugin/vite.d.ts +0 -27
- package/build/plugin-cjs/index.js +0 -90119
- package/build/plugin-cjs/package.json +0 -1
- package/build/plugin-esm/index.js +0 -90115
- package/build/runtime/client.d.ts +0 -3
- package/build/runtime/clientPlugin.d.ts +0 -3
- package/build/runtime/componentFields.d.ts +0 -9
- package/build/runtime/hooks/index.d.ts +0 -8
- package/build/runtime/hooks/useDeepCompareEffect.d.ts +0 -35
- package/build/runtime/hooks/useDocumentHandle.d.ts +0 -36
- package/build/runtime/hooks/useDocumentStore.d.ts +0 -11
- package/build/runtime/hooks/useDocumentSubscription.d.ts +0 -11
- package/build/runtime/hooks/useFragment.d.ts +0 -16
- package/build/runtime/hooks/useFragmentHandle.d.ts +0 -8
- package/build/runtime/hooks/useIsMounted.d.ts +0 -3
- package/build/runtime/hooks/useMutation.d.ts +0 -14
- package/build/runtime/hooks/useQuery.d.ts +0 -5
- package/build/runtime/hooks/useQueryHandle.d.ts +0 -10
- package/build/runtime/hooks/useSubscription.d.ts +0 -4
- package/build/runtime/hooks/useSubscriptionHandle.d.ts +0 -25
- package/build/runtime/index.d.ts +0 -14
- package/build/runtime/manifest.d.ts +0 -3
- package/build/runtime/routing/Router.d.ts +0 -62
- package/build/runtime/routing/cache.d.ts +0 -7
- package/build/runtime/routing/hooks.d.ts +0 -40
- package/build/runtime/routing/index.d.ts +0 -3
- package/build/runtime-cjs/client.d.ts +0 -3
- package/build/runtime-cjs/client.js +0 -25
- package/build/runtime-cjs/clientPlugin.d.ts +0 -3
- package/build/runtime-cjs/clientPlugin.js +0 -37
- package/build/runtime-cjs/componentFields.d.ts +0 -9
- package/build/runtime-cjs/componentFields.js +0 -83
- package/build/runtime-cjs/hooks/index.d.ts +0 -8
- package/build/runtime-cjs/hooks/index.js +0 -45
- package/build/runtime-cjs/hooks/useDeepCompareEffect.d.ts +0 -35
- package/build/runtime-cjs/hooks/useDeepCompareEffect.js +0 -76
- package/build/runtime-cjs/hooks/useDocumentHandle.d.ts +0 -36
- package/build/runtime-cjs/hooks/useDocumentHandle.js +0 -177
- package/build/runtime-cjs/hooks/useDocumentStore.d.ts +0 -11
- package/build/runtime-cjs/hooks/useDocumentStore.js +0 -76
- package/build/runtime-cjs/hooks/useDocumentSubscription.d.ts +0 -11
- package/build/runtime-cjs/hooks/useDocumentSubscription.js +0 -76
- package/build/runtime-cjs/hooks/useFragment.d.ts +0 -16
- package/build/runtime-cjs/hooks/useFragment.js +0 -102
- package/build/runtime-cjs/hooks/useFragmentHandle.d.ts +0 -8
- package/build/runtime-cjs/hooks/useFragmentHandle.js +0 -47
- package/build/runtime-cjs/hooks/useIsMounted.d.ts +0 -3
- package/build/runtime-cjs/hooks/useIsMounted.js +0 -38
- package/build/runtime-cjs/hooks/useMutation.d.ts +0 -14
- package/build/runtime-cjs/hooks/useMutation.js +0 -67
- package/build/runtime-cjs/hooks/useQuery.d.ts +0 -5
- package/build/runtime-cjs/hooks/useQuery.js +0 -32
- package/build/runtime-cjs/hooks/useQueryHandle.d.ts +0 -10
- package/build/runtime-cjs/hooks/useQueryHandle.js +0 -131
- package/build/runtime-cjs/hooks/useSubscription.d.ts +0 -4
- package/build/runtime-cjs/hooks/useSubscription.js +0 -32
- package/build/runtime-cjs/hooks/useSubscriptionHandle.d.ts +0 -25
- package/build/runtime-cjs/hooks/useSubscriptionHandle.js +0 -42
- package/build/runtime-cjs/index.d.ts +0 -14
- package/build/runtime-cjs/index.js +0 -88
- package/build/runtime-cjs/manifest.d.ts +0 -3
- package/build/runtime-cjs/manifest.js +0 -25
- package/build/runtime-cjs/package.json +0 -1
- package/build/runtime-cjs/routing/Router.d.ts +0 -62
- package/build/runtime-cjs/routing/Router.js +0 -540
- package/build/runtime-cjs/routing/cache.d.ts +0 -7
- package/build/runtime-cjs/routing/cache.js +0 -61
- package/build/runtime-cjs/routing/hooks.d.ts +0 -40
- package/build/runtime-cjs/routing/hooks.js +0 -93
- package/build/runtime-cjs/routing/index.d.ts +0 -3
- package/build/runtime-cjs/routing/index.js +0 -33
- package/build/runtime-esm/client.d.ts +0 -3
- package/build/runtime-esm/client.js +0 -5
- package/build/runtime-esm/clientPlugin.d.ts +0 -3
- package/build/runtime-esm/clientPlugin.js +0 -17
- package/build/runtime-esm/componentFields.d.ts +0 -9
- package/build/runtime-esm/componentFields.js +0 -59
- package/build/runtime-esm/hooks/index.d.ts +0 -8
- package/build/runtime-esm/hooks/index.js +0 -15
- package/build/runtime-esm/hooks/useDeepCompareEffect.d.ts +0 -35
- package/build/runtime-esm/hooks/useDeepCompareEffect.js +0 -41
- package/build/runtime-esm/hooks/useDocumentHandle.d.ts +0 -36
- package/build/runtime-esm/hooks/useDocumentHandle.js +0 -143
- package/build/runtime-esm/hooks/useDocumentStore.d.ts +0 -11
- package/build/runtime-esm/hooks/useDocumentStore.js +0 -42
- package/build/runtime-esm/hooks/useDocumentSubscription.d.ts +0 -11
- package/build/runtime-esm/hooks/useDocumentSubscription.js +0 -42
- package/build/runtime-esm/hooks/useFragment.d.ts +0 -16
- package/build/runtime-esm/hooks/useFragment.js +0 -67
- package/build/runtime-esm/hooks/useFragmentHandle.d.ts +0 -8
- package/build/runtime-esm/hooks/useFragmentHandle.js +0 -23
- package/build/runtime-esm/hooks/useIsMounted.d.ts +0 -3
- package/build/runtime-esm/hooks/useIsMounted.js +0 -14
- package/build/runtime-esm/hooks/useMutation.d.ts +0 -14
- package/build/runtime-esm/hooks/useMutation.js +0 -42
- package/build/runtime-esm/hooks/useQuery.d.ts +0 -5
- package/build/runtime-esm/hooks/useQuery.js +0 -8
- package/build/runtime-esm/hooks/useQueryHandle.d.ts +0 -10
- package/build/runtime-esm/hooks/useQueryHandle.js +0 -97
- package/build/runtime-esm/hooks/useSubscription.d.ts +0 -4
- package/build/runtime-esm/hooks/useSubscription.js +0 -8
- package/build/runtime-esm/hooks/useSubscriptionHandle.d.ts +0 -25
- package/build/runtime-esm/hooks/useSubscriptionHandle.js +0 -18
- package/build/runtime-esm/index.d.ts +0 -14
- package/build/runtime-esm/index.js +0 -48
- package/build/runtime-esm/manifest.d.ts +0 -3
- package/build/runtime-esm/manifest.js +0 -5
- package/build/runtime-esm/routing/Router.d.ts +0 -62
- package/build/runtime-esm/routing/Router.js +0 -499
- package/build/runtime-esm/routing/cache.d.ts +0 -7
- package/build/runtime-esm/routing/cache.js +0 -36
- package/build/runtime-esm/routing/hooks.d.ts +0 -40
- package/build/runtime-esm/routing/hooks.js +0 -53
- package/build/runtime-esm/routing/index.d.ts +0 -3
- package/build/runtime-esm/routing/index.js +0 -6
- package/build/server/index.d.ts +0 -1
- package/build/server-cjs/index.js +0 -28
- package/build/server-cjs/package.json +0 -1
- package/build/server-esm/index.js +0 -4
- package/build/server-esm/package.json +0 -1
- /package/{build/plugin-esm → server}/package.json +0 -0
- /package/{build/runtime-esm → vite}/package.json +0 -0
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
// a suspense cache is an object that maintains a key-value store of
|
|
2
|
+
// objects. If a value is missing when get() is called, a promise
|
|
3
|
+
// is thrown that resolves when a value is passed to set()
|
|
4
|
+
import { LRUCache } from 'houdini/runtime'
|
|
5
|
+
|
|
6
|
+
export function suspense_cache<T>(initialData?: Record<string, T>): SuspenseCache<T> {
|
|
7
|
+
const cache = new SuspenseCache<T>()
|
|
8
|
+
|
|
9
|
+
for (const [key, value] of Object.entries(initialData ?? {})) {
|
|
10
|
+
cache.set(key, value)
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
return cache
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export class SuspenseCache<_Data> extends LRUCache<_Data> {
|
|
17
|
+
// if get is called before set, we need to invoke a callback.
|
|
18
|
+
// that means we need a place to put our callbacks
|
|
19
|
+
#callbacks: Map<string, { resolve: () => void; reject: () => void }[]> = new Map()
|
|
20
|
+
|
|
21
|
+
get(key: string): _Data {
|
|
22
|
+
// if there is a value, use that
|
|
23
|
+
if (super.has(key)) {
|
|
24
|
+
return super.get(key)!
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
// we don't have a value, so we need to throw a promise
|
|
28
|
+
// that resolves when a value is passed to set()
|
|
29
|
+
throw new Promise<void>((resolve, reject) => {
|
|
30
|
+
this.#subscribe(key, resolve, reject)
|
|
31
|
+
})
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
override clear() {
|
|
35
|
+
super.clear()
|
|
36
|
+
this.#callbacks.clear()
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
set(key: string, value: _Data) {
|
|
40
|
+
// perform the set like normal
|
|
41
|
+
super.set(key, value)
|
|
42
|
+
|
|
43
|
+
// if there are subscribers, resolve them
|
|
44
|
+
if (this.#callbacks.has(key)) {
|
|
45
|
+
// resolve all of the callbacks
|
|
46
|
+
this.#callbacks.get(key)?.forEach(({ resolve }) => {
|
|
47
|
+
resolve()
|
|
48
|
+
})
|
|
49
|
+
// delete the key
|
|
50
|
+
this.#callbacks.delete(key)
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
#subscribe(key: string, resolve: () => void, reject: () => void) {
|
|
55
|
+
this.#callbacks.set(key, [...(this.#callbacks.get(key) || []), { resolve, reject }])
|
|
56
|
+
}
|
|
57
|
+
}
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
import type { GraphQLError } from 'houdini/runtime'
|
|
2
|
+
import React from 'react'
|
|
3
|
+
|
|
4
|
+
export class GraphQLErrors extends Error {
|
|
5
|
+
graphqlErrors: GraphQLError[]
|
|
6
|
+
|
|
7
|
+
constructor(errors: GraphQLError[]) {
|
|
8
|
+
super(errors.map((e) => e.message).join('\n'))
|
|
9
|
+
this.name = 'GraphQLErrors'
|
|
10
|
+
this.graphqlErrors = errors
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
let _currentSegment: string | undefined
|
|
15
|
+
|
|
16
|
+
export function setCurrentSegment(id: string | undefined): void {
|
|
17
|
+
_currentSegment = id
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function getCurrentSegment(): string | undefined {
|
|
21
|
+
return _currentSegment
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export class RoutingError extends Error {
|
|
25
|
+
status: number
|
|
26
|
+
segment: string | undefined
|
|
27
|
+
|
|
28
|
+
constructor(status: number) {
|
|
29
|
+
super(`Routing error: ${status}`)
|
|
30
|
+
this.name = 'RoutingError'
|
|
31
|
+
this.status = status
|
|
32
|
+
this.segment = getCurrentSegment()
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export class RedirectError extends Error {
|
|
37
|
+
status: number
|
|
38
|
+
location: string
|
|
39
|
+
|
|
40
|
+
constructor(status: number, location: string) {
|
|
41
|
+
super(`Redirect: ${status} ${location}`)
|
|
42
|
+
this.name = 'RedirectError'
|
|
43
|
+
this.status = status
|
|
44
|
+
this.location = location
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export function isRoutingError(error: unknown): error is RoutingError {
|
|
49
|
+
return error instanceof RoutingError
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export function isApiError(error: unknown): error is GraphQLErrors {
|
|
53
|
+
return error instanceof GraphQLErrors
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export function notFound(): never {
|
|
57
|
+
throw new RoutingError(404)
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export function unauthorized(): never {
|
|
61
|
+
throw new RoutingError(401)
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export function forbidden(): never {
|
|
65
|
+
throw new RoutingError(403)
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export function httpError(status: number): never {
|
|
69
|
+
throw new RoutingError(status)
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
export function redirect(status: 300 | 301 | 302 | 303 | 307 | 308, location: string): never {
|
|
73
|
+
throw new RedirectError(status, location)
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// Mutable ref passed from the server renderer so that a synchronous RoutingError
|
|
77
|
+
// or redirect() can propagate the correct HTTP status/location before streaming.
|
|
78
|
+
export const StatusContext = React.createContext<{ status: number; location?: string } | null>(null)
|
|
79
|
+
|
|
80
|
+
type HoudiniErrorBoundaryProps = {
|
|
81
|
+
errorView: React.ComponentType<{
|
|
82
|
+
errors: Array<Error | GraphQLError>
|
|
83
|
+
children: React.ReactNode
|
|
84
|
+
}>
|
|
85
|
+
children: React.ReactNode
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
type HoudiniErrorBoundaryState = {
|
|
89
|
+
hasError: boolean
|
|
90
|
+
errors: Array<Error | GraphQLError>
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
export class HoudiniErrorBoundary extends React.Component<
|
|
94
|
+
HoudiniErrorBoundaryProps,
|
|
95
|
+
HoudiniErrorBoundaryState
|
|
96
|
+
> {
|
|
97
|
+
static contextType = StatusContext
|
|
98
|
+
declare context: React.ContextType<typeof StatusContext>
|
|
99
|
+
|
|
100
|
+
constructor(
|
|
101
|
+
props: HoudiniErrorBoundaryProps,
|
|
102
|
+
context: React.ContextType<typeof StatusContext>
|
|
103
|
+
) {
|
|
104
|
+
super(props, context)
|
|
105
|
+
// Second-pass SSR: statusRef is pre-set to an error status by on_render after the first
|
|
106
|
+
// render threw. Start in error state immediately so children never render (and never throw).
|
|
107
|
+
if (typeof window === 'undefined' && context && context.status >= 400) {
|
|
108
|
+
this.state = {
|
|
109
|
+
hasError: true,
|
|
110
|
+
errors: [new RoutingError(context.status)],
|
|
111
|
+
}
|
|
112
|
+
} else {
|
|
113
|
+
this.state = { hasError: false, errors: [] }
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
static getDerivedStateFromError(error: unknown): HoudiniErrorBoundaryState {
|
|
118
|
+
if (error instanceof GraphQLErrors) {
|
|
119
|
+
return { hasError: true, errors: error.graphqlErrors }
|
|
120
|
+
}
|
|
121
|
+
return {
|
|
122
|
+
hasError: true,
|
|
123
|
+
errors: [error instanceof Error ? error : new Error(String(error))],
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
componentDidCatch(error: Error): void {
|
|
128
|
+
if (this.context) {
|
|
129
|
+
if (error instanceof RoutingError) {
|
|
130
|
+
this.context.status = error.status
|
|
131
|
+
} else if (error instanceof RedirectError) {
|
|
132
|
+
this.context.status = error.status
|
|
133
|
+
this.context.location = error.location
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
render() {
|
|
139
|
+
if (this.state.hasError) {
|
|
140
|
+
const ErrorView = this.props.errorView
|
|
141
|
+
return <ErrorView errors={this.state.errors}>{this.props.children}</ErrorView>
|
|
142
|
+
}
|
|
143
|
+
return this.props.children
|
|
144
|
+
}
|
|
145
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export * from './Router.js'
|
|
2
|
+
export { type SuspenseCache, suspense_cache } from './cache.js'
|
|
3
|
+
export {
|
|
4
|
+
HoudiniErrorBoundary,
|
|
5
|
+
GraphQLErrors,
|
|
6
|
+
RoutingError,
|
|
7
|
+
RedirectError,
|
|
8
|
+
notFound,
|
|
9
|
+
unauthorized,
|
|
10
|
+
forbidden,
|
|
11
|
+
httpError,
|
|
12
|
+
redirect,
|
|
13
|
+
isRoutingError,
|
|
14
|
+
isApiError,
|
|
15
|
+
StatusContext,
|
|
16
|
+
setCurrentSegment,
|
|
17
|
+
} from './errors.js'
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"baseUrl": ".",
|
|
4
|
+
"paths": {
|
|
5
|
+
"$houdini": ["."],
|
|
6
|
+
"$houdini/*": ["./*"],
|
|
7
|
+
"~": ["../src"],
|
|
8
|
+
"~/*": ["../src/*"]
|
|
9
|
+
},
|
|
10
|
+
"rootDirs": ["..", "./types"],
|
|
11
|
+
"target": "ESNext",
|
|
12
|
+
"useDefineForClassFields": true,
|
|
13
|
+
"lib": ["DOM", "DOM.Iterable", "ESNext"],
|
|
14
|
+
"allowJs": true,
|
|
15
|
+
"skipLibCheck": true,
|
|
16
|
+
"esModuleInterop": false,
|
|
17
|
+
"allowSyntheticDefaultImports": true,
|
|
18
|
+
"strict": true,
|
|
19
|
+
"forceConsistentCasingInFileNames": true,
|
|
20
|
+
"module": "ESNext",
|
|
21
|
+
"moduleResolution": "Bundler",
|
|
22
|
+
"allowImportingTsExtensions": true,
|
|
23
|
+
"resolveJsonModule": true,
|
|
24
|
+
"isolatedModules": true,
|
|
25
|
+
"noEmit": true,
|
|
26
|
+
"jsx": "react-jsx"
|
|
27
|
+
},
|
|
28
|
+
"include": [
|
|
29
|
+
"ambient.d.ts",
|
|
30
|
+
"./types/**/$types.d.ts",
|
|
31
|
+
"../vite.config.ts",
|
|
32
|
+
"../src/**/*.js",
|
|
33
|
+
"../src/**/*.ts",
|
|
34
|
+
"../src/**/*.jsx",
|
|
35
|
+
"../src/**/*.tsx",
|
|
36
|
+
"../src/+app.d.ts"
|
|
37
|
+
],
|
|
38
|
+
"exclude": ["../node_modules/**", "./[!ambient.d.ts]**"]
|
|
39
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { renderToStream } from 'react-streaming/server';
|
package/server/index.js
ADDED
|
File without changes
|
package/vite/index.d.ts
ADDED
package/vite/index.js
ADDED
|
@@ -0,0 +1,384 @@
|
|
|
1
|
+
import { fs, path } from "houdini";
|
|
2
|
+
import {
|
|
3
|
+
app_component_path,
|
|
4
|
+
adapter_config_path,
|
|
5
|
+
plugin_dir,
|
|
6
|
+
client_build_directory
|
|
7
|
+
} from "houdini/router/conventions";
|
|
8
|
+
import { load_manifest } from "houdini/router/manifest";
|
|
9
|
+
import { existsSync, mkdirSync, writeFileSync } from "node:fs";
|
|
10
|
+
import { createRequire } from "node:module";
|
|
11
|
+
import { build } from "vite";
|
|
12
|
+
import { transform_file } from "./transform.js";
|
|
13
|
+
const REACT_TSCONFIG_STUB = `{
|
|
14
|
+
"compilerOptions": {
|
|
15
|
+
"baseUrl": ".",
|
|
16
|
+
"paths": {
|
|
17
|
+
"$houdini": ["."],
|
|
18
|
+
"$houdini/*": ["./*"],
|
|
19
|
+
"~": ["../src"],
|
|
20
|
+
"~/*": ["../src/*"]
|
|
21
|
+
},
|
|
22
|
+
"rootDirs": ["..", "./types"],
|
|
23
|
+
"target": "ESNext",
|
|
24
|
+
"useDefineForClassFields": true,
|
|
25
|
+
"lib": ["DOM", "DOM.Iterable", "ESNext"],
|
|
26
|
+
"allowJs": true,
|
|
27
|
+
"skipLibCheck": true,
|
|
28
|
+
"esModuleInterop": false,
|
|
29
|
+
"allowSyntheticDefaultImports": true,
|
|
30
|
+
"strict": true,
|
|
31
|
+
"forceConsistentCasingInFileNames": true,
|
|
32
|
+
"module": "ESNext",
|
|
33
|
+
"moduleResolution": "Bundler",
|
|
34
|
+
"allowImportingTsExtensions": true,
|
|
35
|
+
"resolveJsonModule": true,
|
|
36
|
+
"isolatedModules": true,
|
|
37
|
+
"noEmit": true,
|
|
38
|
+
"jsx": "react-jsx"
|
|
39
|
+
},
|
|
40
|
+
"include": [
|
|
41
|
+
"ambient.d.ts",
|
|
42
|
+
"./types/**/$types.d.ts",
|
|
43
|
+
"../vite.config.ts",
|
|
44
|
+
"../src/**/*.js",
|
|
45
|
+
"../src/**/*.ts",
|
|
46
|
+
"../src/**/*.jsx",
|
|
47
|
+
"../src/**/*.tsx",
|
|
48
|
+
"../src/+app.d.ts"
|
|
49
|
+
],
|
|
50
|
+
"exclude": ["../node_modules/**", "./[!ambient.d.ts]**"]
|
|
51
|
+
}
|
|
52
|
+
`;
|
|
53
|
+
const _require = createRequire(import.meta.url);
|
|
54
|
+
let reactStreamingServerPath = "";
|
|
55
|
+
try {
|
|
56
|
+
const main = _require.resolve("react-streaming");
|
|
57
|
+
const pkgDir = main.replace(/\/dist\/.*$/, "");
|
|
58
|
+
reactStreamingServerPath = path.join(pkgDir, "dist/server/index.node-and-web.js");
|
|
59
|
+
} catch {
|
|
60
|
+
}
|
|
61
|
+
function index_default(ctx) {
|
|
62
|
+
let manifest;
|
|
63
|
+
let viteEnv;
|
|
64
|
+
let devServer = false;
|
|
65
|
+
let isSSRBuild = false;
|
|
66
|
+
let cfCache = null;
|
|
67
|
+
return {
|
|
68
|
+
name: "houdini-react",
|
|
69
|
+
configResolved(config) {
|
|
70
|
+
isSSRBuild = !!config.build.ssr;
|
|
71
|
+
},
|
|
72
|
+
async config(userConfig, env) {
|
|
73
|
+
viteEnv = env;
|
|
74
|
+
const runtimeDir = path.join(
|
|
75
|
+
ctx.config.root_dir,
|
|
76
|
+
ctx.config.config_file.runtimeDir ?? ".houdini"
|
|
77
|
+
);
|
|
78
|
+
try {
|
|
79
|
+
mkdirSync(runtimeDir, { recursive: true });
|
|
80
|
+
const tsconfigPath = path.join(runtimeDir, "tsconfig.json");
|
|
81
|
+
if (!existsSync(tsconfigPath)) {
|
|
82
|
+
writeFileSync(tsconfigPath, REACT_TSCONFIG_STUB);
|
|
83
|
+
}
|
|
84
|
+
} catch {
|
|
85
|
+
}
|
|
86
|
+
if (userConfig.build?.ssr) {
|
|
87
|
+
return reactStreamingServerPath ? { resolve: { alias: { "react-streaming/server": reactStreamingServerPath } } } : {};
|
|
88
|
+
}
|
|
89
|
+
try {
|
|
90
|
+
manifest = await load_manifest({ config: ctx.config });
|
|
91
|
+
} catch (e) {
|
|
92
|
+
console.log(
|
|
93
|
+
"something went wrong. please try again. \n error: " + e.message
|
|
94
|
+
);
|
|
95
|
+
manifest = {
|
|
96
|
+
pages: {},
|
|
97
|
+
layouts: {},
|
|
98
|
+
page_queries: {},
|
|
99
|
+
layout_queries: {},
|
|
100
|
+
artifacts: [],
|
|
101
|
+
local_schema: false,
|
|
102
|
+
local_yoga: false,
|
|
103
|
+
component_fields: {}
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
let conf = {
|
|
107
|
+
build: { rollupOptions: {} }
|
|
108
|
+
};
|
|
109
|
+
if (env.command === "build") {
|
|
110
|
+
conf.base = "/assets";
|
|
111
|
+
}
|
|
112
|
+
const compiledAssetsDir = client_build_directory(ctx.config);
|
|
113
|
+
await fs.mkdirp(compiledAssetsDir);
|
|
114
|
+
conf.build = {
|
|
115
|
+
outDir: compiledAssetsDir,
|
|
116
|
+
rollupOptions: {
|
|
117
|
+
output: {
|
|
118
|
+
assetFileNames: "assets/[name].js",
|
|
119
|
+
entryFileNames: "[name].js"
|
|
120
|
+
},
|
|
121
|
+
input: {
|
|
122
|
+
"entries/app": app_component_path(ctx.config),
|
|
123
|
+
...ctx.adapter ? { "entries/adapter": adapter_config_path(ctx.config) } : {}
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
};
|
|
127
|
+
if (env.command === "build" && ctx.adapter && ctx.adapter.includePaths) {
|
|
128
|
+
const extra = typeof ctx.adapter.includePaths === "function" ? ctx.adapter.includePaths({ config: ctx.config }) : ctx.adapter.includePaths;
|
|
129
|
+
Object.assign(conf.build.rollupOptions.input ?? {}, extra);
|
|
130
|
+
}
|
|
131
|
+
for (const [id, page] of Object.entries(manifest.pages)) {
|
|
132
|
+
;
|
|
133
|
+
conf.build.rollupOptions.input[`pages/${id}`] = `virtual:houdini/pages/${page.id}.jsx`;
|
|
134
|
+
}
|
|
135
|
+
return reactStreamingServerPath ? {
|
|
136
|
+
...conf,
|
|
137
|
+
resolve: { alias: { "react-streaming/server": reactStreamingServerPath } }
|
|
138
|
+
} : conf;
|
|
139
|
+
},
|
|
140
|
+
resolveId(id) {
|
|
141
|
+
if (id.includes("virtual:houdini")) {
|
|
142
|
+
return id.substring(id.indexOf("virtual:houdini"));
|
|
143
|
+
}
|
|
144
|
+
return null;
|
|
145
|
+
},
|
|
146
|
+
hotUpdate() {
|
|
147
|
+
cfCache = null;
|
|
148
|
+
},
|
|
149
|
+
async transform(code, filepath) {
|
|
150
|
+
filepath = path.posixify(filepath);
|
|
151
|
+
if (filepath.startsWith("/src/")) {
|
|
152
|
+
filepath = path.join(process.cwd(), filepath);
|
|
153
|
+
}
|
|
154
|
+
if (!ctx.config.includeFile(filepath)) {
|
|
155
|
+
return;
|
|
156
|
+
}
|
|
157
|
+
if (cfCache === null) {
|
|
158
|
+
try {
|
|
159
|
+
cfCache = ctx.db.all(
|
|
160
|
+
"SELECT type, field, fragment FROM component_fields"
|
|
161
|
+
);
|
|
162
|
+
} catch {
|
|
163
|
+
cfCache = [];
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
return transform_file(
|
|
167
|
+
{
|
|
168
|
+
config: ctx.config,
|
|
169
|
+
content: code,
|
|
170
|
+
filepath: path.posixify(filepath),
|
|
171
|
+
watch_file: this.addWatchFile.bind(this)
|
|
172
|
+
},
|
|
173
|
+
cfCache
|
|
174
|
+
);
|
|
175
|
+
},
|
|
176
|
+
async closeBundle() {
|
|
177
|
+
if (viteEnv.mode !== "production" || devServer || isSSRBuild) {
|
|
178
|
+
return;
|
|
179
|
+
}
|
|
180
|
+
if (!ctx.adapter || ctx.adapter?.disableServer) {
|
|
181
|
+
return;
|
|
182
|
+
}
|
|
183
|
+
const compiledAssetsDir = client_build_directory(ctx.config);
|
|
184
|
+
await build({
|
|
185
|
+
build: {
|
|
186
|
+
ssr: true,
|
|
187
|
+
outDir: path.join(compiledAssetsDir, "ssr"),
|
|
188
|
+
rollupOptions: {
|
|
189
|
+
output: {
|
|
190
|
+
assetFileNames: "assets/[name].js",
|
|
191
|
+
entryFileNames: "[name].js"
|
|
192
|
+
},
|
|
193
|
+
input: {
|
|
194
|
+
"entries/adapter": adapter_config_path(ctx.config)
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
});
|
|
199
|
+
},
|
|
200
|
+
async load(id) {
|
|
201
|
+
if (!id.startsWith("virtual:houdini")) {
|
|
202
|
+
return;
|
|
203
|
+
}
|
|
204
|
+
if (!manifest) {
|
|
205
|
+
return;
|
|
206
|
+
}
|
|
207
|
+
let [, which, arg] = id.split("/");
|
|
208
|
+
const parsedPath = arg ? path.parse(arg) : "";
|
|
209
|
+
const pageName = parsedPath ? parsedPath.name : "";
|
|
210
|
+
if (which === "pages") {
|
|
211
|
+
let page = manifest.pages[pageName];
|
|
212
|
+
if (!page) {
|
|
213
|
+
try {
|
|
214
|
+
manifest = await load_manifest({ config: ctx.config });
|
|
215
|
+
page = manifest.pages[pageName];
|
|
216
|
+
} catch {
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
if (!page) {
|
|
220
|
+
throw new Error("unknown page" + pageName);
|
|
221
|
+
}
|
|
222
|
+
const pendingQueries = page.queries.filter((query) => {
|
|
223
|
+
const pg = Object.values(manifest.page_queries).find((q) => q.name === query);
|
|
224
|
+
if (pg) {
|
|
225
|
+
return pg.loading;
|
|
226
|
+
}
|
|
227
|
+
const layout = Object.values(manifest.layout_queries).find(
|
|
228
|
+
(q) => q.name === query
|
|
229
|
+
);
|
|
230
|
+
return layout?.loading;
|
|
231
|
+
});
|
|
232
|
+
return `
|
|
233
|
+
import App from '$houdini/plugins/houdini-react/units/render/App'
|
|
234
|
+
import Component from '$houdini/plugins/houdini-react/units/entries/${pageName}.jsx'
|
|
235
|
+
import { hydrate_page } from '$houdini/plugins/houdini-react/runtime/hydration'
|
|
236
|
+
hydrate_page(App, Component, '${pageName}', ${JSON.stringify(pendingQueries)})
|
|
237
|
+
`;
|
|
238
|
+
}
|
|
239
|
+
if (which === "artifacts") {
|
|
240
|
+
return `
|
|
241
|
+
import artifact from '$houdini/artifacts/${pageName}'
|
|
242
|
+
import { register_artifact } from '$houdini/plugins/houdini-react/runtime/hydration'
|
|
243
|
+
register_artifact('${pageName}', artifact)
|
|
244
|
+
`;
|
|
245
|
+
}
|
|
246
|
+
if (which === "static-entry") {
|
|
247
|
+
return `
|
|
248
|
+
import App from '$houdini/plugins/houdini-react/units/render/App'
|
|
249
|
+
import manifest from '$houdini/plugins/houdini-react/runtime/manifest'
|
|
250
|
+
import { mount_static_app } from '$houdini/plugins/houdini-react/runtime/hydration'
|
|
251
|
+
mount_static_app(App, manifest)
|
|
252
|
+
`;
|
|
253
|
+
}
|
|
254
|
+
},
|
|
255
|
+
async configureServer(server) {
|
|
256
|
+
devServer = true;
|
|
257
|
+
const onUnhandledRejection = (err) => {
|
|
258
|
+
console.error("\n[houdini] dev server error (server still running):\n", err, "\n");
|
|
259
|
+
};
|
|
260
|
+
process.on("unhandledRejection", onUnhandledRejection);
|
|
261
|
+
server.httpServer?.once(
|
|
262
|
+
"close",
|
|
263
|
+
() => process.off("unhandledRejection", onUnhandledRejection)
|
|
264
|
+
);
|
|
265
|
+
server.httpServer?.once("listening", () => {
|
|
266
|
+
const addr = server.httpServer?.address();
|
|
267
|
+
if (addr && typeof addr === "object") {
|
|
268
|
+
process.env.HOUDINI_PORT = String(addr.port);
|
|
269
|
+
}
|
|
270
|
+
const root = ctx.config.root_dir;
|
|
271
|
+
const entry = ["+index.tsx", "+index.jsx"].map((f) => path.join(root, "src", f)).find((f) => existsSync(f));
|
|
272
|
+
if (entry) {
|
|
273
|
+
server.ssrLoadModule(entry).catch(() => {
|
|
274
|
+
});
|
|
275
|
+
}
|
|
276
|
+
});
|
|
277
|
+
server.middlewares.use(async (req, res, next) => {
|
|
278
|
+
if (!req.url) {
|
|
279
|
+
next();
|
|
280
|
+
return;
|
|
281
|
+
}
|
|
282
|
+
const url = req.url.split("?")[0];
|
|
283
|
+
if (url.startsWith("/@") || url.startsWith("/virtual:") || url.startsWith("/node_modules/") || /\.[a-z]+$/i.test(url)) {
|
|
284
|
+
next();
|
|
285
|
+
return;
|
|
286
|
+
}
|
|
287
|
+
const { default: router_manifest } = await server.ssrLoadModule(
|
|
288
|
+
path.join(plugin_dir(ctx.config, "houdini-react"), "runtime", "manifest.ts")
|
|
289
|
+
);
|
|
290
|
+
const { createServerAdapter } = await server.ssrLoadModule(
|
|
291
|
+
adapter_config_path(ctx.config)
|
|
292
|
+
);
|
|
293
|
+
const requestHeaders = new Headers();
|
|
294
|
+
for (const header of Object.entries(req.headers ?? {})) {
|
|
295
|
+
requestHeaders.set(header[0], header[1]);
|
|
296
|
+
}
|
|
297
|
+
const port = server.config.server.port ?? 5173;
|
|
298
|
+
const request = new Request(
|
|
299
|
+
`http://localhost:${port}` + req.url,
|
|
300
|
+
req.method === "POST" ? {
|
|
301
|
+
method: req.method,
|
|
302
|
+
headers: requestHeaders,
|
|
303
|
+
body: await getBody(req)
|
|
304
|
+
} : void 0
|
|
305
|
+
);
|
|
306
|
+
let documentPremable = `<script type="module" src="/@vite/client" async=""></script>`;
|
|
307
|
+
try {
|
|
308
|
+
const transformed = await server.transformIndexHtml(
|
|
309
|
+
req.url,
|
|
310
|
+
"<!DOCTYPE html><html><head></head><body></body></html>"
|
|
311
|
+
);
|
|
312
|
+
const headMatch = transformed.match(/<head>([\s\S]*?)<\/head>/);
|
|
313
|
+
if (headMatch?.[1]?.trim()) {
|
|
314
|
+
documentPremable = headMatch[1].trim();
|
|
315
|
+
}
|
|
316
|
+
} catch {
|
|
317
|
+
}
|
|
318
|
+
const cssLinkSet = /* @__PURE__ */ new Set();
|
|
319
|
+
for (const [url2] of server.moduleGraph.urlToModuleMap) {
|
|
320
|
+
const cleanUrl = url2.split("?")[0];
|
|
321
|
+
if (!cleanUrl.includes("node_modules") && cleanUrl.endsWith(".css") && !cleanUrl.endsWith(".module.css")) {
|
|
322
|
+
cssLinkSet.add(cleanUrl);
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
const cssLinks = [...cssLinkSet];
|
|
326
|
+
res.setHeader("Content-Type", "text/html; charset=utf-8");
|
|
327
|
+
try {
|
|
328
|
+
const result = await createServerAdapter({
|
|
329
|
+
production: false,
|
|
330
|
+
manifest: router_manifest,
|
|
331
|
+
assetPrefix: "/virtual:houdini",
|
|
332
|
+
pipe: res,
|
|
333
|
+
documentPremable,
|
|
334
|
+
cssLinks
|
|
335
|
+
})(request);
|
|
336
|
+
if (result && result.status === 404) {
|
|
337
|
+
return next();
|
|
338
|
+
}
|
|
339
|
+
if (result && typeof result !== "boolean") {
|
|
340
|
+
if (res.closed) {
|
|
341
|
+
return;
|
|
342
|
+
}
|
|
343
|
+
for (const header of result.headers ?? []) {
|
|
344
|
+
res.setHeader(header[0], header[1]);
|
|
345
|
+
}
|
|
346
|
+
if (result.status >= 300 && result.status < 400) {
|
|
347
|
+
res.writeHead(result.status, {
|
|
348
|
+
Location: result.headers.get("Location") ?? "",
|
|
349
|
+
...[...result.headers].reduce(
|
|
350
|
+
(headers, [key, value]) => ({
|
|
351
|
+
...headers,
|
|
352
|
+
[key]: value
|
|
353
|
+
}),
|
|
354
|
+
{}
|
|
355
|
+
)
|
|
356
|
+
});
|
|
357
|
+
} else {
|
|
358
|
+
res.write(await result.text());
|
|
359
|
+
}
|
|
360
|
+
res.end();
|
|
361
|
+
}
|
|
362
|
+
} catch (e) {
|
|
363
|
+
console.error(e);
|
|
364
|
+
res.end();
|
|
365
|
+
}
|
|
366
|
+
});
|
|
367
|
+
}
|
|
368
|
+
};
|
|
369
|
+
}
|
|
370
|
+
function getBody(request) {
|
|
371
|
+
return new Promise((resolve) => {
|
|
372
|
+
const bodyParts = [];
|
|
373
|
+
let body;
|
|
374
|
+
request.on("data", (chunk) => {
|
|
375
|
+
bodyParts.push(chunk);
|
|
376
|
+
}).on("end", () => {
|
|
377
|
+
body = Buffer.concat(bodyParts).toString();
|
|
378
|
+
resolve(body);
|
|
379
|
+
});
|
|
380
|
+
});
|
|
381
|
+
}
|
|
382
|
+
export {
|
|
383
|
+
index_default as default
|
|
384
|
+
};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { TransformPage } from 'houdini';
|
|
2
|
+
import type { SourceMapInput } from 'rollup';
|
|
3
|
+
export type ComponentFieldRow = {
|
|
4
|
+
type: string;
|
|
5
|
+
field: string;
|
|
6
|
+
fragment: string;
|
|
7
|
+
};
|
|
8
|
+
export declare function transform_file(page: TransformPage, cfRows: ComponentFieldRow[]): Promise<{
|
|
9
|
+
code: string;
|
|
10
|
+
map?: SourceMapInput;
|
|
11
|
+
}>;
|