@@ -10,6 +10,7 @@ import {
10
10
} from "types/open-next" ;
11
11
import url from "url" ;
12
12
13
+ import { compileCache } from "../build.js" ;
13
14
import logger from "../logger.js" ;
14
15
import { minifyAll } from "../minimize-js.js" ;
15
16
import { openNextReplacementPlugin } from "../plugins/replacement.js" ;
@@ -37,6 +38,14 @@ export async function createServerBundle(
37
38
const defaultFn = config . default ;
38
39
const functions = Object . entries ( config . functions ?? { } ) ;
39
40
41
+ // Recompile cache.ts as ESM if any function is using Deno runtime
42
+ if (
43
+ defaultFn . runtime === "deno" ||
44
+ functions . some ( ( [ , fn ] ) => fn . runtime === "deno" )
45
+ ) {
46
+ compileCache ( "esm" ) ;
47
+ }
48
+
40
49
const promises = functions . map ( async ( [ name , fnOptions ] ) => {
41
50
const routes = fnOptions . routes ;
42
51
routes . forEach ( ( route ) => foundRoutes . add ( route ) ) ;
@@ -134,11 +143,16 @@ async function generateBundle(
134
143
const packagePath = path . relative ( monorepoRoot , appBuildOutputPath ) ;
135
144
fs . mkdirSync ( path . join ( outputPath , packagePath ) , { recursive : true } ) ;
136
145
146
+ const ext = fnOptions . runtime === "deno" ? "mjs" : "cjs" ;
137
147
fs . copyFileSync (
138
- path . join ( outputDir , ".build" , " cache.cjs" ) ,
148
+ path . join ( outputDir , ".build" , ` cache.${ ext } ` ) ,
139
149
path . join ( outputPath , packagePath , "cache.cjs" ) ,
140
150
) ;
141
151
152
+ if ( fnOptions . runtime === "deno" ) {
153
+ addDenoJson ( outputPath , packagePath ) ;
154
+ }
155
+
142
156
// Bundle next server if necessary
143
157
const isBundled = fnOptions . experimentalBundledNextServer ?? false ;
144
158
if ( isBundled ) {
@@ -227,14 +241,18 @@ async function generateBundle(
227
241
. join ( "," ) } ] for Next version: ${ options . nextVersion } `,
228
242
) ;
229
243
}
244
+
245
+ const outfileExt = fnOptions . runtime === "deno" ? "ts" : "mjs" ;
230
246
await esbuildAsync (
231
247
{
232
248
entryPoints : [ path . join ( __dirname , "../adapters" , "server-adapter.js" ) ] ,
233
249
external : [ "next" , "./middleware.mjs" , "./next-server.runtime.prod.js" ] ,
234
- outfile : path . join ( outputPath , packagePath , " index.mjs" ) ,
250
+ outfile : path . join ( outputPath , packagePath , ` index.${ outfileExt } ` ) ,
235
251
banner : {
236
252
js : [
237
253
`globalThis.monorepoPackagePath = "${ packagePath } ";` ,
254
+ "import process from 'node:process';" ,
255
+ "import { Buffer } from 'node:buffer';" ,
238
256
"import { createRequire as topLevelCreateRequire } from 'module';" ,
239
257
"const require = topLevelCreateRequire(import.meta.url);" ,
240
258
"import bannerUrl from 'url';" ,
@@ -280,6 +298,20 @@ function shouldGenerateDockerfile(options: FunctionOptions) {
280
298
return options . override ?. generateDockerfile ?? false ;
281
299
}
282
300
301
+ // Add deno.json file to enable "bring your own node_modules" mode.
302
+ // TODO: this won't be necessary in Deno 2. See https://github.com/denoland/deno/issues/23151
303
+ function addDenoJson ( outputPath : string , packagePath : string ) {
304
+ const config = {
305
+ // Enable "bring your own node_modules" mode
306
+ // and allow `__proto__`
307
+ unstable : [ "byonm" , "fs" , "unsafe-proto" ] ,
308
+ } ;
309
+ fs . writeFileSync (
310
+ path . join ( outputPath , packagePath , "deno.json" ) ,
311
+ JSON . stringify ( config , null , 2 ) ,
312
+ ) ;
313
+ }
314
+
283
315
//TODO: check if this PR is still necessary https://github.com/sst/open-next/pull/341
284
316
function addMonorepoEntrypoint ( outputPath : string , packagePath : string ) {
285
317
// Note: in the monorepo case, the handler file is output to
0 commit comments