-
-
Notifications
You must be signed in to change notification settings - Fork 1.6k
Expand file tree
/
Copy pathplugin.ts
More file actions
69 lines (60 loc) · 2.8 KB
/
plugin.ts
File metadata and controls
69 lines (60 loc) · 2.8 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
import { pathToFileURL } from 'node:url'
import { basename, extname, join } from 'pathe'
import { NodeRequest, sendNodeResponse } from 'srvx/node'
import { joinURL } from 'ufo'
import { VITE_ENVIRONMENT_NAMES } from '../constants'
import { getServerOutputDirectory } from '../output-directory'
import { getBundlerOptions } from '../utils'
import type { Plugin } from 'vite'
export function previewServerPlugin(): Plugin {
return {
name: 'tanstack-start-core:preview-server',
configurePreviewServer: {
// Run last so platform plugins (Cloudflare, Vercel, etc.) can register their handlers first
order: 'post',
handler(server) {
// Return a function so Vite's internal middlewares (static files, etc.) handle requests first.
// Our SSR handler only processes requests that nothing else handled.
return () => {
// Cache the server build to avoid re-importing on every request
let serverBuild: any = null
server.middlewares.use(async (req, res, next) => {
try {
// Lazy load server build on first request
if (!serverBuild) {
// Derive output filename from input
const serverEnv =
server.config.environments[VITE_ENVIRONMENT_NAMES.server]
const serverInput =
getBundlerOptions(serverEnv?.build)?.input ?? 'server'
if (typeof serverInput !== 'string') {
throw new Error('Invalid server input. Expected a string.')
}
// Get basename without extension and add .js
const outputFilename = `${basename(serverInput, extname(serverInput))}.js`
const serverOutputDir = getServerOutputDirectory(server.config)
const serverEntryPath = join(serverOutputDir, outputFilename)
const imported = await import(
pathToFileURL(serverEntryPath).toString()
)
serverBuild = imported.default
}
// Prepend base path to request URL to match routing setup
req.url = joinURL(server.config.base, req.url ?? '/')
const webReq = new NodeRequest({ req, res })
const webRes: Response = await serverBuild.fetch(webReq)
// Temporary workaround
// Vite preview's compression middleware doesn't support flattened array headers that srvx sets
// Call writeHead() before srvx to avoid corruption
webRes.headers.forEach((value, key) => res.setHeader(key, value));
res.writeHead(webRes.status, webRes.statusText)
return sendNodeResponse(res, webRes)
} catch (error) {
next(error)
}
})
}
},
},
}
}