1
- import { readFileSync } from 'node:fs'
1
+ import { existsSync , readFileSync } from 'node:fs'
2
2
import { readFile } from 'node:fs/promises'
3
3
// Here we need to actually import `resolve` from node:path as we want to resolve the paths
4
4
// eslint-disable-next-line no-restricted-imports
@@ -32,6 +32,11 @@ export interface RequiredServerFilesManifest {
32
32
ignore : string [ ]
33
33
}
34
34
35
+ export interface ExportDetail {
36
+ success : boolean
37
+ outDirectory : string
38
+ }
39
+
35
40
export class PluginContext {
36
41
utils : NetlifyPluginUtils
37
42
netlifyConfig : NetlifyPluginOptions [ 'netlifyConfig' ]
@@ -200,6 +205,28 @@ export class PluginContext {
200
205
return JSON . parse ( await readFile ( join ( this . publishDir , 'prerender-manifest.json' ) , 'utf-8' ) )
201
206
}
202
207
208
+ /**
209
+ * Uses various heuristics to try to find the .next dir.
210
+ * Works by looking for BUILD_ID, so requires the site to have been built
211
+ */
212
+ findDotNext ( ) : string | false {
213
+ for ( const dir of [
214
+ // The publish directory
215
+ this . publishDir ,
216
+ // In the root
217
+ resolve ( DEFAULT_PUBLISH_DIR ) ,
218
+ // The sibling of the publish directory
219
+ resolve ( this . publishDir , '..' , DEFAULT_PUBLISH_DIR ) ,
220
+ // In the package dir
221
+ resolve ( this . constants . PACKAGE_PATH || '' , DEFAULT_PUBLISH_DIR ) ,
222
+ ] ) {
223
+ if ( existsSync ( join ( dir , 'BUILD_ID' ) ) ) {
224
+ return dir
225
+ }
226
+ }
227
+ return false
228
+ }
229
+
203
230
/**
204
231
* Get Next.js middleware config from the build output
205
232
*/
@@ -215,13 +242,45 @@ export class PluginContext {
215
242
/** Get RequiredServerFiles manifest from build output **/
216
243
get requiredServerFiles ( ) : RequiredServerFilesManifest {
217
244
if ( ! this . _requiredServerFiles ) {
245
+ let requiredServerFilesJson = join ( this . publishDir , 'required-server-files.json' )
246
+
247
+ if ( ! existsSync ( requiredServerFilesJson ) ) {
248
+ const dotNext = this . findDotNext ( )
249
+ if ( dotNext ) {
250
+ requiredServerFilesJson = join ( dotNext , 'required-server-files.json' )
251
+ }
252
+ }
253
+
218
254
this . _requiredServerFiles = JSON . parse (
219
- readFileSync ( join ( this . publishDir , 'required-server-files.json' ) , 'utf-8' ) ,
255
+ readFileSync ( requiredServerFilesJson , 'utf-8' ) ,
220
256
) as RequiredServerFilesManifest
221
257
}
222
258
return this . _requiredServerFiles
223
259
}
224
260
261
+ #exportDetail: ExportDetail | null = null
262
+
263
+ /** Get metadata when output = export */
264
+ get exportDetail ( ) : ExportDetail | null {
265
+ if ( this . buildConfig . output !== 'export' ) {
266
+ return null
267
+ }
268
+ if ( ! this . #exportDetail) {
269
+ const detailFile = join (
270
+ this . requiredServerFiles . appDir ,
271
+ this . buildConfig . distDir ,
272
+ 'export-detail.json' ,
273
+ )
274
+ if ( ! existsSync ( detailFile ) ) {
275
+ return null
276
+ }
277
+ try {
278
+ this . #exportDetail = JSON . parse ( readFileSync ( detailFile , 'utf-8' ) )
279
+ } catch { }
280
+ }
281
+ return this . #exportDetail
282
+ }
283
+
225
284
/** Get Next Config from build output **/
226
285
get buildConfig ( ) : NextConfigComplete {
227
286
return this . requiredServerFiles . config
0 commit comments