-
Notifications
You must be signed in to change notification settings - Fork 7
[DRAFT] Make Babel plugin more "compatible" with Node.js; emit requireNodeAddons() with 3 args
#105
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 19 commits
0a106e5
6725125
c64891f
2d17eb6
8bb3e77
0ed5259
4dcf2fd
9bb9eec
4154615
ee87dd0
a60c848
41d4ebb
5596273
d23fe0b
63725af
25b55da
e5c28a7
7106775
47db302
8e1c278
4aa8549
a431e8e
446b1a4
cdf1316
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -4,9 +4,9 @@ import path from "node:path"; | |||||
| import type { PluginObj, NodePath } from "@babel/core"; | ||||||
| import * as t from "@babel/types"; | ||||||
|
|
||||||
| import { getLibraryName, isNodeApiModule, NamingStrategy } from "../path-utils"; | ||||||
| import { determineModuleContext, isNodeApiModule } from "../path-utils"; | ||||||
|
|
||||||
| type PluginOptions = { | ||||||
| export type PluginOptions = { | ||||||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Let's add an option to allow-list URL schemes which will trigger a re-write into a |
||||||
| stripPathSuffix?: boolean; | ||||||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If this is not used anymore, perhaps delete the option entirely? |
||||||
| }; | ||||||
|
|
||||||
|
|
@@ -20,12 +20,68 @@ function assertOptions(opts: unknown): asserts opts is PluginOptions { | |||||
| } | ||||||
| } | ||||||
|
|
||||||
| export function replaceWithRequireNodeAddon( | ||||||
| // This function should work with both CommonJS and ECMAScript modules, | ||||||
| // (pretending that addons are supported with ES module imports), hence it | ||||||
| // must accept following import specifiers: | ||||||
| // - "Relative specifiers" (e.g. `./build/Release/addon.node`) | ||||||
| // - "Bare specifiers", in particular | ||||||
| // - to an entry point (e.g. `@callstack/example-addon`) | ||||||
| // - any specific exported feature within | ||||||
| // - "Absolute specifiers" like `node:fs/promise` and URLs. | ||||||
| // | ||||||
| // This function should also respect the Package entry points defined in the | ||||||
| // respective "package.json" file using "main" or "exports" and "imports" | ||||||
| // fields (including conditional exports and subpath imports). | ||||||
| // - https://nodejs.org/api/packages.html#package-entry-points | ||||||
| // - https://nodejs.org/api/packages.html#subpath-imports | ||||||
| function tryResolveModulePath(id: string, from: string): string | undefined { | ||||||
| if (id.includes(":")) { | ||||||
| // This must be a prefixed "Absolute specifier". We assume its a built-in | ||||||
| // module and pass it through without any changes. For security reasons, | ||||||
| // we don't support URLs to dynamic libraries (like Node-API addons). | ||||||
| return undefined; | ||||||
| } else { | ||||||
| // TODO: Stay compatible with https://nodejs.org/api/modules.html#all-together | ||||||
| try { | ||||||
| return require.resolve(id, { paths: [from] }); | ||||||
| } catch { | ||||||
| return undefined; | ||||||
| } | ||||||
| } | ||||||
| } | ||||||
|
|
||||||
| const nodeBindingsSubdirs = [ | ||||||
|
||||||
| "./", | ||||||
| "./build/Release", | ||||||
| "./build/Debug", | ||||||
| "./build", | ||||||
| "./out/Release", | ||||||
| "./out/Debug", | ||||||
| "./Release", | ||||||
| "./Debug", | ||||||
| ]; | ||||||
| export function findNodeAddonForBindings(id: string, fromDir: string) { | ||||||
|
||||||
| const idWithExt = id.endsWith(".node") ? id : `${id}.node`; | ||||||
| // Support traversing the filesystem to find the Node-API module. | ||||||
| // Currently, we check the most common directories like `bindings` does. | ||||||
| for (const subdir of nodeBindingsSubdirs) { | ||||||
| const resolvedPath = path.join(fromDir, subdir, idWithExt); | ||||||
| if (isNodeApiModule(resolvedPath)) { | ||||||
| return resolvedPath; | ||||||
| } | ||||||
| } | ||||||
| return undefined; | ||||||
| } | ||||||
|
|
||||||
| export function replaceWithRequireNodeAddon3( | ||||||
| p: NodePath, | ||||||
| modulePath: string, | ||||||
| naming: NamingStrategy | ||||||
| resolvedPath: string, | ||||||
| originalPath: string | ||||||
| ) { | ||||||
| const requireCallArgument = getLibraryName(modulePath, naming); | ||||||
| const { packageName, relativePath } = determineModuleContext(resolvedPath); | ||||||
| const relPath = relativePath.replaceAll("\\", "/"); | ||||||
|
||||||
| const relPath = relativePath.replaceAll("\\", "/"); | |
| const relativePosixPath = relativePath.replaceAll("\\", "/"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Discussed this in-person: We should move this into determineModuleContext instead.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
for-of loop please 😊 I know it always does, but nothing actually guaranties that the callback will be called synchronously.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also, I'd suggest using
satisfiesinstead ofasin a place like this.