Skip to content

Commit

Permalink
fix: always generate an HTTP response pageContext.httpResponse (#1848)
Browse files Browse the repository at this point in the history
  • Loading branch information
brillout authored Sep 4, 2024
1 parent 57a2eba commit b45c154
Show file tree
Hide file tree
Showing 32 changed files with 175 additions and 264 deletions.
17 changes: 6 additions & 11 deletions boilerplates/boilerplate-react-ts/server/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ async function startServer() {

// Vike middleware. It should always be our last middleware (because it's a
// catch-all middleware superseding any middleware placed after it).
app.get('*', async (req, res, next) => {
app.get('*', async (req, res) => {
const pageContextInit = {
urlOriginal: req.originalUrl,
headersOriginal: req.headers
Expand All @@ -60,16 +60,11 @@ async function startServer() {
// Install error tracking here, see https://vike.dev/errors
}
const { httpResponse } = pageContext
if (!httpResponse) {
return next()
} else {
const { body, statusCode, headers, earlyHints } = httpResponse
if (res.writeEarlyHints) res.writeEarlyHints({ link: earlyHints.map((e) => e.earlyHintLink) })
headers.forEach(([name, value]) => res.setHeader(name, value))
res.status(statusCode)
// For HTTP streams use httpResponse.pipe() instead, see https://vike.dev/streaming
res.send(body)
}
if (res.writeEarlyHints) res.writeEarlyHints({ link: httpResponse.earlyHints.map((e) => e.earlyHintLink) })
httpResponse.headers.forEach(([name, value]) => res.setHeader(name, value))
res.status(httpResponse.statusCode)
// For HTTP streams use pageContext.httpResponse.pipe() instead, see https://vike.dev/streaming
res.send(httpResponse.body)
})

const port = process.env.PORT || 3000
Expand Down
17 changes: 6 additions & 11 deletions boilerplates/boilerplate-react/server/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ async function startServer() {

// Vike middleware. It should always be our last middleware (because it's a
// catch-all middleware superseding any middleware placed after it).
app.get('*', async (req, res, next) => {
app.get('*', async (req, res) => {
const pageContextInit = {
urlOriginal: req.originalUrl,
headersOriginal: req.headers
Expand All @@ -60,16 +60,11 @@ async function startServer() {
// Install error tracking here, see https://vike.dev/errors
}
const { httpResponse } = pageContext
if (!httpResponse) {
return next()
} else {
const { body, statusCode, headers, earlyHints } = httpResponse
if (res.writeEarlyHints) res.writeEarlyHints({ link: earlyHints.map((e) => e.earlyHintLink) })
headers.forEach(([name, value]) => res.setHeader(name, value))
res.status(statusCode)
// For HTTP streams use httpResponse.pipe() instead, see https://vike.dev/streaming
res.send(body)
}
if (res.writeEarlyHints) res.writeEarlyHints({ link: httpResponse.earlyHints.map((e) => e.earlyHintLink) })
httpResponse.headers.forEach(([name, value]) => res.setHeader(name, value))
res.status(httpResponse.statusCode)
// For HTTP streams use pageContext.httpResponse.pipe() instead, see https://vike.dev/streaming
res.send(httpResponse.body)
})

const port = process.env.PORT || 3000
Expand Down
17 changes: 6 additions & 11 deletions boilerplates/boilerplate-vue-ts/server/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ async function startServer() {

// Vike middleware. It should always be our last middleware (because it's a
// catch-all middleware superseding any middleware placed after it).
app.get('*', async (req, res, next) => {
app.get('*', async (req, res) => {
const pageContextInit = {
urlOriginal: req.originalUrl,
headersOriginal: req.headers
Expand All @@ -60,16 +60,11 @@ async function startServer() {
// Install error tracking here, see https://vike.dev/errors
}
const { httpResponse } = pageContext
if (!httpResponse) {
return next()
} else {
const { body, statusCode, headers, earlyHints } = httpResponse
if (res.writeEarlyHints) res.writeEarlyHints({ link: earlyHints.map((e) => e.earlyHintLink) })
headers.forEach(([name, value]) => res.setHeader(name, value))
res.status(statusCode)
// For HTTP streams use httpResponse.pipe() instead, see https://vike.dev/streaming
res.send(body)
}
if (res.writeEarlyHints) res.writeEarlyHints({ link: httpResponse.earlyHints.map((e) => e.earlyHintLink) })
httpResponse.headers.forEach(([name, value]) => res.setHeader(name, value))
res.status(httpResponse.statusCode)
// For HTTP streams use pageContext.httpResponse.pipe() instead, see https://vike.dev/streaming
res.send(httpResponse.body)
})

const port = process.env.PORT || 3000
Expand Down
17 changes: 6 additions & 11 deletions boilerplates/boilerplate-vue/server/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ async function startServer() {

// Vike middleware. It should always be our last middleware (because it's a
// catch-all middleware superseding any middleware placed after it).
app.get('*', async (req, res, next) => {
app.get('*', async (req, res) => {
const pageContextInit = {
urlOriginal: req.originalUrl,
headersOriginal: req.headers
Expand All @@ -60,16 +60,11 @@ async function startServer() {
// Install error tracking here, see https://vike.dev/errors
}
const { httpResponse } = pageContext
if (!httpResponse) {
return next()
} else {
const { body, statusCode, headers, earlyHints } = httpResponse
if (res.writeEarlyHints) res.writeEarlyHints({ link: earlyHints.map((e) => e.earlyHintLink) })
headers.forEach(([name, value]) => res.setHeader(name, value))
res.status(statusCode)
// For HTTP streams use httpResponse.pipe() instead, see https://vike.dev/streaming
res.send(body)
}
if (res.writeEarlyHints) res.writeEarlyHints({ link: httpResponse.earlyHints.map((e) => e.earlyHintLink) })
httpResponse.headers.forEach(([name, value]) => res.setHeader(name, value))
res.status(httpResponse.statusCode)
// For HTTP streams use pageContext.httpResponse.pipe() instead, see https://vike.dev/streaming
res.send(httpResponse.body)
})

const port = process.env.PORT || 3000
Expand Down
1 change: 0 additions & 1 deletion docs/components/JustAMiddleware.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ server.addMiddleware({
async handler(request) {
const pageContextInit = { urlOriginal: request.url }
const pageContext = await renderPage(pageContextInit)
if (!pageContext.httpResponse) return null
// `body` is the HTML of the page with a route matching pageContextInit.urlOriginal
const { body, statusCode, headers } = pageContext.httpResponse
const response = { body, statusCode, headers }
Expand Down
16 changes: 2 additions & 14 deletions docs/pages/errors/+Page.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -24,22 +24,10 @@ server.addMiddleware({

// If you use an error tracker (e.g. Sentry):
myErrorTracker.intercept(pageContext.errorWhileRendering)

// If you use a server middleware that handles errors:
if (!pageContext.httpResponse) {
// Don't throw if there is a pageContext.httpResponse, otherwise
// the error page won't be rendered.
throw pageContext.errorWhileRendering
}

}

// pageContext.httpResponse is missing if:
// - There is an error and you didn't define an error page.
// - Your error page has a bug and, therefore, couldn't be rendered.
if (!pageContext.httpResponse) return null

// The HTTP response of the page. This can be the error page.
// The HTTP response of the page.
// If pageContext.errorWhileRendering is defined then this is usually the error page.
return pageContext.httpResponse
}
})
Expand Down
2 changes: 1 addition & 1 deletion docs/pages/pageContext-json/+Page.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ Vike makes a `pageContext.json` request for a page if and only if one of the two
- The `pageContextInit` at <Link href="/renderPage">`renderPage()`</Link> contains a property that is included in <Link href="/passToClient">`passToClient`</Link>.
```js
// Vike server middleware
async (req, res, next) => {
async (req, res) => {
const pageContextInit = {
urlOriginal: req.originalUrl,
// If passToClient contains 'user' then Vike makes a pageContext.json request
Expand Down
8 changes: 1 addition & 7 deletions docs/pages/renderPage/+Page.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ async function startServer() {

// Vike middleware. It should always be our last middleware (because it's a
// catch-all middleware superseding any middleware placed after it).
app.get('*', async (req, res, next) => {
app.get('*', async (req, res) => {
const pageContextInit = {
// Required: the URL of the page
urlOriginal: req.originalUrl
Expand All @@ -75,7 +75,6 @@ async function startServer() {
}

const pageContext = await renderPage(pageContextInit)
if (pageContext.httpResponse === null) return next()

const { body, statusCode, headers } = pageContext.httpResponse
headers.forEach(([name, value]) => res.setHeader(name, value))
Expand All @@ -98,11 +97,6 @@ For HTML streams use `httpResponse.pipe()` instead of `pageContext.httpResponse.

Optionally, you can use `pageContext.httpResponse.earlyHints` for adding early hints (`103 Early Hint`), see <Link href="/preloading#early-hints" />.

The `pageContext.httpResponse` value is `null` if:
- An error occurred while rendering the page and no <Link text="error page" href="/error-page" noBreadcrumb /> is defined.
- An error occurred while rendering the error page.
- Vike skips certain URLs, such as `/favicon.ico` (because browsers automatically make favicon requests).

The `renderPage()` function doesn't depend on Node.js and you can use `renderPage()` (and therefore embed Vike) anywhere:
- Any server environment (Express.js, HatTip, Deno, Fastify, Vite's development server, Node.js's HTTP server, ...)
- Any deployment provider (AWS, Cloudflare Workers, Vercel, ...)
Expand Down
15 changes: 5 additions & 10 deletions docs/pages/streaming/+Page.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -60,11 +60,10 @@ Node.js platforms (Vercel, AWS EC2, AWS Lambda, ...):

import { renderPage } from 'vike/server'

app.get("*", async (req, res, next) => {
app.get("*", async (req, res) => {
const pageContextInit = { urlOriginal: req.url }
const pageContext = await renderPage(pageContextInit)
const { httpResponse } = pageContext
if (!httpResponse) return next()
// httpResponse.pipe() works with Node.js Streams as well as Web Streams
httpResponse.pipe(res)
})
Expand All @@ -85,14 +84,10 @@ async function handleFetchEvent(event) {
const pageContextInit = { urlOriginal: event.request.url }
const pageContext = await renderPage(pageContextInit)
const { httpResponse } = pageContext
if (!httpResponse) {
return null
} else {
// httpResponse.getReadableWebStream() only works with Web Streams
const readable = httpResponse.getReadableWebStream()
const { statusCode: status, headers } = httpResponse
return new Response(readable, { headers, status })
}
// httpResponse.getReadableWebStream() only works with Web Streams
const readable = httpResponse.getReadableWebStream()
const { statusCode: status, headers } = httpResponse
return new Response(readable, { headers, status })
}
```

Expand Down
14 changes: 4 additions & 10 deletions examples/auth/server/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ async function assets(app) {
}

function vike(app) {
app.get('*', async (req, res, next) => {
app.get('*', async (req, res) => {
const pageContextInit = {
urlOriginal: req.originalUrl,
headersOriginal: req.headers,
Expand All @@ -70,14 +70,8 @@ function vike(app) {
}
const pageContext = await renderPage(pageContextInit)
const { httpResponse } = pageContext
if (!httpResponse) {
return next()
} else {
const { statusCode, headers, earlyHints } = httpResponse
if (res.writeEarlyHints) res.writeEarlyHints({ link: earlyHints.map((e) => e.earlyHintLink) })
headers.forEach(([name, value]) => res.setHeader(name, value))
res.status(statusCode)
httpResponse.pipe(res)
}
httpResponse.headers.forEach(([name, value]) => res.setHeader(name, value))
res.status(httpResponse.statusCode)
httpResponse.pipe(res)
})
}
12 changes: 4 additions & 8 deletions examples/base-url-cdn/server/ssr.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,15 @@ import { renderPage } from 'vike/server'

const app = express()

app.get('*', async (req, res, next) => {
app.get('*', async (req, res) => {
const pageContextInit = {
urlOriginal: req.originalUrl
}
const pageContext = await renderPage(pageContextInit)
const { httpResponse } = pageContext
if (!httpResponse) {
return next()
} else {
const { body, statusCode, headers } = httpResponse
headers.forEach(([name, value]) => res.setHeader(name, value))
res.status(statusCode).send(body)
}
httpResponse.headers.forEach(([name, value]) => res.setHeader(name, value))
res.status(httpResponse.statusCode)
httpResponse.pipe(res)
})

app.listen(3000)
Expand Down
12 changes: 4 additions & 8 deletions examples/base-url-server/server/ssr.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,15 @@ import { baseServer } from '../base.js'

const { app, startApp } = createExpressApp({ base: baseServer, port: 3000 })

app.get('*', async (req, res, next) => {
app.get('*', async (req, res) => {
const pageContextInit = {
urlOriginal: req.originalUrl
}
const pageContext = await renderPage(pageContextInit)
const { httpResponse } = pageContext
if (!httpResponse) {
return next()
} else {
const { body, statusCode, headers } = httpResponse
headers.forEach(([name, value]) => res.setHeader(name, value))
res.status(statusCode).send(body)
}
httpResponse.headers.forEach(([name, value]) => res.setHeader(name, value))
res.status(httpResponse.statusCode)
httpResponse.pipe(res)
})

startApp()
Expand Down
13 changes: 4 additions & 9 deletions examples/cloudflare-workers-react-full/dev-server/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,22 +22,17 @@ async function startServer() {
).middlewares
app.use(viteDevMiddleware)

app.get('*', async (req, res, next) => {
app.get('*', async (req, res) => {
const pageContextInit = {
urlOriginal: req.originalUrl,
headersOriginal: req.headers,
fetch
}
const pageContext = await renderPage(pageContextInit)
const { httpResponse } = pageContext
if (!httpResponse) {
return next()
} else {
const { statusCode, headers } = httpResponse
headers.forEach(([name, value]) => res.setHeader(name, value))
res.status(statusCode)
httpResponse.pipe(res)
}
httpResponse.headers.forEach(([name, value]) => res.setHeader(name, value))
res.status(httpResponse.statusCode)
httpResponse.pipe(res)
})

const port = 3000
Expand Down
12 changes: 5 additions & 7 deletions examples/cloudflare-workers-react-full/worker/ssr.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,9 @@ async function handleSsr(url: string, headers: Headers) {
}
const pageContext = await renderPage(pageContextInit)
const { httpResponse } = pageContext
if (!httpResponse) {
return null
} else {
const { statusCode: status, headers } = httpResponse
const stream = httpResponse.getReadableWebStream()
return new Response(stream, { headers, status })
}
const stream = httpResponse.getReadableWebStream()
return new Response(stream, {
headers: httpResponse.headers,
status: httpResponse.statusCode
})
}
10 changes: 4 additions & 6 deletions examples/cloudflare-workers-react/worker/ssr.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,8 @@ async function handleSsr(url) {
}
const pageContext = await renderPage(pageContextInit)
const { httpResponse } = pageContext
if (!httpResponse) {
return null
} else {
const { body, statusCode: status, headers } = httpResponse
return new Response(body, { headers, status })
}
return new Response(httpResponse.body, {
headers: httpResponse.headers,
status: httpResponse.statusCode
})
}
10 changes: 3 additions & 7 deletions examples/cloudflare-workers-vue/worker/ssr.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,7 @@ async function handleSsr(url) {
}
const pageContext = await renderPage(pageContextInit)
const { httpResponse } = pageContext
if (!httpResponse) {
return null
} else {
const { readable, writable } = new TransformStream()
httpResponse.pipe(writable)
return new Response(readable)
}
const { readable, writable } = new TransformStream()
httpResponse.pipe(writable)
return new Response(readable)
}
12 changes: 4 additions & 8 deletions examples/path-aliases/server/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,19 +29,15 @@ async function startServer() {
app.use(viteDevMiddleware)
}

app.get('*', async (req, res, next) => {
app.get('*', async (req, res) => {
const pageContextInit = {
urlOriginal: req.originalUrl
}
const pageContext = await renderPage(pageContextInit)
const { httpResponse } = pageContext
if (!httpResponse) {
return next()
} else {
const { body, statusCode, headers } = httpResponse
headers.forEach(([name, value]) => res.setHeader(name, value))
res.status(statusCode).send(body)
}
httpResponse.headers.forEach(([name, value]) => res.setHeader(name, value))
res.status(httpResponse.statusCode)
httpResponse.pipe(res)
})

const port = process.env.PORT || 3000
Expand Down
Loading

0 comments on commit b45c154

Please sign in to comment.