2021-12-07 02:14:55 +01:00
import fs from 'fs'
import { join , relative } from 'path'
import { PAGES_MANIFEST , BUILD_ID_FILE } from '../shared/lib/constants'
import { PagesManifest } from '../build/webpack/plugins/pages-manifest-plugin'
import type { Route } from './router'
import { recursiveReadDirSync } from './lib/recursive-readdir-sync'
import { route } from './router'
2021-12-05 22:53:11 +01:00
import BaseServer from './base-server'
export * from './base-server'
2021-11-28 17:48:43 +01:00
2021-12-07 02:14:55 +01:00
export default class NextNodeServer extends BaseServer {
protected getHasStaticDir ( ) : boolean {
return fs . existsSync ( join ( this . dir , 'static' ) )
}
protected getPagesManifest ( ) : PagesManifest | undefined {
const pagesManifestPath = join ( this . serverBuildDir , PAGES_MANIFEST )
return require ( pagesManifestPath )
}
protected getBuildId ( ) : string {
const buildIdFile = join ( this . distDir , BUILD_ID_FILE )
try {
return fs . readFileSync ( buildIdFile , 'utf8' ) . trim ( )
} catch ( err ) {
if ( ! fs . existsSync ( buildIdFile ) ) {
throw new Error (
` Could not find a production build in the ' ${ this . distDir } ' directory. Try building your app with 'next build' before starting the production server. https://nextjs.org/docs/messages/production-start-no-build-id `
)
}
throw err
}
}
protected generatePublicRoutes ( ) : Route [ ] {
if ( ! fs . existsSync ( this . publicDir ) ) return [ ]
const publicFiles = new Set (
recursiveReadDirSync ( this . publicDir ) . map ( ( p ) = >
encodeURI ( p . replace ( /\\/g , '/' ) )
)
)
return [
{
match : route ( '/:path*' ) ,
name : 'public folder catchall' ,
fn : async ( req , res , params , parsedUrl ) = > {
const pathParts : string [ ] = params . path || [ ]
const { basePath } = this . nextConfig
// if basePath is defined require it be present
if ( basePath ) {
const basePathParts = basePath . split ( '/' )
// remove first empty value
basePathParts . shift ( )
if (
! basePathParts . every ( ( part : string , idx : number ) = > {
return part === pathParts [ idx ]
} )
) {
return { finished : false }
}
pathParts . splice ( 0 , basePathParts . length )
}
let path = ` / ${ pathParts . join ( '/' ) } `
if ( ! publicFiles . has ( path ) ) {
// In `next-dev-server.ts`, we ensure encoded paths match
// decoded paths on the filesystem. So we need do the
// opposite here: make sure decoded paths match encoded.
path = encodeURI ( path )
}
if ( publicFiles . has ( path ) ) {
await this . serveStatic (
req ,
res ,
join ( this . publicDir , . . . pathParts ) ,
parsedUrl
)
return {
finished : true ,
}
}
return {
finished : false ,
}
} ,
} as Route ,
]
}
private _validFilesystemPathSet : Set < string > | null = null
protected getFilesystemPaths ( ) : Set < string > {
if ( this . _validFilesystemPathSet ) {
return this . _validFilesystemPathSet
}
const pathUserFilesStatic = join ( this . dir , 'static' )
let userFilesStatic : string [ ] = [ ]
if ( this . hasStaticDir && fs . existsSync ( pathUserFilesStatic ) ) {
userFilesStatic = recursiveReadDirSync ( pathUserFilesStatic ) . map ( ( f ) = >
join ( '.' , 'static' , f )
)
}
let userFilesPublic : string [ ] = [ ]
if ( this . publicDir && fs . existsSync ( this . publicDir ) ) {
userFilesPublic = recursiveReadDirSync ( this . publicDir ) . map ( ( f ) = >
join ( '.' , 'public' , f )
)
}
let nextFilesStatic : string [ ] = [ ]
nextFilesStatic =
! this . minimalMode && fs . existsSync ( join ( this . distDir , 'static' ) )
? recursiveReadDirSync ( join ( this . distDir , 'static' ) ) . map ( ( f ) = >
join ( '.' , relative ( this . dir , this . distDir ) , 'static' , f )
)
: [ ]
return ( this . _validFilesystemPathSet = new Set < string > ( [
. . . nextFilesStatic ,
. . . userFilesPublic ,
. . . userFilesStatic ,
] ) )
}
}