@@ -3,8 +3,10 @@ import path from "node:path";
3
3
4
4
import type { FunctionOptions , SplittedFunctionOptions } from "types/open-next" ;
5
5
6
+ import type { Plugin } from "esbuild" ;
6
7
import logger from "../logger.js" ;
7
8
import { minifyAll } from "../minimize-js.js" ;
9
+ import { ContentUpdater } from "../plugins/content-updater.js" ;
8
10
import { openNextReplacementPlugin } from "../plugins/replacement.js" ;
9
11
import { openNextResolvePlugin } from "../plugins/resolve.js" ;
10
12
import { getCrossPlatformPathRegex } from "../utils/regex.js" ;
@@ -14,8 +16,20 @@ import { copyTracedFiles } from "./copyTracedFiles.js";
14
16
import { generateEdgeBundle } from "./edge/createEdgeBundle.js" ;
15
17
import * as buildHelper from "./helper.js" ;
16
18
import { installDependencies } from "./installDeps.js" ;
19
+ import { type CodePatcher , applyCodePatches } from "./patch/codePatcher.js" ;
20
+
21
+ interface CodeCustomization {
22
+ // These patches are meant to apply on user and next generated code
23
+ additionalCodePatches ?: CodePatcher [ ] ;
24
+ // These plugins are meant to apply during the esbuild bundling process.
25
+ // This will only apply to OpenNext code.
26
+ additionalPlugins ?: ( contentUpdater : ContentUpdater ) => Plugin [ ] ;
27
+ }
17
28
18
- export async function createServerBundle ( options : buildHelper . BuildOptions ) {
29
+ export async function createServerBundle (
30
+ options : buildHelper . BuildOptions ,
31
+ codeCustomization ?: CodeCustomization ,
32
+ ) {
19
33
const { config } = options ;
20
34
const foundRoutes = new Set < string > ( ) ;
21
35
// Get all functions to build
@@ -36,7 +50,7 @@ export async function createServerBundle(options: buildHelper.BuildOptions) {
36
50
if ( fnOptions . runtime === "edge" ) {
37
51
await generateEdgeBundle ( name , options , fnOptions ) ;
38
52
} else {
39
- await generateBundle ( name , options , fnOptions ) ;
53
+ await generateBundle ( name , options , fnOptions , codeCustomization ) ;
40
54
}
41
55
} ) ;
42
56
@@ -101,6 +115,7 @@ async function generateBundle(
101
115
name : string ,
102
116
options : buildHelper . BuildOptions ,
103
117
fnOptions : SplittedFunctionOptions ,
118
+ codeCustomization ?: CodeCustomization ,
104
119
) {
105
120
const { appPath, appBuildOutputPath, config, outputDir, monorepoRoot } =
106
121
options ;
@@ -153,14 +168,20 @@ async function generateBundle(
153
168
buildHelper . copyEnvFile ( appBuildOutputPath , packagePath , outputPath ) ;
154
169
155
170
// Copy all necessary traced files
156
- await copyTracedFiles ( {
171
+ const { tracedFiles , manifests } = await copyTracedFiles ( {
157
172
buildOutputPath : appBuildOutputPath ,
158
173
packagePath,
159
174
outputDir : outputPath ,
160
175
routes : fnOptions . routes ?? [ "app/page.tsx" ] ,
161
176
bundledNextServer : isBundled ,
162
177
} ) ;
163
178
179
+ const additionalCodePatches = codeCustomization ?. additionalCodePatches ?? [ ] ;
180
+
181
+ await applyCodePatches ( options , tracedFiles , manifests , [
182
+ ...additionalCodePatches ,
183
+ ] ) ;
184
+
164
185
// Build Lambda code
165
186
// note: bundle in OpenNext package b/c the adapter relies on the
166
187
// "serverless-http" package which is not a dependency in user's
@@ -179,6 +200,12 @@ async function generateBundle(
179
200
180
201
const disableRouting = isBefore13413 || config . middleware ?. external ;
181
202
203
+ const updater = new ContentUpdater ( options ) ;
204
+
205
+ const additionalPlugins = codeCustomization ?. additionalPlugins
206
+ ? codeCustomization . additionalPlugins ( updater )
207
+ : [ ] ;
208
+
182
209
const plugins = [
183
210
openNextReplacementPlugin ( {
184
211
name : `requestHandlerOverride ${ name } ` ,
@@ -204,6 +231,9 @@ async function generateBundle(
204
231
fnName : name ,
205
232
overrides,
206
233
} ) ,
234
+ ...additionalPlugins ,
235
+ // The content updater plugin must be the last plugin
236
+ updater . plugin ,
207
237
] ;
208
238
209
239
const outfileExt = fnOptions . runtime === "deno" ? "ts" : "mjs" ;
0 commit comments