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.
@@ -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
@@ -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