@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 CHANGED
@@ -5,7 +5,7 @@
5
5
  * and run json-schema-to-typescript to regenerate this file.
6
6
  */
7
7
 
8
- export interface PlatformaticViteStackable {
8
+ export interface PlatformaticViteConfig {
9
9
  $schema?: string;
10
10
  logger?: {
11
11
  level: (
package/index.js CHANGED
@@ -1,422 +1,16 @@
1
- import fastifyStatic from '@fastify/static'
2
- import {
3
- BaseStackable,
4
- transformConfig as basicTransformConfig,
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
- const supportedVersions = '^5.0.0'
6
+ /* c8 ignore next 5 */
7
+ export async function transform (config, schema, options) {
8
+ config = await basicTransform(config, schema, options)
25
9
 
26
- export class ViteStackable extends BaseStackable {
27
- #vite
28
- #app
29
- #server
30
- #basePath
10
+ config.watch = { enabled: false }
31
11
 
32
- constructor (options, root, configManager) {
33
- super('vite', packageJson.version, options, root, configManager)
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 basicTransformConfig.call(this)
21
+ return config
428
22
  }
429
23
 
430
- export async function buildStackable (opts) {
431
- const root = opts.context.directory
24
+ export async function loadConfiguration (configOrRoot, sourceOrConfig, context) {
25
+ const { root, source } = await resolve(configOrRoot, sourceOrConfig, 'application')
432
26
 
433
- const configManager = new ConfigManager({
434
- schema,
435
- source: opts.config ?? {},
436
- schemaOptions,
437
- transformConfig,
438
- dirname: root
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 { schema, schemaComponents } from './lib/schema.js'
36
+ export async function create (configOrRoot, sourceOrConfig, context) {
37
+ const config = await loadConfiguration(configOrRoot, sourceOrConfig, context)
453
38
 
454
- export default {
455
- configType: 'vite',
456
- configManagerConfig: {
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(new URL('../package.json', import.meta.url), 'utf-8'))
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 Stackable',
55
+ title: 'Platformatic Vite Config',
54
56
  type: 'object',
55
57
  properties: {
56
58
  $schema: {
@@ -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": "2.71.1-alpha.0",
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": "2.71.1-alpha.0",
22
- "@platformatic/node": "2.71.1-alpha.0",
23
- "@platformatic/config": "2.71.1-alpha.0",
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": "2.71.1-alpha.0",
38
- "@platformatic/service": "2.71.1-alpha.0"
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 --no-timeout",
42
- "coverage": "npm run lint && borp -C -X test -X test/fixtures --concurrency=1 --no-timeout",
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.71.1-alpha.0.json",
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 Stackable",
4
+ "title": "Platformatic Vite Config",
5
5
  "type": "object",
6
6
  "properties": {
7
7
  "$schema": {