Skip to content

Commit

Permalink
handle response headers
Browse files Browse the repository at this point in the history
  • Loading branch information
AlecAivazis committed Oct 1, 2023
1 parent b76ba68 commit a255bd1
Show file tree
Hide file tree
Showing 9 changed files with 277 additions and 287 deletions.
2 changes: 1 addition & 1 deletion e2e/react/src/components/SponsorInfo.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { graphql, useFragment, type SponsorInfo } from '$houdini'
import { graphql, type SponsorInfo, useFragment } from '$houdini'

type Props = {
sponsor: SponsorInfo
Expand Down
164 changes: 96 additions & 68 deletions packages/houdini-react/src/plugin/codegen/render.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,104 @@ export const renderToStream = render
`

const app_index = `
import { Router } from '$houdini/plugins/houdini-react/runtime'
import React from 'react'
import Shell from '../../../../../src/+index'
import { Router } from '$houdini'
export default (props) => <Shell><Router {...props} /></Shell>
export default (props) => (
<Shell>
<Router {...props} />
</Shell>
)
`

let renderer = `
import { Cache } from '$houdini/runtime/cache/cache'
import { serverAdapterFactory, _serverHandler } from '$houdini/runtime/router/server'
import { HoudiniClient } from '$houdini/runtime/client'
import { renderToStream } from 'react-streaming/server'
import React from 'react'
import { router_cache } from '../../runtime/routing'
// @ts-expect-error
import client from '../../../../../src/+client'
// @ts-expect-error
import App from './App'
export const on_render =
({ assetPrefix, pipe, production, documentPremable }) =>
async ({
url,
match,
session,
manifest,
}) => {
// instanitate a cache we can use for this request
const cache = new Cache({ disabled: false })
if (!match) {
return new Response('not found', { status: 404 })
}
const {
readable,
injectToStream,
pipe: pipeTo,
} = await renderToStream(
React.createElement(App, {
initialURL: url,
cache: cache,
session: session,
assetPrefix: assetPrefix,
manifest: manifest,
...router_cache()
}),
{
userAgent: 'Vite',
}
)
// add the initial scripts to the page
injectToStream(\`
<script>
window.__houdini__initial__cache__ = \${cache.serialize()};
window.__houdini__initial__session__ = \${JSON.stringify(session)};
</script>
\${documentPremable}
<!--
add a virtual module that hydrates the client and sets up the initial pending cache.
the dynamic extension is to support dev which sees the raw jsx, and production which sees the bundled asset
-->
<script type="module" src="\${assetPrefix}/pages/\${match.id}.\${production ? 'js' : 'jsx'}" async=""></script>
\`)
if (pipeTo && pipe) {
pipeTo(pipe)
return true
} else {
return new Response(readable)
}
}
export function reactServerHandler(options) {
return _serverHandler({
...options,
client,
on_render: on_render({ assetPrefix: options.assetPrefix, pipe: options.pipe, documentPremable: options.documentPremable }),
})
}
export default function createServerAdapter(options) {
return serverAdapterFactory({
client,
production: true,
...options,
on_render: on_render({ assetPrefix: options.assetPrefix }),
})
}
`

// and a file that adapters can import to get the local configuration
Expand All @@ -55,74 +148,9 @@ export default (props) => <Shell><Router {...props} /></Shell>
}
`

// we need a file in the local runtime that we can use to drive the server-side responses
const server_adapter = `
import React from 'react'
import { renderToStream } from 'react-streaming/server'
import { Cache } from '$houdini/runtime/cache/cache'
import { serverAdapterFactory } from '$houdini/runtime/router/server'
import { Router, router_cache } from '../../runtime'
import manifest from '../../runtime/manifest'
import App from './App'
import Shell from '../../../../../src/+index'
export default (options) => {
return serverAdapterFactory({
manifest,
...options,
on_render: async ({url, match, session, pipe , manifest }) => {
// instanitate a cache we can use for this request
const cache = new Cache({ disabled: false })
if (!match) {
return new Response('not found', { status: 404 })
}
const { readable, injectToStream, pipe: pipeTo } = await renderToStream(
React.createElement(App, {
initialURL: url,
cache: cache,
session: session,
assetPrefix: options.assetPrefix,
manifest: manifest,
...router_cache()
}),
{
userAgent: 'Vite',
}
)
// add the initial scripts to the page
injectToStream(\`
<script>
window.__houdini__initial__cache__ = \${cache.serialize()};
window.__houdini__initial__session__ = \${JSON.stringify(session)};
</script>
<!--
add a virtual module that hydrates the client and sets up the initial pending cache.
the dynamic extension is to support dev which sees the raw jsx, and production which sees the bundled asset
-->
<script type="module" src="\${options.assetPrefix}/pages/\${match.id}.\${options.production ? 'js' : 'jsx'}" async=""></script>
\`)
if (pipe && pipeTo) {
// pipe the response to the client
pipeTo(pipe)
} else {
// and deliver our Response while that's running.
return new Response(readable)
}
},
})
}
`

await Promise.all([
fs.writeFile(routerConventions.server_adapter_path(config), server_adapter),
fs.writeFile(routerConventions.adapter_config_path(config), adapter_config),
fs.writeFile(routerConventions.server_adapter_path(config), renderer),
fs.writeFile(routerConventions.app_component_path(config), app_index),
fs.writeFile(routerConventions.vite_render_path(config), vite_render),
])
Expand Down
Loading

0 comments on commit a255bd1

Please sign in to comment.