@platformatic/astro 3.4.1 → 3.5.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 +339 -3
- package/index.js +24 -320
- package/lib/capability.js +302 -0
- package/lib/schema.js +7 -4
- package/package.json +18 -15
- package/schema.json +1358 -7
package/index.js
CHANGED
|
@@ -1,327 +1,31 @@
|
|
|
1
|
-
import
|
|
2
|
-
import
|
|
3
|
-
import {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
importFile,
|
|
12
|
-
resolvePackage,
|
|
13
|
-
schemaOptions
|
|
14
|
-
} from '@platformatic/basic'
|
|
15
|
-
import { ConfigManager } from '@platformatic/config'
|
|
16
|
-
import fastify from 'fastify'
|
|
17
|
-
import { existsSync } from 'node:fs'
|
|
18
|
-
import { readFile, writeFile } from 'node:fs/promises'
|
|
19
|
-
import { dirname, resolve } from 'node:path'
|
|
20
|
-
import { pathToFileURL } from 'node:url'
|
|
21
|
-
import { satisfies } from 'semver'
|
|
22
|
-
import { packageJson, schema } from './lib/schema.js'
|
|
23
|
-
|
|
24
|
-
const supportedVersions = '^4.0.0'
|
|
25
|
-
|
|
26
|
-
export class AstroStackable extends BaseStackable {
|
|
27
|
-
#astro
|
|
28
|
-
#app
|
|
29
|
-
#server
|
|
30
|
-
#basePath
|
|
31
|
-
|
|
32
|
-
constructor (options, root, configManager) {
|
|
33
|
-
super('astro', packageJson.version, options, root, configManager)
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
async init () {
|
|
37
|
-
this.#astro = resolve(dirname(resolvePackage(this.root, 'astro')), '../..')
|
|
38
|
-
const astroPackage = JSON.parse(await readFile(resolve(this.#astro, 'package.json'), 'utf-8'))
|
|
39
|
-
|
|
40
|
-
/* c8 ignore next 3 */
|
|
41
|
-
if (!satisfies(astroPackage.version, supportedVersions)) {
|
|
42
|
-
throw new errors.UnsupportedVersion('astro', astroPackage.version, supportedVersions)
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
async start ({ listen }) {
|
|
47
|
-
// Make this idempotent
|
|
48
|
-
if (this.url) {
|
|
49
|
-
return this.url
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
if (this.isProduction) {
|
|
53
|
-
await this.#startProduction(listen)
|
|
54
|
-
} else {
|
|
55
|
-
await this.#startDevelopment(listen)
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
async stop () {
|
|
60
|
-
if (this.subprocess) {
|
|
61
|
-
return this.stopCommand()
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
return this.isProduction ? this.#app.close() : this.#app.stop()
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
async build () {
|
|
68
|
-
const config = this.configManager.current
|
|
69
|
-
const command = config.application.commands.build
|
|
70
|
-
const configFile = config.astro.configFile // Note: Astro expect this to be a relative path to the root
|
|
71
|
-
let basePath = config.application?.basePath
|
|
72
|
-
? ensureTrailingSlash(cleanBasePath(config.application?.basePath))
|
|
73
|
-
: undefined
|
|
74
|
-
|
|
75
|
-
if (command) {
|
|
76
|
-
return this.buildWithCommand(command, basePath)
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
await this.init()
|
|
80
|
-
const { build } = await importFile(resolve(this.#astro, 'dist/core/index.js'))
|
|
81
|
-
|
|
82
|
-
await build({
|
|
83
|
-
root: this.root,
|
|
84
|
-
base: basePath,
|
|
85
|
-
outDir: config.application.outputDirectory,
|
|
86
|
-
mode: 'production',
|
|
87
|
-
configFile,
|
|
88
|
-
logLevel: this.logger.level,
|
|
89
|
-
integrations: [
|
|
90
|
-
{
|
|
91
|
-
name: 'platformatic',
|
|
92
|
-
hooks: {
|
|
93
|
-
'astro:config:done': ({ config }) => {
|
|
94
|
-
basePath = ensureTrailingSlash(cleanBasePath(config.base))
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
}
|
|
98
|
-
]
|
|
99
|
-
})
|
|
100
|
-
|
|
101
|
-
await writeFile(
|
|
102
|
-
resolve(this.root, config.application.outputDirectory, '.platformatic-build.json'),
|
|
103
|
-
JSON.stringify({ basePath }),
|
|
104
|
-
'utf-8'
|
|
105
|
-
)
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
/* c8 ignore next 5 */
|
|
109
|
-
async getWatchConfig () {
|
|
110
|
-
return {
|
|
111
|
-
enabled: false
|
|
112
|
-
}
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
getMeta () {
|
|
116
|
-
const config = this.subprocessConfig ?? this.#app?.config
|
|
117
|
-
|
|
118
|
-
const composer = {
|
|
119
|
-
tcp: typeof this.url !== 'undefined',
|
|
120
|
-
url: this.url,
|
|
121
|
-
prefix: this.basePath ?? config?.base ?? this.#basePath,
|
|
122
|
-
wantsAbsoluteUrls: true,
|
|
123
|
-
needsRootRedirect: true
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
return { composer }
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
// This is only used in non SSR production mode as in other modes a TCP server is started
|
|
130
|
-
async inject (injectParams, onInject) {
|
|
131
|
-
const res = await this.#app.inject(injectParams, onInject)
|
|
132
|
-
|
|
133
|
-
/* c8 ignore next 3 */
|
|
134
|
-
if (onInject) {
|
|
135
|
-
return
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
// Since inject might be called from the main thread directly via ITC, let's clean it up
|
|
139
|
-
const { statusCode, headers, body, payload, rawPayload } = res
|
|
140
|
-
return { statusCode, headers, body, payload, rawPayload }
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
async #startDevelopment () {
|
|
144
|
-
// Make this idempotent
|
|
145
|
-
if (this.url) {
|
|
146
|
-
return this.url
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
const config = this.configManager.current
|
|
150
|
-
const command = this.configManager.current.application.commands.development
|
|
151
|
-
|
|
152
|
-
this.#basePath = config.application?.basePath
|
|
153
|
-
? ensureTrailingSlash(cleanBasePath(config.application?.basePath))
|
|
154
|
-
: undefined
|
|
155
|
-
|
|
156
|
-
this.registerGlobals({
|
|
157
|
-
id: this.id,
|
|
158
|
-
// Always use URL to avoid serialization problem in Windows
|
|
159
|
-
root: pathToFileURL(this.root).toString(),
|
|
160
|
-
basePath: this.#basePath,
|
|
161
|
-
logLevel: this.logger.level
|
|
162
|
-
})
|
|
163
|
-
|
|
164
|
-
if (command) {
|
|
165
|
-
return this.startWithCommand(command)
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
// Prepare options
|
|
169
|
-
const { hostname, port } = this.serverConfig ?? {}
|
|
170
|
-
const configFile = config.astro.configFile // Note: Astro expect this to be a relative path to the root
|
|
171
|
-
|
|
172
|
-
const serverOptions = {
|
|
173
|
-
host: hostname || '127.0.0.1',
|
|
174
|
-
port: port || 0
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
// Require Astro
|
|
178
|
-
const serverPromise = createServerListener(
|
|
179
|
-
(this.isEntrypoint ? serverOptions?.port : undefined) ?? true,
|
|
180
|
-
(this.isEntrypoint ? serverOptions?.hostname : undefined) ?? true
|
|
181
|
-
)
|
|
182
|
-
const { dev } = await importFile(resolve(this.#astro, 'dist/core/index.js'))
|
|
183
|
-
|
|
184
|
-
// Create the server and listen
|
|
185
|
-
this.#app = await dev({
|
|
186
|
-
root: this.root,
|
|
187
|
-
base: this.#basePath,
|
|
188
|
-
mode: 'development',
|
|
189
|
-
configFile,
|
|
190
|
-
logLevel: this.logger.level,
|
|
191
|
-
server: serverOptions,
|
|
192
|
-
integrations: [
|
|
193
|
-
{
|
|
194
|
-
name: 'platformatic',
|
|
195
|
-
hooks: {
|
|
196
|
-
'astro:config:setup': ({ config }) => {
|
|
197
|
-
this.#basePath = ensureTrailingSlash(cleanBasePath(config.base))
|
|
198
|
-
|
|
199
|
-
/*
|
|
200
|
-
As Astro generates invalid paths in development mode which ignore the basePath
|
|
201
|
-
(see https://github.com/withastro/astro/issues/11445), make sure we provide
|
|
202
|
-
the prefix in HMR path.
|
|
203
|
-
*/
|
|
204
|
-
config.vite.server ??= {}
|
|
205
|
-
config.vite.server.hmr ??= {}
|
|
206
|
-
config.vite.server.hmr.path = `/${this.#basePath}/`.replaceAll(/\/+/g, '/')
|
|
207
|
-
}
|
|
208
|
-
}
|
|
209
|
-
}
|
|
210
|
-
]
|
|
211
|
-
})
|
|
212
|
-
|
|
213
|
-
this.#server = await serverPromise
|
|
214
|
-
this.url = getServerUrl(this.#server)
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
async #startProduction (listen) {
|
|
218
|
-
const config = this.configManager.current
|
|
219
|
-
const command = this.configManager.current.application.commands.production
|
|
220
|
-
const outputDirectory = config.application.outputDirectory
|
|
221
|
-
|
|
222
|
-
this.#basePath = config.application?.basePath
|
|
223
|
-
? ensureTrailingSlash(cleanBasePath(config.application?.basePath))
|
|
224
|
-
: undefined
|
|
225
|
-
|
|
226
|
-
this.registerGlobals({
|
|
227
|
-
id: this.id,
|
|
228
|
-
// Always use URL to avoid serialization problem in Windows
|
|
229
|
-
root: pathToFileURL(this.root).toString(),
|
|
230
|
-
basePath: this.#basePath,
|
|
231
|
-
logLevel: this.logger.level
|
|
232
|
-
})
|
|
233
|
-
|
|
234
|
-
if (command) {
|
|
235
|
-
return this.startWithCommand(command)
|
|
236
|
-
}
|
|
237
|
-
|
|
238
|
-
if (this.#app && listen) {
|
|
239
|
-
const serverOptions = this.serverConfig
|
|
240
|
-
await this.#app.listen({ host: serverOptions?.hostname || '127.0.0.1', port: serverOptions?.port || 0 })
|
|
241
|
-
this.url = getServerUrl(this.#app.server)
|
|
242
|
-
return this.url
|
|
243
|
-
}
|
|
244
|
-
|
|
245
|
-
this.#app = fastify({ logger: { level: this.logger.level } })
|
|
246
|
-
|
|
247
|
-
const root = resolve(this.root, outputDirectory)
|
|
248
|
-
this.verifyOutputDirectory(root)
|
|
249
|
-
|
|
250
|
-
const buildInfoPath = resolve(root, '.platformatic-build.json')
|
|
251
|
-
|
|
252
|
-
if (!this.#basePath && existsSync(buildInfoPath)) {
|
|
253
|
-
try {
|
|
254
|
-
const buildInfo = JSON.parse(await readFile(buildInfoPath, 'utf-8'))
|
|
255
|
-
this.#basePath = buildInfo.basePath
|
|
256
|
-
} catch (e) {
|
|
257
|
-
console.log(e)
|
|
258
|
-
}
|
|
259
|
-
}
|
|
260
|
-
|
|
261
|
-
const ssrEntrypoint = resolve(this.root, outputDirectory, 'server/entry.mjs')
|
|
262
|
-
|
|
263
|
-
if (existsSync(ssrEntrypoint)) {
|
|
264
|
-
const { handler } = await importFile(ssrEntrypoint)
|
|
265
|
-
|
|
266
|
-
await this.#app.register(fastifyStatic, {
|
|
267
|
-
root: resolve(this.root, outputDirectory, 'client'),
|
|
268
|
-
prefix: this.#basePath,
|
|
269
|
-
prefixAvoidTrailingSlash: true,
|
|
270
|
-
schemaHide: true
|
|
271
|
-
})
|
|
272
|
-
|
|
273
|
-
await this.#app.register(middie)
|
|
274
|
-
await this.#app.use(this.#basePath, handler)
|
|
275
|
-
} else {
|
|
276
|
-
await this.#app.register(fastifyStatic, {
|
|
277
|
-
root,
|
|
278
|
-
prefix: this.#basePath,
|
|
279
|
-
prefixAvoidTrailingSlash: true,
|
|
280
|
-
schemaHide: true
|
|
281
|
-
})
|
|
282
|
-
}
|
|
283
|
-
|
|
284
|
-
await this.#app.ready()
|
|
285
|
-
}
|
|
1
|
+
import { transform as basicTransform, resolve, validationOptions } from '@platformatic/basic'
|
|
2
|
+
import { kMetadata, loadConfiguration as utilsLoadConfiguration } from '@platformatic/foundation'
|
|
3
|
+
import { AstroCapability } from './lib/capability.js'
|
|
4
|
+
import { schema } from './lib/schema.js'
|
|
5
|
+
|
|
6
|
+
/* c8 ignore next 5 */
|
|
7
|
+
export async function transform (config, schema, options) {
|
|
8
|
+
config = await basicTransform(config, schema, options)
|
|
9
|
+
config.watch = { enabled: false }
|
|
10
|
+
return config
|
|
286
11
|
}
|
|
287
12
|
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
if (this.current.watch === undefined) {
|
|
291
|
-
this.current.watch = { enabled: false }
|
|
292
|
-
}
|
|
293
|
-
|
|
294
|
-
if (typeof this.current.watch !== 'object') {
|
|
295
|
-
this.current.watch = { enabled: this.current.watch || false }
|
|
296
|
-
}
|
|
13
|
+
export async function loadConfiguration (configOrRoot, sourceOrConfig, context) {
|
|
14
|
+
const { root, source } = await resolve(configOrRoot, sourceOrConfig, 'application')
|
|
297
15
|
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
const configManager = new ConfigManager({
|
|
305
|
-
schema,
|
|
306
|
-
source: opts.config ?? {},
|
|
307
|
-
schemaOptions,
|
|
308
|
-
transformConfig,
|
|
309
|
-
dirname: root
|
|
16
|
+
return utilsLoadConfiguration(source, context?.schema ?? schema, {
|
|
17
|
+
validationOptions,
|
|
18
|
+
transform,
|
|
19
|
+
replaceEnv: true,
|
|
20
|
+
root,
|
|
21
|
+
...context
|
|
310
22
|
})
|
|
311
|
-
await configManager.parseAndValidate()
|
|
312
|
-
|
|
313
|
-
return new AstroStackable(opts, root, configManager)
|
|
314
23
|
}
|
|
315
24
|
|
|
316
|
-
export
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
configType: 'astro',
|
|
320
|
-
configManagerConfig: {
|
|
321
|
-
schemaOptions,
|
|
322
|
-
transformConfig
|
|
323
|
-
},
|
|
324
|
-
buildStackable,
|
|
325
|
-
schema,
|
|
326
|
-
version: packageJson.version
|
|
25
|
+
export async function create (configOrRoot, sourceOrConfig, context) {
|
|
26
|
+
const config = await loadConfiguration(configOrRoot, sourceOrConfig, context)
|
|
27
|
+
return new AstroCapability(config[kMetadata].root, config, context)
|
|
327
28
|
}
|
|
29
|
+
|
|
30
|
+
export * from './lib/capability.js'
|
|
31
|
+
export { packageJson, schema, schemaComponents, version } from './lib/schema.js'
|
|
@@ -0,0 +1,302 @@
|
|
|
1
|
+
import middie from '@fastify/middie'
|
|
2
|
+
import fastifyStatic from '@fastify/static'
|
|
3
|
+
import {
|
|
4
|
+
BaseCapability,
|
|
5
|
+
cleanBasePath,
|
|
6
|
+
createServerListener,
|
|
7
|
+
ensureTrailingSlash,
|
|
8
|
+
errors,
|
|
9
|
+
getServerUrl,
|
|
10
|
+
importFile,
|
|
11
|
+
resolvePackage
|
|
12
|
+
} from '@platformatic/basic'
|
|
13
|
+
import { ensureLoggableError, features } from '@platformatic/foundation'
|
|
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 = '^4.0.0 || ^5.0.0'
|
|
22
|
+
|
|
23
|
+
export class AstroCapability extends BaseCapability {
|
|
24
|
+
#astro
|
|
25
|
+
#app
|
|
26
|
+
#server
|
|
27
|
+
#basePath
|
|
28
|
+
|
|
29
|
+
constructor (root, config, context) {
|
|
30
|
+
super('astro', version, root, config, context)
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
async init () {
|
|
34
|
+
await super.init()
|
|
35
|
+
|
|
36
|
+
if (this.isProduction) {
|
|
37
|
+
return
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
this.#astro = resolve(dirname(resolvePackage(this.root, 'astro')), '../..')
|
|
41
|
+
const astroPackage = JSON.parse(await readFile(resolve(this.#astro, 'package.json'), 'utf-8'))
|
|
42
|
+
|
|
43
|
+
if (!satisfies(astroPackage.version, supportedVersions)) {
|
|
44
|
+
throw new errors.UnsupportedVersion('astro', astroPackage.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
|
+
await super.stop()
|
|
65
|
+
|
|
66
|
+
if (this.childManager) {
|
|
67
|
+
return this.stopCommand()
|
|
68
|
+
} else if (!this.#app) {
|
|
69
|
+
return
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
return this.isProduction ? this.#app.close() : this.#app.stop()
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
async build () {
|
|
76
|
+
const config = this.config
|
|
77
|
+
const command = config.application.commands.build
|
|
78
|
+
const configFile = config.astro.configFile // Note: Astro expect this to be a relative path to the root
|
|
79
|
+
let basePath = config.application?.basePath
|
|
80
|
+
? ensureTrailingSlash(cleanBasePath(config.application?.basePath))
|
|
81
|
+
: undefined
|
|
82
|
+
|
|
83
|
+
if (command) {
|
|
84
|
+
return this.buildWithCommand(command, basePath)
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
await this.init()
|
|
88
|
+
const { build } = await importFile(resolve(this.#astro, 'dist/core/index.js'))
|
|
89
|
+
|
|
90
|
+
try {
|
|
91
|
+
globalThis.platformatic.isBuilding = true
|
|
92
|
+
|
|
93
|
+
await build({
|
|
94
|
+
root: this.root,
|
|
95
|
+
base: basePath,
|
|
96
|
+
outDir: config.application.outputDirectory,
|
|
97
|
+
mode: 'production',
|
|
98
|
+
configFile,
|
|
99
|
+
logLevel: this.logger.level,
|
|
100
|
+
integrations: [
|
|
101
|
+
{
|
|
102
|
+
name: 'platformatic',
|
|
103
|
+
hooks: {
|
|
104
|
+
'astro:config:done': ({ config }) => {
|
|
105
|
+
basePath = ensureTrailingSlash(cleanBasePath(config.base))
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
]
|
|
110
|
+
})
|
|
111
|
+
} finally {
|
|
112
|
+
globalThis.platformatic.isBuilding = false
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
await writeFile(
|
|
116
|
+
resolve(this.root, config.application.outputDirectory, '.platformatic-build.json'),
|
|
117
|
+
JSON.stringify({ basePath }),
|
|
118
|
+
'utf-8'
|
|
119
|
+
)
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/* c8 ignore next 5 */
|
|
123
|
+
async getWatchConfig () {
|
|
124
|
+
return {
|
|
125
|
+
enabled: false
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
getMeta () {
|
|
130
|
+
const config = this.subprocessConfig ?? this.#app?.config
|
|
131
|
+
|
|
132
|
+
const gateway = {
|
|
133
|
+
tcp: typeof this.url !== 'undefined',
|
|
134
|
+
url: this.url,
|
|
135
|
+
prefix: this.basePath ?? config?.base ?? this.#basePath,
|
|
136
|
+
wantsAbsoluteUrls: true,
|
|
137
|
+
needsRootTrailingSlash: true,
|
|
138
|
+
needsRefererBasedRedirect: !this.isProduction
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
return { gateway }
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
// This is only used in non SSR production mode as in other modes a TCP server is started
|
|
145
|
+
async inject (injectParams, onInject) {
|
|
146
|
+
const res = await this.#app.inject(injectParams, onInject)
|
|
147
|
+
|
|
148
|
+
/* c8 ignore next 3 */
|
|
149
|
+
if (onInject) {
|
|
150
|
+
return
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
// Since inject might be called from the main thread directly via ITC, let's clean it up
|
|
154
|
+
const { statusCode, headers, body, payload, rawPayload } = res
|
|
155
|
+
return { statusCode, headers, body, payload, rawPayload }
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
async #startDevelopment () {
|
|
159
|
+
// Make this idempotent
|
|
160
|
+
if (this.url) {
|
|
161
|
+
return this.url
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
const config = this.config
|
|
165
|
+
const command = this.config.application.commands.development
|
|
166
|
+
|
|
167
|
+
this.#basePath = config.application?.basePath
|
|
168
|
+
? ensureTrailingSlash(cleanBasePath(config.application?.basePath))
|
|
169
|
+
: undefined
|
|
170
|
+
|
|
171
|
+
this.registerGlobals({ basePath: this.#basePath })
|
|
172
|
+
|
|
173
|
+
if (command) {
|
|
174
|
+
return this.startWithCommand(command)
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
// Prepare options
|
|
178
|
+
const { hostname, port } = this.serverConfig ?? {}
|
|
179
|
+
const configFile = config.astro.configFile // Note: Astro expect this to be a relative path to the root
|
|
180
|
+
|
|
181
|
+
const serverOptions = {
|
|
182
|
+
host: hostname || '127.0.0.1',
|
|
183
|
+
port: port || 0
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
// Require Astro
|
|
187
|
+
const serverPromise = createServerListener(
|
|
188
|
+
(this.isEntrypoint ? serverOptions?.port : undefined) ?? true,
|
|
189
|
+
(this.isEntrypoint ? serverOptions?.hostname : undefined) ?? true
|
|
190
|
+
)
|
|
191
|
+
const { dev } = await importFile(resolve(this.#astro, 'dist/core/index.js'))
|
|
192
|
+
|
|
193
|
+
// Create the server and listen
|
|
194
|
+
this.#app = await dev({
|
|
195
|
+
root: this.root,
|
|
196
|
+
base: this.#basePath,
|
|
197
|
+
mode: 'development',
|
|
198
|
+
configFile,
|
|
199
|
+
logLevel: this.logger.level,
|
|
200
|
+
server: serverOptions,
|
|
201
|
+
vite: {
|
|
202
|
+
server: {
|
|
203
|
+
allowedHosts: ['.plt.local']
|
|
204
|
+
}
|
|
205
|
+
},
|
|
206
|
+
integrations: [
|
|
207
|
+
{
|
|
208
|
+
name: 'platformatic',
|
|
209
|
+
hooks: {
|
|
210
|
+
'astro:config:setup': ({ config }) => {
|
|
211
|
+
this.#basePath = ensureTrailingSlash(cleanBasePath(config.base))
|
|
212
|
+
|
|
213
|
+
/*
|
|
214
|
+
As Astro generates invalid paths in development mode which ignore the basePath
|
|
215
|
+
(see https://github.com/withastro/astro/issues/11445), make sure we provide
|
|
216
|
+
the prefix in HMR path.
|
|
217
|
+
*/
|
|
218
|
+
config.vite.server ??= {}
|
|
219
|
+
config.vite.server.hmr ??= {}
|
|
220
|
+
config.vite.server.hmr.path = `/${this.#basePath}/`.replaceAll(/\/+/g, '/')
|
|
221
|
+
config.vite.server.fs ??= {}
|
|
222
|
+
config.vite.server.fs.strict = false
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
]
|
|
227
|
+
})
|
|
228
|
+
|
|
229
|
+
this.#server = await serverPromise
|
|
230
|
+
this.url = getServerUrl(this.#server)
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
async #startProduction (listen) {
|
|
234
|
+
const config = this.config
|
|
235
|
+
const command = this.config.application.commands.production
|
|
236
|
+
const outputDirectory = config.application.outputDirectory
|
|
237
|
+
|
|
238
|
+
this.#basePath = config.application?.basePath
|
|
239
|
+
? ensureTrailingSlash(cleanBasePath(config.application?.basePath))
|
|
240
|
+
: undefined
|
|
241
|
+
|
|
242
|
+
this.registerGlobals({ basePath: this.#basePath })
|
|
243
|
+
|
|
244
|
+
if (command) {
|
|
245
|
+
return this.startWithCommand(command)
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
if (this.#app && listen) {
|
|
249
|
+
const serverOptions = this.serverConfig
|
|
250
|
+
const listenOptions = { host: serverOptions?.hostname || '127.0.0.1', port: serverOptions?.port || 0 }
|
|
251
|
+
|
|
252
|
+
if (this.isProduction && features.node.reusePort) {
|
|
253
|
+
listenOptions.reusePort = true
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
await this.#app.listen(listenOptions)
|
|
257
|
+
this.url = getServerUrl(this.#app.server)
|
|
258
|
+
return this.url
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
this.#app = fastify({ loggerInstance: this.logger })
|
|
262
|
+
|
|
263
|
+
const root = resolve(this.root, outputDirectory)
|
|
264
|
+
this.verifyOutputDirectory(root)
|
|
265
|
+
|
|
266
|
+
const buildInfoPath = resolve(root, '.platformatic-build.json')
|
|
267
|
+
|
|
268
|
+
if (!this.#basePath && existsSync(buildInfoPath)) {
|
|
269
|
+
try {
|
|
270
|
+
const buildInfo = JSON.parse(await readFile(buildInfoPath, 'utf-8'))
|
|
271
|
+
this.#basePath = buildInfo.basePath
|
|
272
|
+
} catch (e) {
|
|
273
|
+
globalThis.platformatic.logger.error({ err: ensureLoggableError(e) }, 'Reading build info failed.')
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
const ssrEntrypoint = resolve(this.root, outputDirectory, 'server/entry.mjs')
|
|
278
|
+
|
|
279
|
+
if (existsSync(ssrEntrypoint)) {
|
|
280
|
+
const { handler } = await importFile(ssrEntrypoint)
|
|
281
|
+
|
|
282
|
+
await this.#app.register(fastifyStatic, {
|
|
283
|
+
root: resolve(this.root, outputDirectory, 'client'),
|
|
284
|
+
prefix: this.#basePath,
|
|
285
|
+
prefixAvoidTrailingSlash: true,
|
|
286
|
+
schemaHide: true
|
|
287
|
+
})
|
|
288
|
+
|
|
289
|
+
await this.#app.register(middie)
|
|
290
|
+
await this.#app.use(this.#basePath, handler)
|
|
291
|
+
} else {
|
|
292
|
+
await this.#app.register(fastifyStatic, {
|
|
293
|
+
root,
|
|
294
|
+
prefix: this.#basePath,
|
|
295
|
+
prefixAvoidTrailingSlash: true,
|
|
296
|
+
schemaHide: true
|
|
297
|
+
})
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
await this.#app.ready()
|
|
301
|
+
}
|
|
302
|
+
}
|
package/lib/schema.js
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import { schemaComponents as basicSchemaComponents } from '@platformatic/basic'
|
|
2
|
-
import { schemaComponents as utilsSchemaComponents } from '@platformatic/
|
|
2
|
+
import { schemaComponents as utilsSchemaComponents } from '@platformatic/foundation'
|
|
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
|
export const astro = {
|
|
8
10
|
type: 'object',
|
|
@@ -20,7 +22,7 @@ export const schemaComponents = { astro }
|
|
|
20
22
|
export const schema = {
|
|
21
23
|
$id: `https://schemas.platformatic.dev/@platformatic/astro/${packageJson.version}.json`,
|
|
22
24
|
$schema: 'http://json-schema.org/draft-07/schema#',
|
|
23
|
-
title: 'Platformatic Astro
|
|
25
|
+
title: 'Platformatic Astro Config',
|
|
24
26
|
type: 'object',
|
|
25
27
|
properties: {
|
|
26
28
|
$schema: {
|
|
@@ -29,7 +31,8 @@ export const schema = {
|
|
|
29
31
|
logger: utilsSchemaComponents.logger,
|
|
30
32
|
server: utilsSchemaComponents.server,
|
|
31
33
|
watch: basicSchemaComponents.watch,
|
|
32
|
-
application: basicSchemaComponents.
|
|
34
|
+
application: basicSchemaComponents.buildableApplication,
|
|
35
|
+
runtime: utilsSchemaComponents.wrappedRuntime,
|
|
33
36
|
astro
|
|
34
37
|
},
|
|
35
38
|
additionalProperties: false
|