@platformatic/next 3.33.0-alpha.1 → 3.33.0-alpha.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/capability.js CHANGED
@@ -33,7 +33,7 @@ export class NextCapability extends BaseCapability {
33
33
  #child
34
34
  #server
35
35
  #configModified
36
- #isStandalone
36
+ #standaloneEntrypoint
37
37
 
38
38
  constructor (root, config, context) {
39
39
  super('next', version, root, config, context)
@@ -41,15 +41,39 @@ export class NextCapability extends BaseCapability {
41
41
  this.exitOnUnhandledErrors = false
42
42
  }
43
43
 
44
- async init () {
44
+ async init (building = false) {
45
45
  await super.init()
46
46
 
47
- if (this.isProduction && this.config.next?.standalone) {
48
- this.#isStandalone = true
49
- return
47
+ // This is needed to avoid Next.js to throw an error when the lockfile is not correct
48
+ // and the user is using npm but has pnpm in its $PATH.
49
+ //
50
+ // See: https://github.com/platformatic/composer-next-node-fastify/pull/3
51
+ //
52
+ // PS by Paolo: Sob.
53
+ process.env.NEXT_IGNORE_INCORRECT_LOCKFILE = 'true'
54
+
55
+ if (!building && this.isProduction && this.config.next?.standalone) {
56
+ this.#standaloneEntrypoint = await this.#resolveStandaloneEntrypoint()
57
+ this.#next = resolvePath(dirname(await resolvePackageViaCJS(this.#standaloneEntrypoint, 'next')), '../..')
58
+ } else {
59
+ this.#next = resolvePath(dirname(await resolvePackageViaCJS(this.root, 'next')), '../..')
60
+ }
61
+
62
+ const nextPackage = JSON.parse(await readFile(resolvePath(this.#next, 'package.json'), 'utf-8'))
63
+ this.#nextVersion = parse(nextPackage.version)
64
+
65
+ if (this.#nextVersion.major < 15 || (this.#nextVersion.major <= 15 && this.#nextVersion.minor < 1)) {
66
+ await import('./create-context-patch.js')
50
67
  }
51
68
 
52
- return this.#init()
69
+ if (this.#nextVersion.major < 16 && this.config.next?.useExperimentalAdapter === true) {
70
+ this.config.next.useExperimentalAdapter = false
71
+ }
72
+
73
+ /* c8 ignore next 3 */
74
+ if (!this.isProduction && !supportedVersions.some(v => satisfies(nextPackage.version, v))) {
75
+ throw new basicErrors.UnsupportedVersion('next', nextPackage.version, supportedVersions)
76
+ }
53
77
  }
54
78
 
55
79
  async start ({ listen }) {
@@ -107,18 +131,17 @@ export class NextCapability extends BaseCapability {
107
131
  }
108
132
 
109
133
  async build () {
110
- if (!this.#nextVersion) {
111
- await this.#init()
112
- }
113
-
114
134
  const config = this.config
115
135
  const loader = new URL('./loader.js', import.meta.url)
116
136
  this.#basePath = config.application?.basePath ? cleanBasePath(config.application?.basePath) : ''
117
137
 
118
138
  let command = config.application.commands.build
119
139
 
140
+ if (!command || !config.next?.standalone) {
141
+ await this.init(true)
142
+ }
143
+
120
144
  if (!command) {
121
- await this.init()
122
145
  command = ['node', resolvePath(this.#next, './dist/bin/next'), 'build', this.root]
123
146
  }
124
147
 
@@ -156,33 +179,6 @@ export class NextCapability extends BaseCapability {
156
179
  return context
157
180
  }
158
181
 
159
- async #init () {
160
- // This is needed to avoid Next.js to throw an error when the lockfile is not correct
161
- // and the user is using npm but has pnpm in its $PATH.
162
- //
163
- // See: https://github.com/platformatic/composer-next-node-fastify/pull/3
164
- //
165
- // PS by Paolo: Sob.
166
- process.env.NEXT_IGNORE_INCORRECT_LOCKFILE = 'true'
167
-
168
- this.#next = resolvePath(dirname(await resolvePackageViaCJS(this.root, 'next')), '../..')
169
- const nextPackage = JSON.parse(await readFile(resolvePath(this.#next, 'package.json'), 'utf-8'))
170
- this.#nextVersion = parse(nextPackage.version)
171
-
172
- if (this.#nextVersion.major < 15 || (this.#nextVersion.major <= 15 && this.#nextVersion.minor < 1)) {
173
- await import('./create-context-patch.js')
174
- }
175
-
176
- if (this.#nextVersion.major < 16 && this.config.next?.useExperimentalAdapter === true) {
177
- this.config.next.useExperimentalAdapter = false
178
- }
179
-
180
- /* c8 ignore next 3 */
181
- if (!supportedVersions.some(v => satisfies(nextPackage.version, v))) {
182
- throw new basicErrors.UnsupportedVersion('next', nextPackage.version, supportedVersions)
183
- }
184
- }
185
-
186
182
  async #startDevelopment () {
187
183
  const config = this.config
188
184
  const loaderUrl = new URL('./loader.js', import.meta.url)
@@ -264,7 +260,7 @@ export class NextCapability extends BaseCapability {
264
260
  this.#getChildManagerScripts()
265
261
  )
266
262
 
267
- if (this.#isStandalone) {
263
+ if (this.#standaloneEntrypoint) {
268
264
  return this.#startProductionStandaloneNext()
269
265
  } else {
270
266
  this.verifyOutputDirectory(resolvePath(this.root, '.next'))
@@ -310,25 +306,6 @@ export class NextCapability extends BaseCapability {
310
306
  }
311
307
 
312
308
  async #startProductionStandaloneNext () {
313
- // If built in standalone mode, the generated standalone directory is not on the root of the project but somewhere
314
- // inside .next/standalone due to turbopack limitations in determining the root of the project.
315
- // In that case we search a server.js next to a .next folder inside the .next /standalone folder.
316
- const serverEntrypoints = await Array.fromAsync(
317
- glob(['**/server.js'], { cwd: this.root, ignore: ['node_modules', '**/node_modules/**'] })
318
- )
319
-
320
- let serverEntrypoint
321
- for (const entrypoint of serverEntrypoints) {
322
- if (existsSync(resolvePath(this.root, dirname(entrypoint), '.next'))) {
323
- serverEntrypoint = resolvePath(this.root, entrypoint)
324
- break
325
- }
326
- }
327
-
328
- if (!serverEntrypoint) {
329
- throw new errors.StandaloneServerNotFound()
330
- }
331
-
332
309
  // The default Next.js standalone server uses chdir, which is not supported in worker threads.
333
310
  // Therefore we need to reproduce the server.js logic here, which what we do in the rest of this method.
334
311
 
@@ -336,7 +313,7 @@ export class NextCapability extends BaseCapability {
336
313
  // For now we use simple regex parsing, if it breaks, we can switch to proper AST parsing.
337
314
  let nextConfig
338
315
  try {
339
- const serverJsContent = await readFile(serverEntrypoint, 'utf-8')
316
+ const serverJsContent = await readFile(this.#standaloneEntrypoint, 'utf-8')
340
317
  const nextConfigMatch = serverJsContent.match(/(?:const|let)\s*nextConfig\s*=\s*(\{.+)/)
341
318
  nextConfig = JSON.parse(nextConfigMatch[1])
342
319
  } catch (e) {
@@ -378,10 +355,10 @@ export class NextCapability extends BaseCapability {
378
355
 
379
356
  // This is needed by Next.js standalone server to pick up the correct configuration
380
357
  process.env.__NEXT_PRIVATE_STANDALONE_CONFIG = JSON.stringify(nextConfig)
381
- const { startServer } = this.#requireStandaloneEntrypoint(serverEntrypoint)
358
+ const { startServer } = this.#requireStandaloneEntrypoint(this.#standaloneEntrypoint)
382
359
 
383
360
  await startServer({
384
- dir: dirname(serverEntrypoint),
361
+ dir: dirname(this.#standaloneEntrypoint),
385
362
  isDev: false,
386
363
  config: nextConfig,
387
364
  hostname: serverOptions.hostname,
@@ -462,6 +439,34 @@ export class NextCapability extends BaseCapability {
462
439
  return distDir
463
440
  }
464
441
 
442
+ async #resolveStandaloneEntrypoint () {
443
+ // If built in standalone mode, the generated standalone directory is not on the root of the project but somewhere
444
+ // inside .next/standalone due to turbopack limitations in determining the root of the project.
445
+ // In that case we search a server.js next to a .next folder inside the .next /standalone folder.
446
+ const serverEntrypoints = await Array.fromAsync(
447
+ glob(['**/server.js'], { cwd: this.root, ignore: ['node_modules', '**/node_modules/**'] })
448
+ )
449
+
450
+ let serverEntrypoint
451
+ for (const entrypoint of serverEntrypoints) {
452
+ if (existsSync(resolvePath(this.root, dirname(entrypoint), '.next'))) {
453
+ const candidate = resolvePath(this.root, entrypoint)
454
+ const contents = await readFile(candidate, 'utf-8')
455
+
456
+ if (contents.includes('process.env.__NEXT_PRIVATE_STANDALONE_CONFIG =')) {
457
+ serverEntrypoint = candidate
458
+ break
459
+ }
460
+ }
461
+ }
462
+
463
+ if (!serverEntrypoint) {
464
+ throw new errors.StandaloneServerNotFound()
465
+ }
466
+
467
+ return serverEntrypoint
468
+ }
469
+
465
470
  #requireStandaloneEntrypoint (serverEntrypoint) {
466
471
  let serverModule
467
472
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@platformatic/next",
3
- "version": "3.33.0-alpha.1",
3
+ "version": "3.33.0-alpha.3",
4
4
  "description": "Platformatic Next.js Capability",
5
5
  "main": "index.js",
6
6
  "type": "module",
@@ -23,8 +23,8 @@
23
23
  "iovalkey": "^0.3.0",
24
24
  "msgpackr": "^1.11.2",
25
25
  "semver": "^7.6.3",
26
- "@platformatic/basic": "3.33.0-alpha.1",
27
- "@platformatic/foundation": "3.33.0-alpha.1"
26
+ "@platformatic/basic": "3.33.0-alpha.3",
27
+ "@platformatic/foundation": "3.33.0-alpha.3"
28
28
  },
29
29
  "devDependencies": {
30
30
  "@fastify/reply-from": "^12.0.0",
@@ -40,8 +40,8 @@
40
40
  "next": "^16.0.0",
41
41
  "typescript": "^5.5.4",
42
42
  "ws": "^8.18.0",
43
- "@platformatic/gateway": "3.33.0-alpha.1",
44
- "@platformatic/service": "3.33.0-alpha.1"
43
+ "@platformatic/gateway": "3.33.0-alpha.3",
44
+ "@platformatic/service": "3.33.0-alpha.3"
45
45
  },
46
46
  "engines": {
47
47
  "node": ">=22.19.0"
package/schema.json CHANGED
@@ -1,5 +1,5 @@
1
1
  {
2
- "$id": "https://schemas.platformatic.dev/@platformatic/next/3.33.0-alpha.1.json",
2
+ "$id": "https://schemas.platformatic.dev/@platformatic/next/3.33.0-alpha.3.json",
3
3
  "$schema": "http://json-schema.org/draft-07/schema#",
4
4
  "title": "Platformatic Next.js Config",
5
5
  "type": "object",