vue-ssr-lite 0.0.3
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/README.md +154 -0
- package/apollo/SsrApolloAdapter.js +184 -0
- package/apollo/index.d.ts +50 -0
- package/bin/vue-ssr-lite.mjs +83 -0
- package/engine/.fuse_hidden0000002d00000001 +166 -0
- package/engine/SsrEngine.js +139 -0
- package/engine/SsrEngineHostPolicy.js +132 -0
- package/engine/SsrEngineHtml.js +166 -0
- package/engine/index.d.ts +86 -0
- package/engine/index.js +26 -0
- package/index.d.ts +104 -0
- package/index.js +40 -0
- package/package.json +91 -0
- package/runtime/SsrRuntimeApp.js +94 -0
- package/runtime/SsrRuntimeClient.js +72 -0
- package/runtime/SsrRuntimeContext.js +44 -0
- package/runtime/SsrRuntimeServer.js +63 -0
- package/runtime/client.d.ts +20 -0
- package/runtime/server.d.ts +26 -0
- package/server/SsrServer.js +600 -0
- package/server/index.d.ts +91 -0
- package/server/index.js +14 -0
- package/vite/SsrVitePlugin.js +218 -0
- package/vite/index.d.ts +37 -0
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
// SsrVitePlugin — the package's Vite integration (ships in version one).
|
|
2
|
+
//
|
|
3
|
+
// Owns everything a consumer would otherwise wire by hand: generated
|
|
4
|
+
// (virtual) client and server entries, HTML marker management, client-entry
|
|
5
|
+
// script injection, client/server build orchestration, and a serialized
|
|
6
|
+
// runtime manifest so the production server starts without build tooling.
|
|
7
|
+
//
|
|
8
|
+
// A normal consumer's entire integration is:
|
|
9
|
+
// vueSsrLite({ app: './src/MySsrApp.ts' })
|
|
10
|
+
// plus the package commands (vue-ssr-lite dev | build | start).
|
|
11
|
+
|
|
12
|
+
import { readFileSync, writeFileSync, mkdirSync, existsSync } from 'node:fs'
|
|
13
|
+
import { resolve, dirname } from 'node:path'
|
|
14
|
+
import { ensureSsrMarkers } from '../engine/SsrEngineHtml.js'
|
|
15
|
+
|
|
16
|
+
export const SSR_VIRTUAL_CLIENT = 'virtual:vue-ssr-lite/client'
|
|
17
|
+
export const SSR_VIRTUAL_SERVER = 'virtual:vue-ssr-lite/server'
|
|
18
|
+
const RUNTIME_MANIFEST = '.vue-ssr-lite.json'
|
|
19
|
+
|
|
20
|
+
const toPosix = (value) => value.replaceAll('\\', '/')
|
|
21
|
+
|
|
22
|
+
export const vueSsrLite = (pluginOptions = {}) => {
|
|
23
|
+
if (!pluginOptions.app) {
|
|
24
|
+
throw new Error(
|
|
25
|
+
'vue-ssr-lite/vite: the "app" option (path to the application definition module) is required.',
|
|
26
|
+
)
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
let root = process.cwd()
|
|
30
|
+
let isSsrBuild = false
|
|
31
|
+
let command = 'serve'
|
|
32
|
+
|
|
33
|
+
const template = pluginOptions.template || 'index.html'
|
|
34
|
+
const ssrName = pluginOptions.name || 'ssr'
|
|
35
|
+
const mountSelector = pluginOptions.mountSelector || '#app'
|
|
36
|
+
const spaApps = (pluginOptions.spa || []).map((app) => ({
|
|
37
|
+
type: 'spa',
|
|
38
|
+
hosts: [],
|
|
39
|
+
...app,
|
|
40
|
+
}))
|
|
41
|
+
|
|
42
|
+
const appModulePath = () => toPosix(resolve(root, pluginOptions.app))
|
|
43
|
+
|
|
44
|
+
const serverOptions = () => ({
|
|
45
|
+
apps: [
|
|
46
|
+
{
|
|
47
|
+
name: ssrName,
|
|
48
|
+
type: 'ssr',
|
|
49
|
+
template,
|
|
50
|
+
hosts: pluginOptions.hosts || [],
|
|
51
|
+
default: true,
|
|
52
|
+
},
|
|
53
|
+
...spaApps.map(({ name, template: spaTemplate, hosts, localhost }) => ({
|
|
54
|
+
name,
|
|
55
|
+
type: 'spa',
|
|
56
|
+
template: spaTemplate,
|
|
57
|
+
hosts: hosts || [],
|
|
58
|
+
...(localhost ? { localhost } : {}),
|
|
59
|
+
})),
|
|
60
|
+
],
|
|
61
|
+
serverEntry: SSR_VIRTUAL_SERVER,
|
|
62
|
+
bundlePath: 'dist/server/entry.mjs',
|
|
63
|
+
clientDir: 'dist/client',
|
|
64
|
+
serviceName: pluginOptions.serviceName,
|
|
65
|
+
globals: pluginOptions.globals,
|
|
66
|
+
headAttribute: pluginOptions.headAttribute,
|
|
67
|
+
defaultHead: pluginOptions.defaultHead,
|
|
68
|
+
cookieAllowlist: pluginOptions.cookieAllowlist,
|
|
69
|
+
cookieDenylist: pluginOptions.cookieDenylist,
|
|
70
|
+
renderTimeoutMs: pluginOptions.renderTimeoutMs,
|
|
71
|
+
port: pluginOptions.port,
|
|
72
|
+
})
|
|
73
|
+
|
|
74
|
+
const clientEntryCode = () =>
|
|
75
|
+
[
|
|
76
|
+
`import definition from '${appModulePath()}'`,
|
|
77
|
+
`import { hydrateSsrApp } from 'vue-ssr-lite/runtime/client'`,
|
|
78
|
+
`hydrateSsrApp(definition, ${JSON.stringify({
|
|
79
|
+
...(pluginOptions.globals || {}),
|
|
80
|
+
...(pluginOptions.headAttribute
|
|
81
|
+
? { headAttribute: pluginOptions.headAttribute }
|
|
82
|
+
: {}),
|
|
83
|
+
mountSelector,
|
|
84
|
+
})})`,
|
|
85
|
+
].join('\n')
|
|
86
|
+
|
|
87
|
+
const serverEntryCode = () =>
|
|
88
|
+
[
|
|
89
|
+
`import definition from '${appModulePath()}'`,
|
|
90
|
+
`import { createSsrRender, createSsrReadyProbe } from 'vue-ssr-lite/runtime/server'`,
|
|
91
|
+
`export const render = createSsrRender(definition)`,
|
|
92
|
+
`export const assertReady = createSsrReadyProbe(definition)`,
|
|
93
|
+
].join('\n')
|
|
94
|
+
|
|
95
|
+
return {
|
|
96
|
+
name: 'vue-ssr-lite',
|
|
97
|
+
enforce: 'pre',
|
|
98
|
+
|
|
99
|
+
api: {
|
|
100
|
+
getServerOptions: serverOptions,
|
|
101
|
+
},
|
|
102
|
+
|
|
103
|
+
config(config, env) {
|
|
104
|
+
command = env.command
|
|
105
|
+
isSsrBuild = Boolean(env.isSsrBuild)
|
|
106
|
+
const configRoot = resolve(config.root || process.cwd())
|
|
107
|
+
|
|
108
|
+
if (command !== 'build') return undefined
|
|
109
|
+
|
|
110
|
+
if (isSsrBuild) {
|
|
111
|
+
return {
|
|
112
|
+
build: {
|
|
113
|
+
outDir: 'dist/server',
|
|
114
|
+
emptyOutDir: true,
|
|
115
|
+
ssr: true,
|
|
116
|
+
rollupOptions: {
|
|
117
|
+
input: { entry: SSR_VIRTUAL_SERVER },
|
|
118
|
+
output: { entryFileNames: '[name].mjs' },
|
|
119
|
+
},
|
|
120
|
+
},
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
const input = { [ssrName]: resolve(configRoot, template) }
|
|
125
|
+
for (const spa of spaApps) {
|
|
126
|
+
input[spa.name] = resolve(configRoot, spa.template)
|
|
127
|
+
}
|
|
128
|
+
return {
|
|
129
|
+
build: {
|
|
130
|
+
outDir: 'dist/client',
|
|
131
|
+
emptyOutDir: true,
|
|
132
|
+
manifest: true,
|
|
133
|
+
rollupOptions: { input },
|
|
134
|
+
},
|
|
135
|
+
}
|
|
136
|
+
},
|
|
137
|
+
|
|
138
|
+
configResolved(config) {
|
|
139
|
+
root = config.root
|
|
140
|
+
},
|
|
141
|
+
|
|
142
|
+
resolveId(id) {
|
|
143
|
+
if (id === SSR_VIRTUAL_CLIENT || id === SSR_VIRTUAL_SERVER) return id
|
|
144
|
+
// The SSR build's rollup input references the virtual id as a path.
|
|
145
|
+
if (id.endsWith(SSR_VIRTUAL_SERVER)) return SSR_VIRTUAL_SERVER
|
|
146
|
+
return undefined
|
|
147
|
+
},
|
|
148
|
+
|
|
149
|
+
load(id) {
|
|
150
|
+
if (id === SSR_VIRTUAL_CLIENT) return clientEntryCode()
|
|
151
|
+
if (id === SSR_VIRTUAL_SERVER) return serverEntryCode()
|
|
152
|
+
return undefined
|
|
153
|
+
},
|
|
154
|
+
|
|
155
|
+
transformIndexHtml: {
|
|
156
|
+
order: 'pre',
|
|
157
|
+
handler(html, context) {
|
|
158
|
+
const filename = toPosix(context.filename || '')
|
|
159
|
+
if (!filename.endsWith(`/${template}`) && filename !== toPosix(resolve(root, template))) {
|
|
160
|
+
return html
|
|
161
|
+
}
|
|
162
|
+
let transformed = ensureSsrMarkers(html, { mountSelector })
|
|
163
|
+
if (!transformed.includes(SSR_VIRTUAL_CLIENT)) {
|
|
164
|
+
const src = context.server
|
|
165
|
+
? `/@id/${SSR_VIRTUAL_CLIENT}`
|
|
166
|
+
: SSR_VIRTUAL_CLIENT
|
|
167
|
+
transformed = transformed.replace(
|
|
168
|
+
/<\/body>/i,
|
|
169
|
+
`\t<script type="module" src="${src}"></script>\n</body>`,
|
|
170
|
+
)
|
|
171
|
+
}
|
|
172
|
+
return transformed
|
|
173
|
+
},
|
|
174
|
+
},
|
|
175
|
+
|
|
176
|
+
writeBundle() {
|
|
177
|
+
// Emit the runtime manifest with the client build so the production
|
|
178
|
+
// server (`vue-ssr-lite start`) needs no build tooling and no Vite.
|
|
179
|
+
if (command !== 'build' || isSsrBuild) return
|
|
180
|
+
const outDir = resolve(root, 'dist/client')
|
|
181
|
+
if (!existsSync(outDir)) mkdirSync(outDir, { recursive: true })
|
|
182
|
+
writeFileSync(
|
|
183
|
+
resolve(outDir, RUNTIME_MANIFEST),
|
|
184
|
+
JSON.stringify(serverOptions(), null, '\t'),
|
|
185
|
+
)
|
|
186
|
+
},
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
/**
|
|
191
|
+
* SSR dependency-inlining preset for the Apollo cluster. The @apollo/client
|
|
192
|
+
* subpaths expose CJS entries whose named exports Node cannot statically
|
|
193
|
+
* analyze; graphql without an exports map is a dual-package hazard. Consumers
|
|
194
|
+
* spread this into their Vite `ssr.noExternal` alongside their own UI
|
|
195
|
+
* libraries. (Knowledge ported from the audited ERP build configuration.)
|
|
196
|
+
*/
|
|
197
|
+
export const ssrApolloNoExternal = [
|
|
198
|
+
'@apollo/client',
|
|
199
|
+
'graphql',
|
|
200
|
+
'graphql-tag',
|
|
201
|
+
'optimism',
|
|
202
|
+
'ts-invariant',
|
|
203
|
+
'zen-observable-ts',
|
|
204
|
+
'zen-observable',
|
|
205
|
+
'symbol-observable',
|
|
206
|
+
/^@wry\//,
|
|
207
|
+
]
|
|
208
|
+
|
|
209
|
+
/** Read a template file and report whether it already carries SSR markers (debug aid). */
|
|
210
|
+
export const inspectSsrTemplate = (templatePath) => {
|
|
211
|
+
const html = readFileSync(resolve(templatePath), 'utf8')
|
|
212
|
+
return {
|
|
213
|
+
hasMarkers: html.includes('<!--app-html-->'),
|
|
214
|
+
html: ensureSsrMarkers(html),
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
export default vueSsrLite
|
package/vite/index.d.ts
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import type { Plugin } from 'vite'
|
|
2
|
+
|
|
3
|
+
export interface SsrSpaAppOptions {
|
|
4
|
+
name: string
|
|
5
|
+
template: string
|
|
6
|
+
hosts?: string[]
|
|
7
|
+
/** Serve this SPA for bare localhost hosts in development. */
|
|
8
|
+
localhost?: boolean
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export interface SsrVitePluginOptions {
|
|
12
|
+
/** Path to the module default-exporting defineSsrApp(...). Required. */
|
|
13
|
+
app: string
|
|
14
|
+
/** SSR HTML template (default 'index.html'). */
|
|
15
|
+
template?: string
|
|
16
|
+
/** Name of the SSR app for classification and build entry (default 'ssr'). */
|
|
17
|
+
name?: string
|
|
18
|
+
/** Host patterns served by SSR; empty means every unmatched host. */
|
|
19
|
+
hosts?: string[]
|
|
20
|
+
/** Additional SPA entries (builder/admin applications). */
|
|
21
|
+
spa?: SsrSpaAppOptions[]
|
|
22
|
+
mountSelector?: string
|
|
23
|
+
serviceName?: string
|
|
24
|
+
globals?: { configKey?: string; stateKey?: string }
|
|
25
|
+
headAttribute?: string
|
|
26
|
+
defaultHead?: string
|
|
27
|
+
cookieAllowlist?: string[]
|
|
28
|
+
cookieDenylist?: string[]
|
|
29
|
+
renderTimeoutMs?: number
|
|
30
|
+
port?: number
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export declare const SSR_VIRTUAL_CLIENT: string
|
|
34
|
+
export declare const SSR_VIRTUAL_SERVER: string
|
|
35
|
+
export declare const ssrApolloNoExternal: Array<string | RegExp>
|
|
36
|
+
export declare const vueSsrLite: (options: SsrVitePluginOptions) => Plugin
|
|
37
|
+
export default vueSsrLite
|