@platformatic/vite 2.71.1-alpha.0 → 3.0.0-alpha.1
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/config.d.ts +1 -1
- package/index.js +27 -446
- package/lib/schema.js +4 -2
- package/lib/stackable.js +406 -0
- package/package.json +8 -9
- package/schema.json +2 -2
package/config.d.ts
CHANGED
package/index.js
CHANGED
|
@@ -1,422 +1,16 @@
|
|
|
1
|
-
import
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
cleanBasePath,
|
|
6
|
-
createServerListener,
|
|
7
|
-
ensureTrailingSlash,
|
|
8
|
-
errors,
|
|
9
|
-
getServerUrl,
|
|
10
|
-
importFile,
|
|
11
|
-
resolvePackage,
|
|
12
|
-
schemaOptions
|
|
13
|
-
} from '@platformatic/basic'
|
|
14
|
-
import { ConfigManager } from '@platformatic/config'
|
|
15
|
-
import { NodeStackable } from '@platformatic/node'
|
|
16
|
-
import { features } from '@platformatic/utils'
|
|
17
|
-
import fastify from 'fastify'
|
|
18
|
-
import { existsSync } from 'node:fs'
|
|
19
|
-
import { readFile, writeFile } from 'node:fs/promises'
|
|
20
|
-
import { dirname, resolve } from 'node:path'
|
|
21
|
-
import { satisfies } from 'semver'
|
|
22
|
-
import { packageJson, schema } from './lib/schema.js'
|
|
1
|
+
import { transform as basicTransform, resolve, validationOptions } from '@platformatic/basic'
|
|
2
|
+
import { kMetadata, loadConfiguration as utilsLoadConfiguration } from '@platformatic/utils'
|
|
3
|
+
import { schema } from './lib/schema.js'
|
|
4
|
+
import { ViteSSRStackable, ViteStackable } from './lib/stackable.js'
|
|
23
5
|
|
|
24
|
-
|
|
6
|
+
/* c8 ignore next 5 */
|
|
7
|
+
export async function transform (config, schema, options) {
|
|
8
|
+
config = await basicTransform(config, schema, options)
|
|
25
9
|
|
|
26
|
-
|
|
27
|
-
#vite
|
|
28
|
-
#app
|
|
29
|
-
#server
|
|
30
|
-
#basePath
|
|
10
|
+
config.watch = { enabled: false }
|
|
31
11
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
async init () {
|
|
37
|
-
if (this.isProduction) {
|
|
38
|
-
return
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
this.#vite = dirname(resolvePackage(this.root, 'vite'))
|
|
42
|
-
const vitePackage = JSON.parse(await readFile(resolve(this.#vite, 'package.json'), 'utf-8'))
|
|
43
|
-
|
|
44
|
-
if (!satisfies(vitePackage.version, supportedVersions)) {
|
|
45
|
-
throw new errors.UnsupportedVersion('vite', vitePackage.version, supportedVersions)
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
async start ({ listen }) {
|
|
50
|
-
// Make this idempotent
|
|
51
|
-
if (this.url) {
|
|
52
|
-
return this.url
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
if (this.isProduction) {
|
|
56
|
-
await this.#startProduction(listen)
|
|
57
|
-
} else {
|
|
58
|
-
await this.#startDevelopment(listen)
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
await this._collectMetrics()
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
async stop () {
|
|
65
|
-
if (this.childManager) {
|
|
66
|
-
return this.stopCommand()
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
return this.#app.close()
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
async build () {
|
|
73
|
-
const config = this.configManager.current
|
|
74
|
-
const command = config.application.commands.build
|
|
75
|
-
const configFile = config.vite.configFile ? resolve(this.root, config.vite.configFile) : undefined
|
|
76
|
-
let basePath = config.application?.basePath
|
|
77
|
-
? ensureTrailingSlash(cleanBasePath(config.application?.basePath))
|
|
78
|
-
: undefined
|
|
79
|
-
let outDir
|
|
80
|
-
|
|
81
|
-
if (command) {
|
|
82
|
-
return this.buildWithCommand(command, basePath)
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
await this.init()
|
|
86
|
-
const { build } = await importFile(resolve(this.#vite, 'dist/node/index.js'))
|
|
87
|
-
|
|
88
|
-
try {
|
|
89
|
-
globalThis.platformatic.isBuilding = true
|
|
90
|
-
|
|
91
|
-
await build({
|
|
92
|
-
root: this.root,
|
|
93
|
-
base: basePath,
|
|
94
|
-
mode: 'production',
|
|
95
|
-
configFile,
|
|
96
|
-
logLevel: this.logger.level,
|
|
97
|
-
build: {
|
|
98
|
-
outDir: config.application.outputDirectory
|
|
99
|
-
},
|
|
100
|
-
plugins: [
|
|
101
|
-
{
|
|
102
|
-
name: 'platformatic-build',
|
|
103
|
-
configResolved: config => {
|
|
104
|
-
basePath = ensureTrailingSlash(cleanBasePath(config.base))
|
|
105
|
-
outDir = resolve(this.root, config.build.outDir)
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
]
|
|
109
|
-
})
|
|
110
|
-
} finally {
|
|
111
|
-
globalThis.platformatic.isBuilding = false
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
await writeFile(resolve(outDir, '.platformatic-build.json'), JSON.stringify({ basePath }), 'utf-8')
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
/* c8 ignore next 5 */
|
|
118
|
-
async getWatchConfig () {
|
|
119
|
-
return {
|
|
120
|
-
enabled: false
|
|
121
|
-
}
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
// This is only used in production mode
|
|
125
|
-
async inject (injectParams, onInject) {
|
|
126
|
-
const res = await this.#app.inject(injectParams, onInject)
|
|
127
|
-
|
|
128
|
-
/* c8 ignore next 3 */
|
|
129
|
-
if (onInject) {
|
|
130
|
-
return
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
// Since inject might be called from the main thread directly via ITC, let's clean it up
|
|
134
|
-
const { statusCode, headers, body, payload, rawPayload } = res
|
|
135
|
-
return { statusCode, headers, body, payload, rawPayload }
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
getMeta () {
|
|
139
|
-
const config = this.subprocessConfig ?? this.#app?.config
|
|
140
|
-
|
|
141
|
-
const composer = {
|
|
142
|
-
tcp: typeof this.url !== 'undefined',
|
|
143
|
-
url: this.url,
|
|
144
|
-
prefix: this.basePath ?? config?.base ?? this.#basePath,
|
|
145
|
-
wantsAbsoluteUrls: true,
|
|
146
|
-
needsRootTrailingSlash: true
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
return { composer }
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
_getVite () {
|
|
153
|
-
return this.#app
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
async #startDevelopment () {
|
|
157
|
-
const config = this.configManager.current
|
|
158
|
-
const command = this.configManager.current.application.commands.development
|
|
159
|
-
|
|
160
|
-
this.#basePath = config.application?.basePath
|
|
161
|
-
? ensureTrailingSlash(cleanBasePath(config.application?.basePath))
|
|
162
|
-
: undefined
|
|
163
|
-
|
|
164
|
-
this.registerGlobals({ basePath: this.#basePath })
|
|
165
|
-
|
|
166
|
-
if (command) {
|
|
167
|
-
return this.startWithCommand(command)
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
// Prepare options
|
|
171
|
-
const { hostname, port, https, cors } = this.serverConfig ?? {}
|
|
172
|
-
const configFile = config.vite.configFile ? resolve(this.root, config.vite.configFile) : undefined
|
|
173
|
-
|
|
174
|
-
const serverOptions = {
|
|
175
|
-
host: hostname || '127.0.0.1',
|
|
176
|
-
port: port || 0,
|
|
177
|
-
strictPort: false,
|
|
178
|
-
https,
|
|
179
|
-
cors,
|
|
180
|
-
hmr: true,
|
|
181
|
-
allowedHosts: ['.plt.local'],
|
|
182
|
-
fs: {
|
|
183
|
-
strict: config.vite.devServer.strict
|
|
184
|
-
}
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
// Require Vite
|
|
188
|
-
const serverPromise = createServerListener(
|
|
189
|
-
(this.isEntrypoint ? serverOptions?.port : undefined) ?? true,
|
|
190
|
-
(this.isEntrypoint ? serverOptions?.hostname : undefined) ?? true
|
|
191
|
-
)
|
|
192
|
-
const { createServer } = await importFile(resolve(this.#vite, 'dist/node/index.js'))
|
|
193
|
-
|
|
194
|
-
// Create the server and listen
|
|
195
|
-
this.#app = await createServer({
|
|
196
|
-
root: this.root,
|
|
197
|
-
base: this.#basePath,
|
|
198
|
-
mode: 'development',
|
|
199
|
-
configFile,
|
|
200
|
-
logLevel: this.logger.level,
|
|
201
|
-
clearScreen: false,
|
|
202
|
-
optimizeDeps: { force: false },
|
|
203
|
-
server: serverOptions
|
|
204
|
-
})
|
|
205
|
-
|
|
206
|
-
await this.#app.listen()
|
|
207
|
-
this.#server = await serverPromise
|
|
208
|
-
this.url = getServerUrl(this.#server)
|
|
209
|
-
}
|
|
210
|
-
|
|
211
|
-
async #startProduction (listen) {
|
|
212
|
-
const config = this.configManager.current
|
|
213
|
-
const command = this.configManager.current.application.commands.production
|
|
214
|
-
|
|
215
|
-
this.#basePath = config.application?.basePath
|
|
216
|
-
? ensureTrailingSlash(cleanBasePath(config.application?.basePath))
|
|
217
|
-
: undefined
|
|
218
|
-
|
|
219
|
-
this.registerGlobals({ basePath: this.#basePath })
|
|
220
|
-
|
|
221
|
-
if (command) {
|
|
222
|
-
return this.startWithCommand(command)
|
|
223
|
-
}
|
|
224
|
-
|
|
225
|
-
if (this.#app && listen) {
|
|
226
|
-
const serverOptions = this.serverConfig
|
|
227
|
-
const listenOptions = { host: serverOptions?.hostname || '127.0.0.1', port: serverOptions?.port || 0 }
|
|
228
|
-
|
|
229
|
-
if (this.isProduction && features.node.reusePort) {
|
|
230
|
-
listenOptions.reusePort = true
|
|
231
|
-
}
|
|
232
|
-
|
|
233
|
-
await this.#app.listen(listenOptions)
|
|
234
|
-
this.url = getServerUrl(this.#app.server)
|
|
235
|
-
return this.url
|
|
236
|
-
}
|
|
237
|
-
|
|
238
|
-
this.#app = fastify({ loggerInstance: this.logger })
|
|
239
|
-
|
|
240
|
-
const outputDirectory = resolve(this.root, config.application.outputDirectory)
|
|
241
|
-
this.verifyOutputDirectory(outputDirectory)
|
|
242
|
-
const buildInfoPath = resolve(outputDirectory, '.platformatic-build.json')
|
|
243
|
-
|
|
244
|
-
if (!this.#basePath && existsSync(buildInfoPath)) {
|
|
245
|
-
try {
|
|
246
|
-
const buildInfo = JSON.parse(await readFile(buildInfoPath, 'utf-8'))
|
|
247
|
-
this.#basePath = buildInfo.basePath
|
|
248
|
-
} catch (e) {
|
|
249
|
-
console.log(e)
|
|
250
|
-
}
|
|
251
|
-
}
|
|
252
|
-
|
|
253
|
-
await this.#app.register(fastifyStatic, {
|
|
254
|
-
root: outputDirectory,
|
|
255
|
-
prefix: this.#basePath,
|
|
256
|
-
prefixAvoidTrailingSlash: true,
|
|
257
|
-
schemaHide: true
|
|
258
|
-
})
|
|
259
|
-
|
|
260
|
-
await this.#app.ready()
|
|
261
|
-
}
|
|
262
|
-
}
|
|
263
|
-
|
|
264
|
-
export class ViteSSRStackable extends NodeStackable {
|
|
265
|
-
#basePath
|
|
266
|
-
|
|
267
|
-
constructor (options, root, configManager) {
|
|
268
|
-
super(options, root, configManager)
|
|
269
|
-
|
|
270
|
-
this.type = 'vite'
|
|
271
|
-
}
|
|
272
|
-
|
|
273
|
-
_getWantsAbsoluteUrls () {
|
|
274
|
-
return true
|
|
275
|
-
}
|
|
276
|
-
|
|
277
|
-
async init () {
|
|
278
|
-
const config = this.configManager.current
|
|
279
|
-
|
|
280
|
-
this.#basePath = config.application?.basePath
|
|
281
|
-
? ensureTrailingSlash(cleanBasePath(config.application?.basePath))
|
|
282
|
-
: undefined
|
|
283
|
-
|
|
284
|
-
this.registerGlobals({ basePath: this.#basePath })
|
|
285
|
-
}
|
|
286
|
-
|
|
287
|
-
async start ({ listen }) {
|
|
288
|
-
// Make this idempotent
|
|
289
|
-
/* c8 ignore next 3 */
|
|
290
|
-
if (this.url) {
|
|
291
|
-
return this.url
|
|
292
|
-
}
|
|
293
|
-
|
|
294
|
-
const config = this.configManager.current
|
|
295
|
-
const command = config.application.commands[this.isProduction ? 'production' : 'development']
|
|
296
|
-
|
|
297
|
-
if (command) {
|
|
298
|
-
return this.startWithCommand(command)
|
|
299
|
-
}
|
|
300
|
-
|
|
301
|
-
if (this.isProduction) {
|
|
302
|
-
const clientDirectory = config.vite.ssr.clientDirectory
|
|
303
|
-
const clientOutDir = resolve(this.root, clientDirectory, config.application.outputDirectory, clientDirectory)
|
|
304
|
-
|
|
305
|
-
this.verifyOutputDirectory(clientOutDir)
|
|
306
|
-
|
|
307
|
-
const buildInfoPath = resolve(clientOutDir, '.platformatic-build.json')
|
|
308
|
-
if (!this.#basePath && existsSync(buildInfoPath)) {
|
|
309
|
-
try {
|
|
310
|
-
const buildInfo = JSON.parse(await readFile(buildInfoPath, 'utf-8'))
|
|
311
|
-
this.#basePath = buildInfo.basePath
|
|
312
|
-
} catch (e) {
|
|
313
|
-
console.log(e)
|
|
314
|
-
}
|
|
315
|
-
}
|
|
316
|
-
}
|
|
317
|
-
|
|
318
|
-
await super.start({ listen })
|
|
319
|
-
await super._listen()
|
|
320
|
-
}
|
|
321
|
-
|
|
322
|
-
async build () {
|
|
323
|
-
const config = this.configManager.current
|
|
324
|
-
const command = config.application.commands.build
|
|
325
|
-
const configFile = config.vite.configFile ? resolve(this.root, config.vite.configFile) : undefined
|
|
326
|
-
let basePath = config.application?.basePath
|
|
327
|
-
? ensureTrailingSlash(cleanBasePath(config.application?.basePath))
|
|
328
|
-
: undefined
|
|
329
|
-
|
|
330
|
-
if (command) {
|
|
331
|
-
return this.buildWithCommand(command, basePath)
|
|
332
|
-
}
|
|
333
|
-
|
|
334
|
-
const clientDirectory = config.vite.ssr.clientDirectory
|
|
335
|
-
const serverDirectory = config.vite.ssr.serverDirectory
|
|
336
|
-
let clientOutDir = resolve(this.root, clientDirectory, config.application.outputDirectory, clientDirectory)
|
|
337
|
-
|
|
338
|
-
await this.init()
|
|
339
|
-
const vite = dirname(resolvePackage(this.root, 'vite'))
|
|
340
|
-
const { build } = await importFile(resolve(vite, 'dist/node/index.js'))
|
|
341
|
-
|
|
342
|
-
// Build the client
|
|
343
|
-
try {
|
|
344
|
-
globalThis.platformatic.isBuilding = true
|
|
345
|
-
|
|
346
|
-
await build({
|
|
347
|
-
root: resolve(this.root, clientDirectory),
|
|
348
|
-
base: basePath,
|
|
349
|
-
mode: 'production',
|
|
350
|
-
configFile,
|
|
351
|
-
logLevel: this.logger.level,
|
|
352
|
-
build: {
|
|
353
|
-
outDir: clientOutDir,
|
|
354
|
-
ssrManifest: true
|
|
355
|
-
},
|
|
356
|
-
plugins: [
|
|
357
|
-
{
|
|
358
|
-
name: 'platformatic-build',
|
|
359
|
-
configResolved: config => {
|
|
360
|
-
basePath = ensureTrailingSlash(cleanBasePath(config.base))
|
|
361
|
-
clientOutDir = resolve(this.root, clientDirectory, config.build.outDir)
|
|
362
|
-
}
|
|
363
|
-
}
|
|
364
|
-
]
|
|
365
|
-
})
|
|
366
|
-
} finally {
|
|
367
|
-
globalThis.platformatic.isBuilding = false
|
|
368
|
-
}
|
|
369
|
-
|
|
370
|
-
await writeFile(resolve(clientOutDir, '.platformatic-build.json'), JSON.stringify({ basePath }), 'utf-8')
|
|
371
|
-
|
|
372
|
-
// Build the server
|
|
373
|
-
await build({
|
|
374
|
-
root: this.root,
|
|
375
|
-
base: basePath,
|
|
376
|
-
mode: 'production',
|
|
377
|
-
configFile,
|
|
378
|
-
logLevel: this.logger.level,
|
|
379
|
-
build: {
|
|
380
|
-
outDir: resolve(this.root, clientDirectory, config.application.outputDirectory, serverDirectory),
|
|
381
|
-
ssr: resolve(this.root, clientDirectory, 'index.js')
|
|
382
|
-
}
|
|
383
|
-
})
|
|
384
|
-
}
|
|
385
|
-
|
|
386
|
-
getMeta () {
|
|
387
|
-
const vite = this._getApplication()?.vite
|
|
388
|
-
const config = vite?.devServer?.config ?? vite?.config.vite
|
|
389
|
-
const applicationBasePath = config?.base
|
|
390
|
-
|
|
391
|
-
const composer = {
|
|
392
|
-
tcp: typeof this.url !== 'undefined',
|
|
393
|
-
url: this.url,
|
|
394
|
-
prefix: this.basePath ?? applicationBasePath ?? this.#basePath,
|
|
395
|
-
wantsAbsoluteUrls: true,
|
|
396
|
-
needsRootTrailingSlash: true
|
|
397
|
-
}
|
|
398
|
-
|
|
399
|
-
return { composer }
|
|
400
|
-
}
|
|
401
|
-
|
|
402
|
-
_findEntrypoint () {
|
|
403
|
-
const config = this.configManager.current.vite ?? {}
|
|
404
|
-
return resolve(this.root, config.ssr.entrypoint)
|
|
405
|
-
}
|
|
406
|
-
}
|
|
407
|
-
|
|
408
|
-
/* c8 ignore next 9 */
|
|
409
|
-
export function transformConfig () {
|
|
410
|
-
if (this.current.watch === undefined) {
|
|
411
|
-
this.current.watch = { enabled: false }
|
|
412
|
-
}
|
|
413
|
-
|
|
414
|
-
if (typeof this.current.watch !== 'object') {
|
|
415
|
-
this.current.watch = { enabled: this.current.watch || false }
|
|
416
|
-
}
|
|
417
|
-
|
|
418
|
-
if (this.current.vite.ssr === true) {
|
|
419
|
-
this.current.vite.ssr = {
|
|
12
|
+
if (config.vite.ssr === true) {
|
|
13
|
+
config.vite.ssr = {
|
|
420
14
|
enabled: true,
|
|
421
15
|
entrypoint: 'server.js',
|
|
422
16
|
clientDirectory: 'client',
|
|
@@ -424,41 +18,28 @@ export function transformConfig () {
|
|
|
424
18
|
}
|
|
425
19
|
}
|
|
426
20
|
|
|
427
|
-
return
|
|
21
|
+
return config
|
|
428
22
|
}
|
|
429
23
|
|
|
430
|
-
export async function
|
|
431
|
-
const root =
|
|
24
|
+
export async function loadConfiguration (configOrRoot, sourceOrConfig, context) {
|
|
25
|
+
const { root, source } = await resolve(configOrRoot, sourceOrConfig, 'application')
|
|
432
26
|
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
27
|
+
return utilsLoadConfiguration(source, context?.schema ?? schema, {
|
|
28
|
+
validationOptions,
|
|
29
|
+
transform,
|
|
30
|
+
replaceEnv: true,
|
|
31
|
+
root,
|
|
32
|
+
...context
|
|
439
33
|
})
|
|
440
|
-
await configManager.parseAndValidate()
|
|
441
|
-
|
|
442
|
-
// When in SSR mode, we use ViteSSRStackable, which is a subclass of @platformatic/node
|
|
443
|
-
const viteConfig = configManager.current.vite ?? {}
|
|
444
|
-
|
|
445
|
-
if (viteConfig.ssr?.enabled) {
|
|
446
|
-
return new ViteSSRStackable(opts, root, configManager)
|
|
447
|
-
}
|
|
448
|
-
|
|
449
|
-
return new ViteStackable(opts, root, configManager)
|
|
450
34
|
}
|
|
451
35
|
|
|
452
|
-
export
|
|
36
|
+
export async function create (configOrRoot, sourceOrConfig, context) {
|
|
37
|
+
const config = await loadConfiguration(configOrRoot, sourceOrConfig, context)
|
|
453
38
|
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
schemaOptions,
|
|
458
|
-
transformConfig
|
|
459
|
-
},
|
|
460
|
-
buildStackable,
|
|
461
|
-
schema,
|
|
462
|
-
version: packageJson.version,
|
|
463
|
-
modulesToLoad: []
|
|
39
|
+
// When in SSR mode, we use ViteSSRStackable, which is a subclass of @platformatic/node
|
|
40
|
+
const Stackable = config.vite?.ssr?.enabled ? ViteSSRStackable : ViteStackable
|
|
41
|
+
return new Stackable(config[kMetadata].root, config, context)
|
|
464
42
|
}
|
|
43
|
+
|
|
44
|
+
export { packageJson, schema, schemaComponents, version } from './lib/schema.js'
|
|
45
|
+
export * from './lib/stackable.js'
|
package/lib/schema.js
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import { schemaComponents as basicSchemaComponents } from '@platformatic/basic'
|
|
2
2
|
import { schemaComponents as utilsSchemaComponents } from '@platformatic/utils'
|
|
3
3
|
import { readFileSync } from 'node:fs'
|
|
4
|
+
import { resolve } from 'node:path'
|
|
4
5
|
|
|
5
|
-
export const packageJson = JSON.parse(readFileSync(
|
|
6
|
+
export const packageJson = JSON.parse(readFileSync(resolve(import.meta.dirname, '../package.json'), 'utf8'))
|
|
7
|
+
export const version = packageJson.version
|
|
6
8
|
|
|
7
9
|
const vite = {
|
|
8
10
|
type: 'object',
|
|
@@ -50,7 +52,7 @@ export const schemaComponents = { vite }
|
|
|
50
52
|
export const schema = {
|
|
51
53
|
$id: `https://schemas.platformatic.dev/@platformatic/vite/${packageJson.version}.json`,
|
|
52
54
|
$schema: 'http://json-schema.org/draft-07/schema#',
|
|
53
|
-
title: 'Platformatic Vite
|
|
55
|
+
title: 'Platformatic Vite Config',
|
|
54
56
|
type: 'object',
|
|
55
57
|
properties: {
|
|
56
58
|
$schema: {
|
package/lib/stackable.js
ADDED
|
@@ -0,0 +1,406 @@
|
|
|
1
|
+
import fastifyStatic from '@fastify/static'
|
|
2
|
+
import {
|
|
3
|
+
BaseStackable,
|
|
4
|
+
cleanBasePath,
|
|
5
|
+
createServerListener,
|
|
6
|
+
ensureTrailingSlash,
|
|
7
|
+
errors,
|
|
8
|
+
getServerUrl,
|
|
9
|
+
importFile,
|
|
10
|
+
resolvePackage
|
|
11
|
+
} from '@platformatic/basic'
|
|
12
|
+
import { NodeStackable } from '@platformatic/node'
|
|
13
|
+
import { features } from '@platformatic/utils'
|
|
14
|
+
import fastify from 'fastify'
|
|
15
|
+
import { existsSync } from 'node:fs'
|
|
16
|
+
import { readFile, writeFile } from 'node:fs/promises'
|
|
17
|
+
import { dirname, resolve } from 'node:path'
|
|
18
|
+
import { satisfies } from 'semver'
|
|
19
|
+
import { version } from './schema.js'
|
|
20
|
+
|
|
21
|
+
const supportedVersions = '^5.0.0'
|
|
22
|
+
|
|
23
|
+
export class ViteStackable extends BaseStackable {
|
|
24
|
+
#vite
|
|
25
|
+
#app
|
|
26
|
+
#server
|
|
27
|
+
#basePath
|
|
28
|
+
|
|
29
|
+
constructor (root, config, context) {
|
|
30
|
+
super('vite', version, root, config, context)
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
async init () {
|
|
34
|
+
await super.init()
|
|
35
|
+
|
|
36
|
+
if (this.isProduction) {
|
|
37
|
+
return
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
this.#vite = dirname(resolvePackage(this.root, 'vite'))
|
|
41
|
+
const vitePackage = JSON.parse(await readFile(resolve(this.#vite, 'package.json'), 'utf-8'))
|
|
42
|
+
|
|
43
|
+
if (!satisfies(vitePackage.version, supportedVersions)) {
|
|
44
|
+
throw new errors.UnsupportedVersion('vite', vitePackage.version, supportedVersions)
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
async start ({ listen }) {
|
|
49
|
+
// Make this idempotent
|
|
50
|
+
if (this.url) {
|
|
51
|
+
return this.url
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
if (this.isProduction) {
|
|
55
|
+
await this.#startProduction(listen)
|
|
56
|
+
} else {
|
|
57
|
+
await this.#startDevelopment(listen)
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
await this._collectMetrics()
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
async stop () {
|
|
64
|
+
if (this.childManager) {
|
|
65
|
+
return this.stopCommand()
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
return this.#app.close()
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
async build () {
|
|
72
|
+
const config = this.config
|
|
73
|
+
const command = config.application.commands.build
|
|
74
|
+
const configFile = config.vite.configFile ? resolve(this.root, config.vite.configFile) : undefined
|
|
75
|
+
let basePath = config.application?.basePath
|
|
76
|
+
? ensureTrailingSlash(cleanBasePath(config.application?.basePath))
|
|
77
|
+
: undefined
|
|
78
|
+
let outDir
|
|
79
|
+
|
|
80
|
+
if (command) {
|
|
81
|
+
return this.buildWithCommand(command, basePath)
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
await this.init()
|
|
85
|
+
const { build } = await importFile(resolve(this.#vite, 'dist/node/index.js'))
|
|
86
|
+
|
|
87
|
+
try {
|
|
88
|
+
globalThis.platformatic.isBuilding = true
|
|
89
|
+
|
|
90
|
+
await build({
|
|
91
|
+
root: this.root,
|
|
92
|
+
base: basePath,
|
|
93
|
+
mode: 'production',
|
|
94
|
+
configFile,
|
|
95
|
+
logLevel: this.logger.level,
|
|
96
|
+
build: {
|
|
97
|
+
outDir: config.application.outputDirectory
|
|
98
|
+
},
|
|
99
|
+
plugins: [
|
|
100
|
+
{
|
|
101
|
+
name: 'platformatic-build',
|
|
102
|
+
configResolved: config => {
|
|
103
|
+
basePath = ensureTrailingSlash(cleanBasePath(config.base))
|
|
104
|
+
outDir = resolve(this.root, config.build.outDir)
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
]
|
|
108
|
+
})
|
|
109
|
+
} finally {
|
|
110
|
+
globalThis.platformatic.isBuilding = false
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
await writeFile(resolve(outDir, '.platformatic-build.json'), JSON.stringify({ basePath }), 'utf-8')
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/* c8 ignore next 5 */
|
|
117
|
+
async getWatchConfig () {
|
|
118
|
+
return {
|
|
119
|
+
enabled: false
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
// This is only used in production mode
|
|
124
|
+
async inject (injectParams, onInject) {
|
|
125
|
+
const res = await this.#app.inject(injectParams, onInject)
|
|
126
|
+
|
|
127
|
+
/* c8 ignore next 3 */
|
|
128
|
+
if (onInject) {
|
|
129
|
+
return
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
// Since inject might be called from the main thread directly via ITC, let's clean it up
|
|
133
|
+
const { statusCode, headers, body, payload, rawPayload } = res
|
|
134
|
+
return { statusCode, headers, body, payload, rawPayload }
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
getMeta () {
|
|
138
|
+
const config = this.subprocessConfig ?? this.#app?.config
|
|
139
|
+
|
|
140
|
+
const composer = {
|
|
141
|
+
tcp: typeof this.url !== 'undefined',
|
|
142
|
+
url: this.url,
|
|
143
|
+
prefix: this.basePath ?? config?.base ?? this.#basePath,
|
|
144
|
+
wantsAbsoluteUrls: true,
|
|
145
|
+
needsRootTrailingSlash: true
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
return { composer }
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
_getVite () {
|
|
152
|
+
return this.#app
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
async #startDevelopment () {
|
|
156
|
+
const config = this.config
|
|
157
|
+
const command = this.config.application.commands.development
|
|
158
|
+
|
|
159
|
+
this.#basePath = config.application?.basePath
|
|
160
|
+
? ensureTrailingSlash(cleanBasePath(config.application?.basePath))
|
|
161
|
+
: undefined
|
|
162
|
+
|
|
163
|
+
this.registerGlobals({ basePath: this.#basePath })
|
|
164
|
+
|
|
165
|
+
if (command) {
|
|
166
|
+
return this.startWithCommand(command)
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
// Prepare options
|
|
170
|
+
const { hostname, port, https, cors } = this.serverConfig ?? {}
|
|
171
|
+
const configFile = config.vite.configFile ? resolve(this.root, config.vite.configFile) : undefined
|
|
172
|
+
|
|
173
|
+
const serverOptions = {
|
|
174
|
+
host: hostname || '127.0.0.1',
|
|
175
|
+
port: port || 0,
|
|
176
|
+
strictPort: false,
|
|
177
|
+
https,
|
|
178
|
+
cors,
|
|
179
|
+
hmr: true,
|
|
180
|
+
allowedHosts: ['.plt.local'],
|
|
181
|
+
fs: {
|
|
182
|
+
strict: config.vite.devServer.strict
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
// Require Vite
|
|
187
|
+
const serverPromise = createServerListener(
|
|
188
|
+
(this.isEntrypoint ? serverOptions?.port : undefined) ?? true,
|
|
189
|
+
(this.isEntrypoint ? serverOptions?.hostname : undefined) ?? true
|
|
190
|
+
)
|
|
191
|
+
const { createServer } = await importFile(resolve(this.#vite, 'dist/node/index.js'))
|
|
192
|
+
|
|
193
|
+
// Create the server and listen
|
|
194
|
+
this.#app = await createServer({
|
|
195
|
+
root: this.root,
|
|
196
|
+
base: this.#basePath,
|
|
197
|
+
mode: 'development',
|
|
198
|
+
configFile,
|
|
199
|
+
logLevel: this.logger.level,
|
|
200
|
+
clearScreen: false,
|
|
201
|
+
optimizeDeps: { force: false },
|
|
202
|
+
server: serverOptions
|
|
203
|
+
})
|
|
204
|
+
|
|
205
|
+
await this.#app.listen()
|
|
206
|
+
this.#server = await serverPromise
|
|
207
|
+
this.url = getServerUrl(this.#server)
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
async #startProduction (listen) {
|
|
211
|
+
const config = this.config
|
|
212
|
+
const command = this.config.application.commands.production
|
|
213
|
+
|
|
214
|
+
this.#basePath = config.application?.basePath
|
|
215
|
+
? ensureTrailingSlash(cleanBasePath(config.application?.basePath))
|
|
216
|
+
: undefined
|
|
217
|
+
|
|
218
|
+
this.registerGlobals({ basePath: this.#basePath })
|
|
219
|
+
|
|
220
|
+
if (command) {
|
|
221
|
+
return this.startWithCommand(command)
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
if (this.#app && listen) {
|
|
225
|
+
const serverOptions = this.serverConfig
|
|
226
|
+
const listenOptions = { host: serverOptions?.hostname || '127.0.0.1', port: serverOptions?.port || 0 }
|
|
227
|
+
|
|
228
|
+
if (this.isProduction && features.node.reusePort) {
|
|
229
|
+
listenOptions.reusePort = true
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
await this.#app.listen(listenOptions)
|
|
233
|
+
this.url = getServerUrl(this.#app.server)
|
|
234
|
+
return this.url
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
this.#app = fastify({ loggerInstance: this.logger })
|
|
238
|
+
|
|
239
|
+
const outputDirectory = resolve(this.root, config.application.outputDirectory)
|
|
240
|
+
this.verifyOutputDirectory(outputDirectory)
|
|
241
|
+
const buildInfoPath = resolve(outputDirectory, '.platformatic-build.json')
|
|
242
|
+
|
|
243
|
+
if (!this.#basePath && existsSync(buildInfoPath)) {
|
|
244
|
+
try {
|
|
245
|
+
const buildInfo = JSON.parse(await readFile(buildInfoPath, 'utf-8'))
|
|
246
|
+
this.#basePath = buildInfo.basePath
|
|
247
|
+
} catch (e) {
|
|
248
|
+
console.log(e)
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
await this.#app.register(fastifyStatic, {
|
|
253
|
+
root: outputDirectory,
|
|
254
|
+
prefix: this.#basePath,
|
|
255
|
+
prefixAvoidTrailingSlash: true,
|
|
256
|
+
schemaHide: true
|
|
257
|
+
})
|
|
258
|
+
|
|
259
|
+
await this.#app.ready()
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
export class ViteSSRStackable extends NodeStackable {
|
|
264
|
+
#basePath
|
|
265
|
+
|
|
266
|
+
constructor (root, config, context) {
|
|
267
|
+
super(root, config, context)
|
|
268
|
+
this.type = 'vite'
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
_getWantsAbsoluteUrls () {
|
|
272
|
+
return true
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
async init () {
|
|
276
|
+
await super.init()
|
|
277
|
+
|
|
278
|
+
const config = this.config
|
|
279
|
+
|
|
280
|
+
this.#basePath = config.application?.basePath
|
|
281
|
+
? ensureTrailingSlash(cleanBasePath(config.application?.basePath))
|
|
282
|
+
: undefined
|
|
283
|
+
|
|
284
|
+
this.registerGlobals({ basePath: this.#basePath })
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
async start ({ listen }) {
|
|
288
|
+
// Make this idempotent
|
|
289
|
+
/* c8 ignore next 3 */
|
|
290
|
+
if (this.url) {
|
|
291
|
+
return this.url
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
const config = this.config
|
|
295
|
+
const command = config.application.commands[this.isProduction ? 'production' : 'development']
|
|
296
|
+
|
|
297
|
+
if (command) {
|
|
298
|
+
return this.startWithCommand(command)
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
if (this.isProduction) {
|
|
302
|
+
const clientDirectory = config.vite.ssr.clientDirectory
|
|
303
|
+
const clientOutDir = resolve(this.root, clientDirectory, config.application.outputDirectory, clientDirectory)
|
|
304
|
+
|
|
305
|
+
this.verifyOutputDirectory(clientOutDir)
|
|
306
|
+
|
|
307
|
+
const buildInfoPath = resolve(clientOutDir, '.platformatic-build.json')
|
|
308
|
+
if (!this.#basePath && existsSync(buildInfoPath)) {
|
|
309
|
+
try {
|
|
310
|
+
const buildInfo = JSON.parse(await readFile(buildInfoPath, 'utf-8'))
|
|
311
|
+
this.#basePath = buildInfo.basePath
|
|
312
|
+
} catch (e) {
|
|
313
|
+
console.log(e)
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
await super.start({ listen })
|
|
319
|
+
await super._listen()
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
async build () {
|
|
323
|
+
const config = this.config
|
|
324
|
+
const command = config.application.commands.build
|
|
325
|
+
const configFile = config.vite.configFile ? resolve(this.root, config.vite.configFile) : undefined
|
|
326
|
+
let basePath = config.application?.basePath
|
|
327
|
+
? ensureTrailingSlash(cleanBasePath(config.application?.basePath))
|
|
328
|
+
: undefined
|
|
329
|
+
|
|
330
|
+
if (command) {
|
|
331
|
+
return this.buildWithCommand(command, basePath)
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
const clientDirectory = config.vite.ssr.clientDirectory
|
|
335
|
+
const serverDirectory = config.vite.ssr.serverDirectory
|
|
336
|
+
let clientOutDir = resolve(this.root, clientDirectory, config.application.outputDirectory, clientDirectory)
|
|
337
|
+
|
|
338
|
+
await this.init()
|
|
339
|
+
const vite = dirname(resolvePackage(this.root, 'vite'))
|
|
340
|
+
const { build } = await importFile(resolve(vite, 'dist/node/index.js'))
|
|
341
|
+
|
|
342
|
+
// Build the client
|
|
343
|
+
try {
|
|
344
|
+
globalThis.platformatic.isBuilding = true
|
|
345
|
+
|
|
346
|
+
await build({
|
|
347
|
+
root: resolve(this.root, clientDirectory),
|
|
348
|
+
base: basePath,
|
|
349
|
+
mode: 'production',
|
|
350
|
+
configFile,
|
|
351
|
+
logLevel: this.logger.level,
|
|
352
|
+
build: {
|
|
353
|
+
outDir: clientOutDir,
|
|
354
|
+
ssrManifest: true
|
|
355
|
+
},
|
|
356
|
+
plugins: [
|
|
357
|
+
{
|
|
358
|
+
name: 'platformatic-build',
|
|
359
|
+
configResolved: config => {
|
|
360
|
+
basePath = ensureTrailingSlash(cleanBasePath(config.base))
|
|
361
|
+
clientOutDir = resolve(this.root, clientDirectory, config.build.outDir)
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
]
|
|
365
|
+
})
|
|
366
|
+
} finally {
|
|
367
|
+
globalThis.platformatic.isBuilding = false
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
await writeFile(resolve(clientOutDir, '.platformatic-build.json'), JSON.stringify({ basePath }), 'utf-8')
|
|
371
|
+
|
|
372
|
+
// Build the server
|
|
373
|
+
await build({
|
|
374
|
+
root: this.root,
|
|
375
|
+
base: basePath,
|
|
376
|
+
mode: 'production',
|
|
377
|
+
configFile,
|
|
378
|
+
logLevel: this.logger.level,
|
|
379
|
+
build: {
|
|
380
|
+
outDir: resolve(this.root, clientDirectory, config.application.outputDirectory, serverDirectory),
|
|
381
|
+
ssr: resolve(this.root, clientDirectory, 'index.js')
|
|
382
|
+
}
|
|
383
|
+
})
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
getMeta () {
|
|
387
|
+
const vite = this._getApplication()?.vite
|
|
388
|
+
const config = vite?.devServer?.config ?? vite?.config.vite
|
|
389
|
+
const applicationBasePath = config?.base
|
|
390
|
+
|
|
391
|
+
const composer = {
|
|
392
|
+
tcp: typeof this.url !== 'undefined',
|
|
393
|
+
url: this.url,
|
|
394
|
+
prefix: this.basePath ?? applicationBasePath ?? this.#basePath,
|
|
395
|
+
wantsAbsoluteUrls: true,
|
|
396
|
+
needsRootTrailingSlash: true
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
return { composer }
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
_findEntrypoint () {
|
|
403
|
+
const config = this.config.vite ?? {}
|
|
404
|
+
return resolve(this.root, config.ssr.entrypoint)
|
|
405
|
+
}
|
|
406
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@platformatic/vite",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "3.0.0-alpha.1",
|
|
4
4
|
"description": "Platformatic Vite Stackable",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"type": "module",
|
|
@@ -18,10 +18,9 @@
|
|
|
18
18
|
"@fastify/static": "^8.0.0",
|
|
19
19
|
"fastify": "^5.0.0",
|
|
20
20
|
"semver": "^7.6.3",
|
|
21
|
-
"@platformatic/basic": "
|
|
22
|
-
"@platformatic/node": "
|
|
23
|
-
"@platformatic/
|
|
24
|
-
"@platformatic/utils": "2.71.1-alpha.0"
|
|
21
|
+
"@platformatic/basic": "3.0.0-alpha.1",
|
|
22
|
+
"@platformatic/node": "3.0.0-alpha.1",
|
|
23
|
+
"@platformatic/utils": "3.0.0-alpha.1"
|
|
25
24
|
},
|
|
26
25
|
"devDependencies": {
|
|
27
26
|
"@fastify/vite": "^7.0.1",
|
|
@@ -34,12 +33,12 @@
|
|
|
34
33
|
"typescript": "^5.5.4",
|
|
35
34
|
"vite": "^5.4.0",
|
|
36
35
|
"ws": "^8.18.0",
|
|
37
|
-
"@platformatic/composer": "
|
|
38
|
-
"@platformatic/service": "
|
|
36
|
+
"@platformatic/composer": "3.0.0-alpha.1",
|
|
37
|
+
"@platformatic/service": "3.0.0-alpha.1"
|
|
39
38
|
},
|
|
40
39
|
"scripts": {
|
|
41
|
-
"test": "npm run lint && borp --concurrency=1 --
|
|
42
|
-
"coverage": "npm run lint && borp -C -X test -X test/fixtures --concurrency=1 --
|
|
40
|
+
"test": "npm run lint && borp --concurrency=1 --timeout 1200000",
|
|
41
|
+
"coverage": "npm run lint && borp -C -X test -X test/fixtures --concurrency=1 --timeout 1200000",
|
|
43
42
|
"gen-schema": "node lib/schema.js > schema.json",
|
|
44
43
|
"gen-types": "json2ts > config.d.ts < schema.json",
|
|
45
44
|
"build": "pnpm run gen-schema && pnpm run gen-types",
|
package/schema.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
|
-
"$id": "https://schemas.platformatic.dev/@platformatic/vite/
|
|
2
|
+
"$id": "https://schemas.platformatic.dev/@platformatic/vite/3.0.0-alpha.1.json",
|
|
3
3
|
"$schema": "http://json-schema.org/draft-07/schema#",
|
|
4
|
-
"title": "Platformatic Vite
|
|
4
|
+
"title": "Platformatic Vite Config",
|
|
5
5
|
"type": "object",
|
|
6
6
|
"properties": {
|
|
7
7
|
"$schema": {
|