Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 18 additions & 26 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1529,13 +1529,22 @@ export default nativeModule;
const absolutePath = path.resolve(path.dirname(id), relativePath);

if (fs.existsSync(absolutePath)) {
const info = registerNativeFile(absolutePath);
replacements.push({
start: literalNode.start,
end: literalNode.end,
value: `"./${info.hashedFilename}"`,
});
modified = true;
if (
isIdentifier(calleeNode) &&
(calleeNode.name === "require" || customRequireVars.has(calleeNode.name))
) {
// Replace the whole require() so CommonJS importers get the
// native exports rather than the virtual module's namespace.
processNodeFile(absolutePath, node);
} else {
const info = registerNativeFile(absolutePath);
replacements.push({
start: literalNode.start,
end: literalNode.end,
value: `"./${info.hashedFilename}"`,
});
modified = true;
}
}
}
}
Expand Down Expand Up @@ -1657,14 +1666,7 @@ export default nativeModule;
const nodeFilePath = resolveNpmPackageNodeFile(packageName, path.dirname(id));

if (nodeFilePath) {
const info = registerNativeFile(nodeFilePath);
const literalNode = node.arguments[0] as LiteralNode;
replacements.push({
start: literalNode.start,
end: literalNode.end,
value: `"./${info.hashedFilename}"`,
});
modified = true;
processNodeFile(nodeFilePath, node);
}
}
}
Expand Down Expand Up @@ -1695,17 +1697,7 @@ export default nativeModule;
const result = findPlatformSpecificNativePackage(prefix, path.dirname(id));

if (result) {
const { nodeFilePath } = result;
const info = registerNativeFile(nodeFilePath);
const templateNode = node.arguments[0];
if (templateNode.start !== undefined && templateNode.end !== undefined) {
replacements.push({
start: templateNode.start,
end: templateNode.end,
value: `"./${info.hashedFilename}"`,
});
modified = true;
}
processNodeFile(result.nodeFilePath, node);
}
}
}
Expand Down
6 changes: 3 additions & 3 deletions test/napi-rs.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -179,7 +179,7 @@ describe("NAPI-RS Support", () => {
const joinFilename = joinMatch![1];

// Extract hashed filename from require call
const requireMatch = result.code.match(/require\(['"]\.\/([^'"]+)['"]\)/);
const requireMatch = result.code.match(/require\(['"]\.\/([^'"?]+)/);
expect(requireMatch).toBeDefined();
const requireFilename = requireMatch![1];

Expand Down Expand Up @@ -747,7 +747,7 @@ describe("NAPI-RS Support", () => {
expect(transformResult).toBeDefined();

// Extract hashed filename from transformed code
const match = transformResult.code.match(/require\("\.\/([^"]+\.node)"\)/);
const match = transformResult.code.match(/require\("\.\/([^"?]+\.node)/);
expect(match).toBeDefined();
const hashedFilename = match![1];

Expand Down Expand Up @@ -883,7 +883,7 @@ describe("NAPI-RS Support", () => {
expect(transformResult.code).not.toContain("`@libsql/");

// Extract the hashed filename and verify resolveId returns virtual module ID
const match = transformResult.code.match(/require\("\.\/([^"]+\.node)"\)/);
const match = transformResult.code.match(/require\("\.\/([^"?]+\.node)/);
expect(match).toBeDefined();

const resolveResult = await (plugin.resolveId as any).call(
Expand Down
72 changes: 72 additions & 0 deletions test/vite-static-import-compat.test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import fs from "node:fs";
import os from "node:os";
import path from "node:path";
import { pathToFileURL } from "node:url";
import { afterEach, beforeEach, describe, expect, it } from "vitest";
import { build as buildVite7 } from "vite7";
import vite7Package from "vite7/package.json";
Expand Down Expand Up @@ -133,5 +134,76 @@ describe.each(viteVersions)(

expectNativeAddonOutput(result);
});

it.each([
{ name: "relative path", source: "./build/Release/addon.node", comment: "" },
// NAPI-RS loaders mention their .node filename, which the transform filter requires.
{ name: "package", source: "native-pkg", comment: "// Loads native-pkg/addon.node" },
])(
"returns the native exports from a CommonJS $name require in ESM output",
async ({ comment, source }) => {
const entryPath = path.join(tempDir, "index.mjs");
const releaseDir = path.join(tempDir, "build", "Release");
fs.mkdirSync(releaseDir, { recursive: true });
fs.writeFileSync(path.join(releaseDir, "addon.node"), Buffer.from("fake native module"));
const packageDir = path.join(tempDir, "node_modules", "native-pkg");
fs.mkdirSync(packageDir, { recursive: true });
fs.writeFileSync(path.join(packageDir, "addon.node"), Buffer.from("fake package module"));
fs.writeFileSync(
path.join(packageDir, "package.json"),
JSON.stringify({ main: "addon.node", name: "native-pkg" }),
);
fs.writeFileSync(
path.join(tempDir, "lib.cjs"),
`
${comment}
const addon = require("${source}");
class Wrapped extends addon.Base {}
module.exports = { hasDefault: "default" in addon, wrapped: new Wrapped().marker };
`,
);
fs.writeFileSync(entryPath, "import lib from './lib.cjs'; export default lib;\n");

// Replace createRequire so the bundle can run without a real native binary.
const fakeNodeModule = {
enforce: "pre" as const,
load(id: string) {
if (id === "\0fake-node-module") {
return `class Base { marker = "native"; }
export function createRequire() {
return () => ({ Base });
}`;
}
},
name: "fake-node-module",
resolveId(id: string) {
if (id === "node:module" || id === "module") return "\0fake-node-module";
},
};

const outDir = path.join(tempDir, "dist");
await build({
build: {
outDir,
rollupOptions: {
input: entryPath,
output: { entryFileNames: "index.mjs", format: "es" },
},
ssr: true,
},
configFile: false,
logLevel: "silent",
plugins: [fakeNodeModule, nativeFilePlugin()],
root: tempDir,
ssr: { noExternal: true },
});

const bundledModule = await import(
/* @vite-ignore */ pathToFileURL(path.join(outDir, "index.mjs")).href
);

expect(bundledModule.default).toEqual({ hasDefault: false, wrapped: "native" });
},
);
},
);
Loading