Skip to content

Commit 3a2b1b9

Browse files
clichedmoogclaude
andauthored
fix(build): auto-filter non-Linux platform-specific native binaries (#1117)
* fix(build): auto-filter non-Linux platform-specific native binaries from Lambda bundles Native packages like @swc/core-darwin-arm64 (~22MB) are included by Next.js output file tracing when building on macOS but are never needed on Lambda (Linux). This adds automatic detection and exclusion of darwin/win32/freebsd/android platform binaries during the traced files copy step, reducing bundle size significantly. * fix(build): auto-externalize .node native binary imports in esbuild Add empty loader for .node files in both esbuildSync and esbuildAsync, preventing build crashes when packages like @swc/core include platform-specific native binaries that esbuild cannot bundle. Uses loader: { ".node": "empty" } approach which works for both sync and async builds, replacing .node imports with empty modules. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix(build): address review feedback — remove android, add bypass env, split esbuild change - Remove android from platform filter list - Add OPEN_NEXT_SKIP_PLATFORM_FILTER env variable to bypass the filter - Revert esbuild .node loader change (to be addressed in a separate PR) --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
1 parent e49782a commit 3a2b1b9

3 files changed

Lines changed: 129 additions & 1 deletion

File tree

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@opennextjs/aws": patch
3+
---
4+
5+
Auto-filter non-Linux platform-specific native binaries (e.g. @swc/core-darwin-arm64) from Lambda bundles during traced files copy

packages/open-next/src/build/copyTracedFiles.ts

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,18 @@ export function isExcluded(srcPath: string): boolean {
7373
);
7474
}
7575

76+
const NON_LINUX_PLATFORMS = ["darwin", "win32", "freebsd"];
77+
78+
const platformPattern = NON_LINUX_PLATFORMS.join("|");
79+
const nonLinuxPlatformRegex = getCrossPlatformPathRegex(
80+
`/node_modules/(?:@[^/]+/)?(?:[^/]+-)?(${platformPattern})-[^/]+/`,
81+
{ escape: false },
82+
);
83+
84+
export function isNonLinuxPlatformPackage(srcPath: string): boolean {
85+
return nonLinuxPlatformRegex.test(srcPath);
86+
}
87+
7688
function copyPatchFile(outputDir: string) {
7789
const patchFile = path.join(__dirname, "patch", "patchedAsyncStorage.js");
7890
const outputPatchFile = path.join(outputDir, "patchedAsyncStorage.cjs");
@@ -278,11 +290,26 @@ File ${serverPath} does not exist
278290
const tracedFiles: string[] = [];
279291
const erroredFiles: string[] = [];
280292
//Actually copy the files
293+
const skippedPlatformPackages = new Set<string>();
281294
filesToCopy.forEach((to, from) => {
282295
// We don't want to copy excluded packages (e.g. sharp)
283296
if (isExcluded(from)) {
284297
return;
285298
}
299+
// Skip non-Linux platform-specific native binaries (e.g. @swc/core-darwin-arm64)
300+
// Set OPEN_NEXT_SKIP_PLATFORM_FILTER=true to bypass this check
301+
if (
302+
!process.env.OPEN_NEXT_SKIP_PLATFORM_FILTER &&
303+
isNonLinuxPlatformPackage(from)
304+
) {
305+
const match = from.match(
306+
/node_modules\/(?:\.pnpm\/.*\/node_modules\/)?((?:@[^/]+\/)?[^/]+)/,
307+
);
308+
if (match) {
309+
skippedPlatformPackages.add(match[1]);
310+
}
311+
return;
312+
}
286313
tracedFiles.push(to);
287314
mkdirSync(path.dirname(to), { recursive: true });
288315
let symlink = null;
@@ -314,6 +341,13 @@ File ${serverPath} does not exist
314341
}
315342
});
316343

344+
if (skippedPlatformPackages.size > 0) {
345+
logger.debug(
346+
"Skipped non-Linux platform packages:",
347+
[...skippedPlatformPackages].join(", "),
348+
);
349+
}
350+
317351
readdirSync(standaloneNextDir)
318352
.filter(
319353
(fileOrDir) =>

packages/tests-unit/tests/build/copyTracedFiles.test.ts

Lines changed: 90 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
1-
import { isExcluded } from "@opennextjs/aws/build/copyTracedFiles.js";
1+
import {
2+
isExcluded,
3+
isNonLinuxPlatformPackage,
4+
} from "@opennextjs/aws/build/copyTracedFiles.js";
25

36
describe("isExcluded", () => {
47
test("should exclude sharp", () => {
@@ -40,3 +43,89 @@ describe("isExcluded", () => {
4043
).toBe(false);
4144
});
4245
});
46+
47+
describe("isNonLinuxPlatformPackage", () => {
48+
test("should exclude darwin packages", () => {
49+
expect(
50+
isNonLinuxPlatformPackage(
51+
"/project/node_modules/@swc/core-darwin-arm64/swc.darwin-arm64.node",
52+
),
53+
).toBe(true);
54+
expect(
55+
isNonLinuxPlatformPackage(
56+
"/project/node_modules/@esbuild/darwin-x64/bin/esbuild",
57+
),
58+
).toBe(true);
59+
});
60+
61+
test("should exclude win32 packages", () => {
62+
expect(
63+
isNonLinuxPlatformPackage(
64+
"/project/node_modules/@swc/core-win32-x64-msvc/swc.win32-x64-msvc.node",
65+
),
66+
).toBe(true);
67+
});
68+
69+
test("should exclude freebsd packages", () => {
70+
expect(
71+
isNonLinuxPlatformPackage(
72+
"/project/node_modules/@rollup/rollup-freebsd-x64/rollup.freebsd-x64.node",
73+
),
74+
).toBe(true);
75+
});
76+
77+
test("should keep linux packages", () => {
78+
expect(
79+
isNonLinuxPlatformPackage(
80+
"/project/node_modules/@swc/core-linux-x64-gnu/swc.linux-x64-gnu.node",
81+
),
82+
).toBe(false);
83+
expect(
84+
isNonLinuxPlatformPackage(
85+
"/project/node_modules/@swc/core-linux-arm64-gnu/swc.linux-arm64-gnu.node",
86+
),
87+
).toBe(false);
88+
expect(
89+
isNonLinuxPlatformPackage(
90+
"/project/node_modules/@esbuild/linux-x64/bin/esbuild",
91+
),
92+
).toBe(false);
93+
});
94+
95+
test("should keep non-platform packages", () => {
96+
expect(
97+
isNonLinuxPlatformPackage("/project/node_modules/@swc/core/index.js"),
98+
).toBe(false);
99+
expect(
100+
isNonLinuxPlatformPackage(
101+
"/project/node_modules/next/dist/server/next-server.js",
102+
),
103+
).toBe(false);
104+
});
105+
106+
test("should work with pnpm store paths", () => {
107+
expect(
108+
isNonLinuxPlatformPackage(
109+
"/project/node_modules/.pnpm/@swc+core-darwin-arm64@1.3.0/node_modules/@swc/core-darwin-arm64/swc.node",
110+
),
111+
).toBe(true);
112+
expect(
113+
isNonLinuxPlatformPackage(
114+
"/project/node_modules/.pnpm/@swc+core-linux-x64-gnu@1.3.0/node_modules/@swc/core-linux-x64-gnu/swc.node",
115+
),
116+
).toBe(false);
117+
});
118+
119+
test("should handle unscoped platform packages", () => {
120+
expect(
121+
isNonLinuxPlatformPackage(
122+
"/project/node_modules/turbo-darwin-arm64/bin/turbo",
123+
),
124+
).toBe(true);
125+
expect(
126+
isNonLinuxPlatformPackage(
127+
"/project/node_modules/turbo-linux-x64/bin/turbo",
128+
),
129+
).toBe(false);
130+
});
131+
});

0 commit comments

Comments
 (0)