@@ -4,11 +4,10 @@ import path from "node:path";
4
4
import { fileURLToPath } from "node:url" ;
5
5
6
6
import { Lang , parse } from "@ast-grep/napi" ;
7
- import type { BuildOptions } from "@opennextjs/aws/build/helper.js" ;
7
+ import { type BuildOptions , getPackagePath } from "@opennextjs/aws/build/helper.js" ;
8
8
import { getCrossPlatformPathRegex } from "@opennextjs/aws/utils/regex.js" ;
9
9
import { build , Plugin } from "esbuild" ;
10
10
11
- import { Config } from "../config.js" ;
12
11
import { patchOptionalDependencies } from "./patches/ast/optional-deps.js" ;
13
12
import * as patches from "./patches/index.js" ;
14
13
import { normalizePath , patchCodeWithValidations } from "./utils/index.js" ;
@@ -19,22 +18,25 @@ const packageDistDir = path.join(path.dirname(fileURLToPath(import.meta.url)), "
19
18
/**
20
19
* Bundle the Open Next server.
21
20
*/
22
- export async function bundleServer ( config : Config , openNextOptions : BuildOptions ) : Promise < void > {
23
- patches . copyPackageCliFiles ( packageDistDir , config , openNextOptions ) ;
24
-
25
- const nextConfigStr =
26
- fs
27
- . readFileSync ( path . join ( config . paths . output . standaloneApp , "server.js" ) , "utf8" )
28
- ?. match ( / c o n s t n e x t C o n f i g = ( { .+ ?} ) \n / ) ?. [ 1 ] ?? { } ;
21
+ export async function bundleServer ( buildOpts : BuildOptions ) : Promise < void > {
22
+ patches . copyPackageCliFiles ( packageDistDir , buildOpts ) ;
23
+
24
+ const { appPath, outputDir, monorepoRoot } = buildOpts ;
25
+ const serverFiles = path . join (
26
+ outputDir ,
27
+ "server-functions/default" ,
28
+ getPackagePath ( buildOpts ) ,
29
+ ".next/required-server-files.json"
30
+ ) ;
31
+ const nextConfig = JSON . parse ( fs . readFileSync ( serverFiles , "utf-8" ) ) . config ;
29
32
30
33
console . log ( `\x1b[35m⚙️ Bundling the OpenNext server...\n\x1b[0m` ) ;
31
34
32
- patches . patchWranglerDeps ( config ) ;
33
- patches . updateWebpackChunksFile ( config ) ;
35
+ patches . patchWranglerDeps ( buildOpts ) ;
36
+ patches . updateWebpackChunksFile ( buildOpts ) ;
34
37
35
- const { appBuildOutputPath, appPath, outputDir, monorepoRoot } = openNextOptions ;
36
38
const outputPath = path . join ( outputDir , "server-functions" , "default" ) ;
37
- const packagePath = path . relative ( monorepoRoot , appBuildOutputPath ) ;
39
+ const packagePath = getPackagePath ( buildOpts ) ;
38
40
const openNextServer = path . join ( outputPath , packagePath , `index.mjs` ) ;
39
41
const openNextServerBundle = path . join ( outputPath , packagePath , `handler.mjs` ) ;
40
42
@@ -45,25 +47,28 @@ export async function bundleServer(config: Config, openNextOptions: BuildOptions
45
47
format : "esm" ,
46
48
target : "esnext" ,
47
49
minify : false ,
48
- plugins : [ createFixRequiresESBuildPlugin ( config ) ] ,
50
+ plugins : [ createFixRequiresESBuildPlugin ( buildOpts ) ] ,
49
51
external : [ "./middleware/handler.mjs" , "caniuse-lite" ] ,
50
52
alias : {
51
53
// Note: we apply an empty shim to next/dist/compiled/ws because it generates two `eval`s:
52
54
// eval("require")("bufferutil");
53
55
// eval("require")("utf-8-validate");
54
- "next/dist/compiled/ws" : path . join ( config . paths . internal . templates , "shims" , " empty.js") ,
56
+ "next/dist/compiled/ws" : path . join ( buildOpts . outputDir , "cloudflare-templates/ shims/ empty.js" ) ,
55
57
// Note: we apply an empty shim to next/dist/compiled/edge-runtime since (amongst others) it generated the following `eval`:
56
58
// eval(getModuleCode)(module, module.exports, throwingRequire, params.context, ...Object.values(params.scopedContext));
57
59
// which comes from https://github.com/vercel/edge-runtime/blob/6e96b55f/packages/primitives/src/primitives/load.js#L57-L63
58
60
// QUESTION: Why did I encountered this but mhart didn't?
59
- "next/dist/compiled/edge-runtime" : path . join ( config . paths . internal . templates , "shims" , "empty.js" ) ,
61
+ "next/dist/compiled/edge-runtime" : path . join (
62
+ buildOpts . outputDir ,
63
+ "cloudflare-templates/shims/empty.js"
64
+ ) ,
60
65
// `@next/env` is a library Next.js uses for loading dotenv files, for obvious reasons we need to stub it here
61
66
// source: https://github.com/vercel/next.js/tree/0ac10d79720/packages/next-env
62
- "@next/env" : path . join ( config . paths . internal . templates , "shims" , " env.js") ,
67
+ "@next/env" : path . join ( buildOpts . outputDir , "cloudflare-templates/ shims/ env.js" ) ,
63
68
} ,
64
69
define : {
65
70
// config file used by Next.js, see: https://github.com/vercel/next.js/blob/68a7128/packages/next/src/build/utils.ts#L2137-L2139
66
- "process.env.__NEXT_PRIVATE_STANDALONE_CONFIG" : JSON . stringify ( nextConfigStr ) ,
71
+ "process.env.__NEXT_PRIVATE_STANDALONE_CONFIG" : ` ${ JSON . stringify ( nextConfig ) } ` ,
67
72
// Next.js tried to access __dirname so we need to define it
68
73
__dirname : '""' ,
69
74
// Note: we need the __non_webpack_require__ variable declared as it is used by next-server:
@@ -117,7 +122,7 @@ globalThis.__BUILD_TIMESTAMP_MS__ = ${Date.now()};
117
122
} ,
118
123
} ) ;
119
124
120
- await updateWorkerBundledCode ( openNextServerBundle , config , openNextOptions ) ;
125
+ await updateWorkerBundledCode ( openNextServerBundle , buildOpts ) ;
121
126
122
127
const isMonorepo = monorepoRoot !== appPath ;
123
128
if ( isMonorepo ) {
@@ -127,35 +132,26 @@ globalThis.__BUILD_TIMESTAMP_MS__ = ${Date.now()};
127
132
) ;
128
133
}
129
134
130
- console . log ( `\x1b[35mWorker saved in \`${ getOutputWorkerPath ( openNextOptions ) } \` 🚀\n\x1b[0m` ) ;
135
+ console . log ( `\x1b[35mWorker saved in \`${ getOutputWorkerPath ( buildOpts ) } \` 🚀\n\x1b[0m` ) ;
131
136
}
132
137
133
138
/**
134
- * This function applies string replacements on the bundled worker code necessary to get it to run in workerd
135
- *
136
- * Needless to say all the logic in this function is something we should avoid as much as possible!
137
- *
138
- * @param workerOutputFile
139
- * @param config
139
+ * This function applies patches required for the code to run on workers.
140
140
*/
141
- async function updateWorkerBundledCode (
142
- workerOutputFile : string ,
143
- config : Config ,
144
- openNextOptions : BuildOptions
145
- ) : Promise < void > {
141
+ async function updateWorkerBundledCode ( workerOutputFile : string , buildOpts : BuildOptions ) : Promise < void > {
146
142
const code = await readFile ( workerOutputFile , "utf8" ) ;
147
143
148
144
const patchedCode = await patchCodeWithValidations ( code , [
149
145
[ "require" , patches . patchRequire ] ,
150
- [ "`buildId` function" , ( code ) => patches . patchBuildId ( code , config ) ] ,
151
- [ "`loadManifest` function" , ( code ) => patches . patchLoadManifest ( code , config ) ] ,
152
- [ "next's require" , ( code ) => patches . inlineNextRequire ( code , config ) ] ,
153
- [ "`findDir` function" , ( code ) => patches . patchFindDir ( code , config ) ] ,
154
- [ "`evalManifest` function" , ( code ) => patches . inlineEvalManifest ( code , config ) ] ,
155
- [ "cacheHandler" , ( code ) => patches . patchCache ( code , openNextOptions ) ] ,
146
+ [ "`buildId` function" , ( code ) => patches . patchBuildId ( code , buildOpts ) ] ,
147
+ [ "`loadManifest` function" , ( code ) => patches . patchLoadManifest ( code , buildOpts ) ] ,
148
+ [ "next's require" , ( code ) => patches . inlineNextRequire ( code , buildOpts ) ] ,
149
+ [ "`findDir` function" , ( code ) => patches . patchFindDir ( code , buildOpts ) ] ,
150
+ [ "`evalManifest` function" , ( code ) => patches . inlineEvalManifest ( code , buildOpts ) ] ,
151
+ [ "cacheHandler" , ( code ) => patches . patchCache ( code , buildOpts ) ] ,
156
152
[
157
153
"'require(this.middlewareManifestPath)'" ,
158
- ( code ) => patches . inlineMiddlewareManifestRequire ( code , config ) ,
154
+ ( code ) => patches . inlineMiddlewareManifestRequire ( code , buildOpts ) ,
159
155
] ,
160
156
[ "exception bubbling" , patches . patchExceptionBubbling ] ,
161
157
[ "`loadInstrumentationModule` function" , patches . patchLoadInstrumentationModule ] ,
@@ -185,15 +181,15 @@ async function updateWorkerBundledCode(
185
181
await writeFile ( workerOutputFile , bundle . commitEdits ( edits ) ) ;
186
182
}
187
183
188
- function createFixRequiresESBuildPlugin ( config : Config ) : Plugin {
184
+ function createFixRequiresESBuildPlugin ( options : BuildOptions ) : Plugin {
189
185
return {
190
186
name : "replaceRelative" ,
191
187
setup ( build ) {
192
188
// Note: we (empty) shim require-hook modules as they generate problematic code that uses requires
193
189
build . onResolve (
194
190
{ filter : getCrossPlatformPathRegex ( String . raw `^\./require-hook$` , { escape : false } ) } ,
195
191
( ) => ( {
196
- path : path . join ( config . paths . internal . templates , "shims" , " empty.js") ,
192
+ path : path . join ( options . outputDir , "cloudflare-templates/ shims/ empty.js" ) ,
197
193
} )
198
194
) ;
199
195
} ,
@@ -203,9 +199,9 @@ function createFixRequiresESBuildPlugin(config: Config): Plugin {
203
199
/**
204
200
* Gets the path of the worker.js file generated by the build process
205
201
*
206
- * @param openNextOptions the open-next build options
202
+ * @param buildOpts the open-next build options
207
203
* @returns the path of the worker.js file that the build process generates
208
204
*/
209
- export function getOutputWorkerPath ( openNextOptions : BuildOptions ) : string {
210
- return path . join ( openNextOptions . outputDir , "worker.js" ) ;
205
+ export function getOutputWorkerPath ( buildOpts : BuildOptions ) : string {
206
+ return path . join ( buildOpts . outputDir , "worker.js" ) ;
211
207
}
0 commit comments