next-bun-compile 0.2.2 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -54,6 +54,18 @@ bun run build # Builds Next.js + compiles to ./server
54
54
 
55
55
  The binary is fully self-contained — static assets, public files, and the Next.js server are all embedded. Just copy it anywhere and run.
56
56
 
57
+ ### Cross-Compilation
58
+
59
+ Any flags passed to `next-bun-compile` are forwarded to `bun build --compile`. Use `--target` to cross-compile for a different platform:
60
+
61
+ ```bash
62
+ next-bun-compile --target=bun-linux-x64
63
+ next-bun-compile --target=bun-linux-arm64
64
+ next-bun-compile --target=bun-windows-x64
65
+ ```
66
+
67
+ See the [Bun cross-compilation docs](https://bun.sh/docs/bundler/executables#cross-compile) for all available targets.
68
+
57
69
  ### Environment Variables
58
70
 
59
71
  | Variable | Default | Description |
package/dist/cli.js CHANGED
@@ -67,9 +67,23 @@ function generateStubs(standaloneDir) {
67
67
  console.log(`next-bun-compile: Created ${count} module stubs`);
68
68
  }
69
69
  }
70
+ function patchRequireHook(standaloneDir) {
71
+ const hookPath = join(standaloneDir, "node_modules/next/dist/server/require-hook.js");
72
+ if (!existsSync(hookPath))
73
+ return;
74
+ let content = readFileSync(hookPath, "utf-8");
75
+ const target = "let resolve = process.env.NEXT_MINIMAL ? __non_webpack_require__.resolve : require.resolve;";
76
+ if (!content.includes(target))
77
+ return;
78
+ content = content.replace(target, `let _resolve = process.env.NEXT_MINIMAL ? __non_webpack_require__.resolve : require.resolve;
79
+ let resolve = (id) => { try { return _resolve(id); } catch { return ''; } };`);
80
+ writeFileSync(hookPath, content);
81
+ console.log("next-bun-compile: Patched require-hook.js for compiled binary compatibility");
82
+ }
70
83
  function generateEntryPoint(options) {
71
84
  const { standaloneDir, distDir, projectDir } = options;
72
85
  generateStubs(standaloneDir);
86
+ patchRequireHook(standaloneDir);
73
87
  const staticDir = join(distDir, "static");
74
88
  const staticFiles = walkDir(staticDir).map((f) => ({
75
89
  ...f,
@@ -80,13 +94,18 @@ function generateEntryPoint(options) {
80
94
  ...f,
81
95
  urlPath: `/${f.relativePath.replace(/\\/g, "/")}`
82
96
  }));
97
+ const standaloneNextDir = join(standaloneDir, ".next");
98
+ const runtimeFiles = walkDir(standaloneNextDir).map((f) => ({
99
+ ...f,
100
+ urlPath: `__runtime/.next/${f.relativePath.replace(/\\/g, "/")}`
101
+ }));
83
102
  const ctx = JSON.parse(readFileSync(join(distDir, "bun-compile-ctx.json"), "utf-8"));
84
103
  const { assetPrefix } = ctx;
85
- const assetsToEmbed = assetPrefix ? publicFiles : [...staticFiles, ...publicFiles];
104
+ const assetsToEmbed = assetPrefix ? [...publicFiles, ...runtimeFiles] : [...staticFiles, ...publicFiles, ...runtimeFiles];
86
105
  if (assetPrefix) {
87
106
  console.log(`next-bun-compile: assetPrefix detected — skipping ${staticFiles.length} static assets (served from CDN)`);
88
107
  }
89
- console.log(`next-bun-compile: Embedding ${assetsToEmbed.length} assets (${assetPrefix ? "public only" : `${staticFiles.length} static + ${publicFiles.length} public`})`);
108
+ console.log(`next-bun-compile: Embedding ${assetsToEmbed.length} assets (${staticFiles.length} static + ${publicFiles.length} public + ${runtimeFiles.length} runtime)`);
90
109
  const imports = [];
91
110
  const mapEntries = [];
92
111
  for (const asset of assetsToEmbed) {
@@ -108,7 +127,14 @@ ${mapEntries.join(`
108
127
  throw new Error("next-bun-compile: Could not extract nextConfig from standalone server.js");
109
128
  }
110
129
  const assetExtractions = assetsToEmbed.map((a) => {
111
- const diskPath = a.urlPath.startsWith("/_next/static/") ? ".next/static/" + a.relativePath : "public/" + a.relativePath;
130
+ let diskPath;
131
+ if (a.urlPath.startsWith("__runtime/")) {
132
+ diskPath = a.urlPath.slice("__runtime/".length);
133
+ } else if (a.urlPath.startsWith("/_next/static/")) {
134
+ diskPath = ".next/static/" + a.relativePath;
135
+ } else {
136
+ diskPath = "public/" + a.relativePath;
137
+ }
112
138
  return [a.urlPath, diskPath];
113
139
  });
114
140
  const serverEntry = `import { assetMap } from "./assets.generated.js";
@@ -158,7 +184,7 @@ extractAssets().then(() => {
158
184
  import { execFileSync } from "node:child_process";
159
185
  import { join as join2 } from "node:path";
160
186
  function compile(options) {
161
- const { standaloneDir, outfile } = options;
187
+ const { standaloneDir, outfile, extraArgs = [] } = options;
162
188
  const entryPoint = join2(standaloneDir, "server-entry.js");
163
189
  const args = [
164
190
  "build",
@@ -175,7 +201,8 @@ function compile(options) {
175
201
  "--define",
176
202
  'process.env.NEXT_RUNTIME="nodejs"',
177
203
  "--outfile",
178
- outfile
204
+ outfile,
205
+ ...extraArgs
179
206
  ];
180
207
  console.log(`next-bun-compile: Compiling to ${outfile}...`);
181
208
  execFileSync("bun", args, { stdio: "inherit" });
@@ -185,6 +212,7 @@ function compile(options) {
185
212
  // src/cli.ts
186
213
  import { existsSync as existsSync2 } from "node:fs";
187
214
  import { join as join3, resolve } from "node:path";
215
+ var extraArgs = process.argv.slice(2);
188
216
  var projectDir = resolve(".");
189
217
  var distDir = join3(projectDir, ".next");
190
218
  var standaloneDir = join3(distDir, "standalone");
@@ -197,4 +225,4 @@ if (existsSync2(ctxPath)) {
197
225
  console.log("next-bun-compile: Using build context from adapter");
198
226
  }
199
227
  generateEntryPoint({ standaloneDir, distDir, projectDir });
200
- compile({ standaloneDir, outfile: join3(projectDir, "server") });
228
+ compile({ standaloneDir, outfile: join3(projectDir, "server"), extraArgs });
package/dist/compile.js CHANGED
@@ -5,7 +5,7 @@ var __require = /* @__PURE__ */ createRequire(import.meta.url);
5
5
  import { execFileSync } from "node:child_process";
6
6
  import { join } from "node:path";
7
7
  function compile(options) {
8
- const { standaloneDir, outfile } = options;
8
+ const { standaloneDir, outfile, extraArgs = [] } = options;
9
9
  const entryPoint = join(standaloneDir, "server-entry.js");
10
10
  const args = [
11
11
  "build",
@@ -22,7 +22,8 @@ function compile(options) {
22
22
  "--define",
23
23
  'process.env.NEXT_RUNTIME="nodejs"',
24
24
  "--outfile",
25
- outfile
25
+ outfile,
26
+ ...extraArgs
26
27
  ];
27
28
  console.log(`next-bun-compile: Compiling to ${outfile}...`);
28
29
  execFileSync("bun", args, { stdio: "inherit" });
package/dist/generate.js CHANGED
@@ -66,9 +66,23 @@ function generateStubs(standaloneDir) {
66
66
  console.log(`next-bun-compile: Created ${count} module stubs`);
67
67
  }
68
68
  }
69
+ function patchRequireHook(standaloneDir) {
70
+ const hookPath = join(standaloneDir, "node_modules/next/dist/server/require-hook.js");
71
+ if (!existsSync(hookPath))
72
+ return;
73
+ let content = readFileSync(hookPath, "utf-8");
74
+ const target = "let resolve = process.env.NEXT_MINIMAL ? __non_webpack_require__.resolve : require.resolve;";
75
+ if (!content.includes(target))
76
+ return;
77
+ content = content.replace(target, `let _resolve = process.env.NEXT_MINIMAL ? __non_webpack_require__.resolve : require.resolve;
78
+ let resolve = (id) => { try { return _resolve(id); } catch { return ''; } };`);
79
+ writeFileSync(hookPath, content);
80
+ console.log("next-bun-compile: Patched require-hook.js for compiled binary compatibility");
81
+ }
69
82
  function generateEntryPoint(options) {
70
83
  const { standaloneDir, distDir, projectDir } = options;
71
84
  generateStubs(standaloneDir);
85
+ patchRequireHook(standaloneDir);
72
86
  const staticDir = join(distDir, "static");
73
87
  const staticFiles = walkDir(staticDir).map((f) => ({
74
88
  ...f,
@@ -79,13 +93,18 @@ function generateEntryPoint(options) {
79
93
  ...f,
80
94
  urlPath: `/${f.relativePath.replace(/\\/g, "/")}`
81
95
  }));
96
+ const standaloneNextDir = join(standaloneDir, ".next");
97
+ const runtimeFiles = walkDir(standaloneNextDir).map((f) => ({
98
+ ...f,
99
+ urlPath: `__runtime/.next/${f.relativePath.replace(/\\/g, "/")}`
100
+ }));
82
101
  const ctx = JSON.parse(readFileSync(join(distDir, "bun-compile-ctx.json"), "utf-8"));
83
102
  const { assetPrefix } = ctx;
84
- const assetsToEmbed = assetPrefix ? publicFiles : [...staticFiles, ...publicFiles];
103
+ const assetsToEmbed = assetPrefix ? [...publicFiles, ...runtimeFiles] : [...staticFiles, ...publicFiles, ...runtimeFiles];
85
104
  if (assetPrefix) {
86
105
  console.log(`next-bun-compile: assetPrefix detected — skipping ${staticFiles.length} static assets (served from CDN)`);
87
106
  }
88
- console.log(`next-bun-compile: Embedding ${assetsToEmbed.length} assets (${assetPrefix ? "public only" : `${staticFiles.length} static + ${publicFiles.length} public`})`);
107
+ console.log(`next-bun-compile: Embedding ${assetsToEmbed.length} assets (${staticFiles.length} static + ${publicFiles.length} public + ${runtimeFiles.length} runtime)`);
89
108
  const imports = [];
90
109
  const mapEntries = [];
91
110
  for (const asset of assetsToEmbed) {
@@ -107,7 +126,14 @@ ${mapEntries.join(`
107
126
  throw new Error("next-bun-compile: Could not extract nextConfig from standalone server.js");
108
127
  }
109
128
  const assetExtractions = assetsToEmbed.map((a) => {
110
- const diskPath = a.urlPath.startsWith("/_next/static/") ? ".next/static/" + a.relativePath : "public/" + a.relativePath;
129
+ let diskPath;
130
+ if (a.urlPath.startsWith("__runtime/")) {
131
+ diskPath = a.urlPath.slice("__runtime/".length);
132
+ } else if (a.urlPath.startsWith("/_next/static/")) {
133
+ diskPath = ".next/static/" + a.relativePath;
134
+ } else {
135
+ diskPath = "public/" + a.relativePath;
136
+ }
111
137
  return [a.urlPath, diskPath];
112
138
  });
113
139
  const serverEntry = `import { assetMap } from "./assets.generated.js";
package/dist/index.js CHANGED
@@ -66,9 +66,23 @@ function generateStubs(standaloneDir) {
66
66
  console.log(`next-bun-compile: Created ${count} module stubs`);
67
67
  }
68
68
  }
69
+ function patchRequireHook(standaloneDir) {
70
+ const hookPath = join(standaloneDir, "node_modules/next/dist/server/require-hook.js");
71
+ if (!existsSync(hookPath))
72
+ return;
73
+ let content = readFileSync(hookPath, "utf-8");
74
+ const target = "let resolve = process.env.NEXT_MINIMAL ? __non_webpack_require__.resolve : require.resolve;";
75
+ if (!content.includes(target))
76
+ return;
77
+ content = content.replace(target, `let _resolve = process.env.NEXT_MINIMAL ? __non_webpack_require__.resolve : require.resolve;
78
+ let resolve = (id) => { try { return _resolve(id); } catch { return ''; } };`);
79
+ writeFileSync(hookPath, content);
80
+ console.log("next-bun-compile: Patched require-hook.js for compiled binary compatibility");
81
+ }
69
82
  function generateEntryPoint(options) {
70
83
  const { standaloneDir, distDir, projectDir } = options;
71
84
  generateStubs(standaloneDir);
85
+ patchRequireHook(standaloneDir);
72
86
  const staticDir = join(distDir, "static");
73
87
  const staticFiles = walkDir(staticDir).map((f) => ({
74
88
  ...f,
@@ -79,13 +93,18 @@ function generateEntryPoint(options) {
79
93
  ...f,
80
94
  urlPath: `/${f.relativePath.replace(/\\/g, "/")}`
81
95
  }));
96
+ const standaloneNextDir = join(standaloneDir, ".next");
97
+ const runtimeFiles = walkDir(standaloneNextDir).map((f) => ({
98
+ ...f,
99
+ urlPath: `__runtime/.next/${f.relativePath.replace(/\\/g, "/")}`
100
+ }));
82
101
  const ctx = JSON.parse(readFileSync(join(distDir, "bun-compile-ctx.json"), "utf-8"));
83
102
  const { assetPrefix } = ctx;
84
- const assetsToEmbed = assetPrefix ? publicFiles : [...staticFiles, ...publicFiles];
103
+ const assetsToEmbed = assetPrefix ? [...publicFiles, ...runtimeFiles] : [...staticFiles, ...publicFiles, ...runtimeFiles];
85
104
  if (assetPrefix) {
86
105
  console.log(`next-bun-compile: assetPrefix detected — skipping ${staticFiles.length} static assets (served from CDN)`);
87
106
  }
88
- console.log(`next-bun-compile: Embedding ${assetsToEmbed.length} assets (${assetPrefix ? "public only" : `${staticFiles.length} static + ${publicFiles.length} public`})`);
107
+ console.log(`next-bun-compile: Embedding ${assetsToEmbed.length} assets (${staticFiles.length} static + ${publicFiles.length} public + ${runtimeFiles.length} runtime)`);
89
108
  const imports = [];
90
109
  const mapEntries = [];
91
110
  for (const asset of assetsToEmbed) {
@@ -107,7 +126,14 @@ ${mapEntries.join(`
107
126
  throw new Error("next-bun-compile: Could not extract nextConfig from standalone server.js");
108
127
  }
109
128
  const assetExtractions = assetsToEmbed.map((a) => {
110
- const diskPath = a.urlPath.startsWith("/_next/static/") ? ".next/static/" + a.relativePath : "public/" + a.relativePath;
129
+ let diskPath;
130
+ if (a.urlPath.startsWith("__runtime/")) {
131
+ diskPath = a.urlPath.slice("__runtime/".length);
132
+ } else if (a.urlPath.startsWith("/_next/static/")) {
133
+ diskPath = ".next/static/" + a.relativePath;
134
+ } else {
135
+ diskPath = "public/" + a.relativePath;
136
+ }
111
137
  return [a.urlPath, diskPath];
112
138
  });
113
139
  const serverEntry = `import { assetMap } from "./assets.generated.js";
@@ -157,7 +183,7 @@ extractAssets().then(() => {
157
183
  import { execFileSync } from "node:child_process";
158
184
  import { join as join2 } from "node:path";
159
185
  function compile(options) {
160
- const { standaloneDir, outfile } = options;
186
+ const { standaloneDir, outfile, extraArgs = [] } = options;
161
187
  const entryPoint = join2(standaloneDir, "server-entry.js");
162
188
  const args = [
163
189
  "build",
@@ -174,7 +200,8 @@ function compile(options) {
174
200
  "--define",
175
201
  'process.env.NEXT_RUNTIME="nodejs"',
176
202
  "--outfile",
177
- outfile
203
+ outfile,
204
+ ...extraArgs
178
205
  ];
179
206
  console.log(`next-bun-compile: Compiling to ${outfile}...`);
180
207
  execFileSync("bun", args, { stdio: "inherit" });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "next-bun-compile",
3
- "version": "0.2.2",
3
+ "version": "0.4.0",
4
4
  "description": "Next.js Build Adapter that compiles your app into a Bun single-file executable",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",