From 2d4f74ff94bb16510c74aa01e17b2a39d3824183 Mon Sep 17 00:00:00 2001 From: wanxiankai Date: Thu, 13 Aug 2026 11:14:02 +0800 Subject: [PATCH] fix: verify native prebuild fixtures --- .changeset/calm-bears-resolve.md | 5 ++++ .../host/src/node/babel-plugin/plugin.test.ts | 2 +- packages/host/src/node/babel-plugin/plugin.ts | 10 ++++++++ packages/node-addon-examples/package.json | 1 + .../scripts/verify-prebuilds.mts | 24 ++++++++++++++++++- pnpm-lock.yaml | 3 +++ 6 files changed, 43 insertions(+), 2 deletions(-) create mode 100644 .changeset/calm-bears-resolve.md diff --git a/.changeset/calm-bears-resolve.md b/.changeset/calm-bears-resolve.md new file mode 100644 index 00000000..94aa61c0 --- /dev/null +++ b/.changeset/calm-bears-resolve.md @@ -0,0 +1,5 @@ +--- +"react-native-node-api": patch +--- + +Preserve Node.js module resolution precedence when a JavaScript file and native addon share a basename. diff --git a/packages/host/src/node/babel-plugin/plugin.test.ts b/packages/host/src/node/babel-plugin/plugin.test.ts index 7dae2979..d3fe5fac 100644 --- a/packages/host/src/node/babel-plugin/plugin.test.ts +++ b/packages/host/src/node/babel-plugin/plugin.test.ts @@ -129,7 +129,7 @@ describe("plugin", () => { itTransforms("and does not touch required JS files", { files: { "package.json": `{ "name": "my-package" }`, - // TODO: Add a ./my-addon.node to make this test complete + "my-addon.node": "// This is supposed to be a binary file", "my-addon.js": "// Some JS file", "index.js": ` const addon = require('./my-addon'); diff --git a/packages/host/src/node/babel-plugin/plugin.ts b/packages/host/src/node/babel-plugin/plugin.ts index 45e269e9..9829419f 100644 --- a/packages/host/src/node/babel-plugin/plugin.ts +++ b/packages/host/src/node/babel-plugin/plugin.ts @@ -1,4 +1,5 @@ import assert from "node:assert/strict"; +import { createRequire } from "node:module"; import path from "node:path"; import type { PluginObj, NodePath } from "@babel/core"; @@ -101,6 +102,7 @@ export function plugin(): PluginObj { } } else if ( !path.isAbsolute(id) && + !resolvesToNonNodeModule(id, this.filename) && isNodeApiModule(path.join(from, id)) ) { const relativePath = path.join(from, id); @@ -114,3 +116,11 @@ export function plugin(): PluginObj { }, }; } + +function resolvesToNonNodeModule(id: string, filename: string): boolean { + try { + return !createRequire(filename).resolve(id).endsWith(".node"); + } catch { + return false; + } +} diff --git a/packages/node-addon-examples/package.json b/packages/node-addon-examples/package.json index 0d2d129b..1f530fe5 100644 --- a/packages/node-addon-examples/package.json +++ b/packages/node-addon-examples/package.json @@ -29,6 +29,7 @@ "bootstrap": "node --run copy-and-build" }, "devDependencies": { + "@expo/plist": "0.4.7", "cmake-rn": "workspace:*", "node-addon-examples": "github:nodejs/node-addon-examples#4b7dd86a85644610e6de80154df9acac9329b509", "gyp-to-cmake": "workspace:*", diff --git a/packages/node-addon-examples/scripts/verify-prebuilds.mts b/packages/node-addon-examples/scripts/verify-prebuilds.mts index cdbd312b..c00a846e 100644 --- a/packages/node-addon-examples/scripts/verify-prebuilds.mts +++ b/packages/node-addon-examples/scripts/verify-prebuilds.mts @@ -2,6 +2,8 @@ import fs from "node:fs"; import assert from "node:assert/strict"; import path from "node:path"; +import plistModule from "@expo/plist"; + import { EXAMPLES_DIR } from "./cmake-projects.mjs"; const EXPECTED_ANDROID_ARCHS = ["armeabi-v7a", "arm64-v8a", "x86_64", "x86"]; @@ -65,7 +67,27 @@ async function verifyApplePrebuild(dirent: fs.Dirent) { "Expected only directory and files in framework", ); if (file.name === "Info.plist") { - // TODO: Verify the contents of the Info.plist file + const libraryName = path.basename(frameworkDir, ".framework"); + const infoPlist: unknown = plistModule.default.parse( + await fs.promises.readFile( + path.join(frameworkDir, file.name), + "utf8", + ), + ); + assert( + typeof infoPlist === "object" && infoPlist !== null, + "Expected Info.plist to contain a dictionary", + ); + assert("CFBundleExecutable" in infoPlist); + assert("CFBundleIdentifier" in infoPlist); + assert.equal(infoPlist.CFBundleExecutable, libraryName); + assert.equal( + infoPlist.CFBundleIdentifier, + `com.callstackincubator.node-api.${libraryName}`.replace( + /[^A-Za-z0-9-.]/g, + "-", + ), + ); continue; } else { assert( diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 6a99748a..5527e060 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -281,6 +281,9 @@ importers: specifier: workspace:* version: link:../host devDependencies: + '@expo/plist': + specifier: 0.4.7 + version: 0.4.7 cmake-rn: specifier: workspace:* version: link:../cmake-rn