-
-
Notifications
You must be signed in to change notification settings - Fork 242
Expand file tree
/
Copy pathplugin.ts
More file actions
125 lines (122 loc) · 3.57 KB
/
plugin.ts
File metadata and controls
125 lines (122 loc) · 3.57 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
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
import assert from 'node:assert'
import { rmSync } from 'node:fs'
import path from 'node:path'
import { normalizePath, type Plugin, type Rollup } from 'vite'
export default function vitePluginRscBrowser(): Plugin[] {
let rscBundle: Rollup.OutputBundle
return [
{
name: 'rsc-browser',
config() {
return {
appType: 'spa',
environments: {
client: {
build: {
emptyOutDir: false,
},
},
// TODO: server build is not hashed
rsc: {
build: {
outDir: 'dist/client/__server',
rollupOptions: {
output: {
entryFileNames: '[name]-[hash].js',
},
},
},
keepProcessEnv: false,
resolve: {
noExternal: true,
},
optimizeDeps: {
esbuildOptions: {
platform: 'neutral',
},
},
},
},
rsc: {
serverHandler: false,
},
}
},
configResolved(config) {
// avoid globalThis.AsyncLocalStorage injection in browser mode
const plugin = config.plugins.find(
(p) => p.name === 'rsc:inject-async-local-storage',
)
delete plugin!.transform
},
buildApp: {
order: 'pre',
async handler() {
// clean up nested outDir
rmSync('./dist', { recursive: true, force: true })
},
},
configureServer(server) {
server.middlewares.use(async (req, res, next) => {
const url = new URL(req.url ?? '/', 'https://any.local')
if (url.pathname === '/@vite/invoke-rsc') {
const payload = JSON.parse(url.searchParams.get('data')!)
const result =
await server.environments['rsc']!.hot.handleInvoke(payload)
res.setHeader('Content-Type', 'application/json')
res.end(JSON.stringify(result))
return
}
next()
})
},
},
{
name: 'rsc-browser:load-rsc',
resolveId(source) {
if (source === 'virtual:vite-rsc-browser/load-rsc') {
if (this.environment.mode === 'dev') {
return this.resolve('/lib/dev-proxy')
}
return { id: source, external: true }
}
},
generateBundle(_options, bundle) {
if (this.environment.name === 'rsc') {
rscBundle = bundle
}
},
renderChunk(code, chunk) {
if (code.includes('virtual:vite-rsc-browser/load-rsc')) {
assert(this.environment.name === 'client')
const rscEntry = Object.values(rscBundle).find(
(v) => v.type === 'chunk' && v.isEntry,
)!
const config = this.environment.getTopLevelConfig()
const replacement = normalizeRelativePath(
path.relative(
path.join(
config.environments.client.build.outDir,
chunk.fileName,
'..',
),
path.join(
config.environments.rsc.build.outDir,
rscEntry.fileName,
),
),
)
code = code.replaceAll(
'virtual:vite-rsc-browser/load-rsc',
() => replacement,
)
return { code }
}
},
},
]
}
function normalizeRelativePath(s: string): string {
s = normalizePath(s)
return s[0] === '.' ? s : './' + s
}