Skip to content
Closed
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
6 changes: 6 additions & 0 deletions changelog.d/8817-compiled-package-builtin-import.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
Added regression coverage for Node builtin named imports used from natively
compiled dependencies. The exact `@hono/node-server` fallback from
`options.createServer` to its module-scope `http.createServer` import now has an
offline compiler fixture and a real-package listen/fetch/close release smoke,
covering both `http` and `node:http` spellings without relying on app-level
imports.
114 changes: 114 additions & 0 deletions crates/perry/tests/issue_8749_compiled_package_builtin_import.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
//! Regression test for #8749: a Node builtin named import used from a
//! `compilePackages` dependency must retain its runtime binding.
//!
//! `@hono/node-server` imports `createServer` from `http`, selects it through a
//! module-scope fallback (`options.createServer || createServerHTTP`), and calls
//! the selected function later from `serve()`. App-level imports already
//! worked; the binding was lost specifically while compiling the dependency.

use std::path::PathBuf;
use std::process::Command;

fn perry_bin() -> PathBuf {
PathBuf::from(env!("CARGO_BIN_EXE_perry"))
}

#[test]
fn builtin_named_import_survives_module_scope_fallback_in_compiled_package() {
let dir = tempfile::tempdir().expect("tempdir");
let root = dir.path();

std::fs::write(
root.join("package.json"),
r#"{
"name": "compiled-builtin-import-consumer",
"private": true,
"type": "module",
"perry": {
"compilePackages": ["fake-node-server"],
"allow": { "compilePackages": ["fake-node-server"] }
}
}"#,
)
.expect("write consumer package.json");

let pkg = root.join("node_modules").join("fake-node-server");
std::fs::create_dir_all(&pkg).expect("mkdir fake-node-server");
std::fs::write(
pkg.join("package.json"),
r#"{
"name": "fake-node-server",
"version": "1.0.0",
"type": "module",
"exports": "./index.mjs"
}"#,
)
.expect("write dependency package.json");
std::fs::write(
pkg.join("index.mjs"),
r#"
import { createServer as createServerHTTP } from "http";
import { createServer as createServerNodeHTTP } from "node:http";

const options = {};
const selectedHTTP = options.createServer || createServerHTTP;
const selectedNodeHTTP = options.createServer || createServerNodeHTTP;

export function inspectBindings() {
const serverHTTP = selectedHTTP({}, () => {});
const serverNodeHTTP = selectedNodeHTTP({}, () => {});
return [
typeof createServerHTTP,
typeof createServerNodeHTTP,
typeof selectedHTTP,
typeof selectedNodeHTTP,
typeof serverHTTP.listen,
typeof serverNodeHTTP.listen,
].join(",");
}
"#,
)
.expect("write compiled dependency");

let entry = root.join("main.ts");
std::fs::write(
&entry,
r#"
import { inspectBindings } from "fake-node-server";
console.log(inspectBindings());
process.exit(0);
"#,
)
.expect("write entry");

let output = root.join("main_bin");
let compile = Command::new(perry_bin())
.current_dir(root)
.arg("compile")
.arg(&entry)
.arg("-o")
.arg(&output)
.arg("--no-cache")
.output()
.expect("run perry compile");
assert!(
compile.status.success(),
"perry compile failed\nstdout:\n{}\nstderr:\n{}",
String::from_utf8_lossy(&compile.stdout),
String::from_utf8_lossy(&compile.stderr)
);

let run = Command::new(&output).output().expect("run compiled binary");
assert!(
run.status.success(),
"compiled binary failed\nstatus: {:?}\nstdout:\n{}\nstderr:\n{}",
run.status,
String::from_utf8_lossy(&run.stdout),
String::from_utf8_lossy(&run.stderr)
);
assert_eq!(
String::from_utf8_lossy(&run.stdout),
"function,function,function,function,function,function\n",
"both builtin spellings must stay bound through the dependency's module global"
);
}
16 changes: 16 additions & 0 deletions tests/release/packages/hono-node-server/entry.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// Issue #8749: @hono/node-server selects its imported node:http factory
// through `options.createServer || createServerHTTP` inside compiled package
// code. Exercise the real package through listen, fetch, response, and close.
import { serve } from "@hono/node-server";

const port = 38139;
const server = serve({
fetch: () => new Response("ok"),
port,
}, async () => {
const response = await fetch(`http://127.0.0.1:${port}/`);
console.log(`status=${response.status}`);
console.log(`body=${await response.text()}`);
server.close();
process.exit(0);
});
2 changes: 2 additions & 0 deletions tests/release/packages/hono-node-server/expected.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
status=200
body=ok
10 changes: 10 additions & 0 deletions tests/release/packages/hono-node-server/fixture.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
#!/usr/bin/env bash
# Issue #8749: real-package smoke for @hono/node-server's module-scope
# `options.createServer || createServerHTTP` binding under compilePackages.

set -uo pipefail
cd "$(dirname "$0")"
. "$(dirname "$0")/../_fixture_lib.sh"

fixture_setup "hono-node-server" || exit 1
fixture_compile_run_diff "hono-node-server"
37 changes: 37 additions & 0 deletions tests/release/packages/hono-node-server/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

17 changes: 17 additions & 0 deletions tests/release/packages/hono-node-server/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
"name": "perry-release-fixture-hono-node-server",
"version": "0.0.0",
"private": true,
"type": "module",
"description": "Tier-3 fixture for @hono/node-server's compiled-package Node builtin imports.",
"dependencies": {
"@hono/node-server": "1.19.17",
"hono": "4.13.4"
},
"perry": {
"compilePackages": ["@hono/node-server", "hono"],
"allow": {
"compilePackages": ["@hono/node-server", "hono"]
}
}
}
Loading