@@ -11,18 +11,22 @@ const outputDir = ".open-next";
11
11
const tempDir = path . join ( outputDir , ".build" ) ;
12
12
13
13
export async function build ( ) {
14
+ printVersion ( ) ;
15
+
14
16
// Pre-build validation
17
+ printHeader ( "Validating Next.js app" ) ;
15
18
checkRunningInsideNextjsApp ( ) ;
19
+ setStandaloneBuildMode ( ) ;
20
+ const monorepoRoot = findMonorepoRoot ( ) ;
16
21
17
22
// Build Next.js app
18
- setStandaloneBuildMode ( ) ;
19
- const buildOutput = await buildNextjsApp ( ) ;
23
+ printHeader ( "Building Next.js app" ) ;
24
+ const buildOutput = await buildNextjsApp ( monorepoRoot ) ;
20
25
21
26
// Generate deployable bundle
22
- printHeader ( "Generating OpenNext bundle" ) ;
23
- printVersion ( ) ;
27
+ printHeader ( "Generating bundle" ) ;
24
28
initOutputDir ( ) ;
25
- createServerBundle ( ) ;
29
+ createServerBundle ( monorepoRoot ) ;
26
30
createImageOptimizationBundle ( ) ;
27
31
createMiddlewareBundle ( buildOutput ) ;
28
32
createAssets ( ) ;
@@ -35,14 +39,35 @@ function checkRunningInsideNextjsApp() {
35
39
}
36
40
}
37
41
42
+ function findMonorepoRoot ( ) {
43
+ let currentPath = appPath ;
44
+ while ( currentPath !== "/" ) {
45
+ if ( fs . existsSync ( path . join ( currentPath , "package-lock.json" ) )
46
+ || fs . existsSync ( path . join ( currentPath , "yarn.lock" ) )
47
+ || fs . existsSync ( path . join ( currentPath , "pnpm-lock.yaml" ) ) ) {
48
+ if ( currentPath !== appPath ) {
49
+ console . info ( "Monorepo root detected at" , currentPath ) ;
50
+ }
51
+ return currentPath ;
52
+ }
53
+ currentPath = path . dirname ( currentPath ) ;
54
+ }
55
+
56
+ // note: a lock file (package-lock.json, yarn.lock, or pnpm-lock.yaml) is
57
+ // not found in the app's directory or any of its parent directories.
58
+ // We are going to assume that the app is not part of a monorepo.
59
+ return appPath ;
60
+ }
61
+
38
62
function setStandaloneBuildMode ( ) {
39
63
// Equivalent to setting `target: 'standalone'` in next.config.js
40
64
process . env . NEXT_PRIVATE_STANDALONE = "true" ;
41
65
}
42
66
43
- function buildNextjsApp ( ) {
67
+ function buildNextjsApp ( monorepoRoot : string ) {
44
68
return nextBuild ( {
45
69
files : [ ] ,
70
+ repoRootPath : monorepoRoot ,
46
71
workPath : appPath ,
47
72
entrypoint : "next.config.js" ,
48
73
config : { } ,
@@ -51,7 +76,8 @@ function buildNextjsApp() {
51
76
}
52
77
53
78
function printHeader ( header : string ) {
54
- console . log ( [
79
+ header = `OpenNext — ${ header } ` ;
80
+ console . info ( [
55
81
"┌" + "─" . repeat ( header . length + 2 ) + "┐" ,
56
82
`│ ${ header } │` ,
57
83
"└" + "─" . repeat ( header . length + 2 ) + "┘" ,
@@ -61,7 +87,7 @@ function printHeader(header: string) {
61
87
function printVersion ( ) {
62
88
const pathToPackageJson = path . join ( __dirname , "../package.json" ) ;
63
89
const pkg = JSON . parse ( fs . readFileSync ( pathToPackageJson , "utf-8" ) ) ;
64
- console . log ( `Using v${ pkg . version } ` ) ;
90
+ console . info ( `Using v${ pkg . version } ` ) ;
65
91
}
66
92
67
93
function initOutputDir ( ) {
@@ -75,8 +101,8 @@ function isMiddlewareEnabled() {
75
101
return JSON . parse ( json ) . sortedMiddleware . length > 0 ;
76
102
}
77
103
78
- function createServerBundle ( ) {
79
- console . debug ( `Bundling server function...` ) ;
104
+ function createServerBundle ( monorepoRoot : string ) {
105
+ console . info ( `Bundling server function...` ) ;
80
106
81
107
// Create output folder
82
108
const outputPath = path . join ( outputDir , "server-function" ) ;
@@ -90,6 +116,20 @@ function createServerBundle() {
90
116
path . join ( outputPath ) ,
91
117
{ recursive : true , verbatimSymlinks : true }
92
118
) ;
119
+ // note: if user's app is inside a monorepo, standalone mode places
120
+ // `node_modules` inside `.next/standalone`, and others inside
121
+ // `.next/standalone/package/path` (ie. `.next`, `server.js`).
122
+ // We need to move them to the root of the output folder.
123
+ if ( monorepoRoot ) {
124
+ const packagePath = path . relative ( monorepoRoot , appPath ) ;
125
+ fs . readdirSync ( path . join ( outputPath , packagePath ) )
126
+ . forEach ( file => {
127
+ fs . renameSync (
128
+ path . join ( outputPath , packagePath , file ) ,
129
+ path . join ( outputPath , file )
130
+ ) ;
131
+ } ) ;
132
+ }
93
133
94
134
// Standalone output already has a Node server "server.js", remove it.
95
135
// It will be replaced with the Lambda handler.
@@ -118,7 +158,7 @@ function createServerBundle() {
118
158
}
119
159
120
160
function createImageOptimizationBundle ( ) {
121
- console . debug ( `Bundling image optimization function...` ) ;
161
+ console . info ( `Bundling image optimization function...` ) ;
122
162
123
163
// Create output folder
124
164
const outputPath = path . join ( outputDir , "image-optimization-function" ) ;
@@ -170,10 +210,10 @@ function createImageOptimizationBundle() {
170
210
171
211
function createMiddlewareBundle ( buildOutput : any ) {
172
212
if ( isMiddlewareEnabled ( ) ) {
173
- console . debug ( `Bundling middleware edge function...` ) ;
213
+ console . info ( `Bundling middleware edge function...` ) ;
174
214
}
175
215
else {
176
- console . debug ( `Bundling middleware edge function... \x1b[36m%s\x1b[0m` , "skipped" ) ;
216
+ console . info ( `Bundling middleware edge function... \x1b[36m%s\x1b[0m` , "skipped" ) ;
177
217
return ;
178
218
}
179
219
@@ -221,7 +261,7 @@ function createMiddlewareBundle(buildOutput: any) {
221
261
}
222
262
223
263
function createAssets ( ) {
224
- console . debug ( `Bundling assets...` ) ;
264
+ console . info ( `Bundling assets...` ) ;
225
265
226
266
// Create output folder
227
267
const outputPath = path . join ( outputDir , "assets" ) ;
0 commit comments