1- import { readFileSync } from 'node:fs'
1+ import { existsSync , readFileSync } from 'node:fs'
22import { readFile } from 'node:fs/promises'
33// Here we need to actually import `resolve` from node:path as we want to resolve the paths
44// eslint-disable-next-line no-restricted-imports
@@ -32,6 +32,11 @@ export interface RequiredServerFilesManifest {
3232 ignore : string [ ]
3333}
3434
35+ export interface ExportDetail {
36+ success : boolean
37+ outDirectory : string
38+ }
39+
3540export class PluginContext {
3641 utils : NetlifyPluginUtils
3742 netlifyConfig : NetlifyPluginOptions [ 'netlifyConfig' ]
@@ -200,6 +205,28 @@ export class PluginContext {
200205 return JSON . parse ( await readFile ( join ( this . publishDir , 'prerender-manifest.json' ) , 'utf-8' ) )
201206 }
202207
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+
203230 /**
204231 * Get Next.js middleware config from the build output
205232 */
@@ -215,13 +242,45 @@ export class PluginContext {
215242 /** Get RequiredServerFiles manifest from build output **/
216243 get requiredServerFiles ( ) : RequiredServerFilesManifest {
217244 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+
218254 this . _requiredServerFiles = JSON . parse (
219- readFileSync ( join ( this . publishDir , 'required-server-files.json' ) , 'utf-8' ) ,
255+ readFileSync ( requiredServerFilesJson , 'utf-8' ) ,
220256 ) as RequiredServerFilesManifest
221257 }
222258 return this . _requiredServerFiles
223259 }
224260
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+
225284 /** Get Next Config from build output **/
226285 get buildConfig ( ) : NextConfigComplete {
227286 return this . requiredServerFiles . config
0 commit comments