use std::path::Path;
use oj_server::optimize::{OptimizeInput, OptimizedDeps};
#[tokio::test(flavor = "multi_thread")]
async fn optimizer_prebundles_through_the_engine_with_real_rolldown() {
let repo = Path::new(env!("CARGO_MANIFEST_DIR")).join("../..");
let vite = repo.join("e2e/fixtures/start-app/node_modules/vite");
if !vite.exists() {
eprintln!("skipping: fixture vite not installed");
return;
}
let dir = tempfile::tempdir().unwrap();
let root = dir.path();
std::fs::create_dir_all(root.join("node_modules")).unwrap();
std::fs::write(root.join("package.json"), r#"{"name":"fx"}"#).unwrap();
std::os::unix::fs::symlink(&vite, root.join("node_modules/vite")).unwrap();
let dep = root.join("node_modules/plaincjs");
std::fs::create_dir_all(&dep).unwrap();
std::fs::write(
dep.join("package.json"),
r#"{"name":"plaincjs","version":"1.0.0","main":"index.js"}"#,
)
.unwrap();
std::fs::write(dep.join("index.js"), "exports.a = 1;\nexports.b = 2;\n").unwrap();
let input = || OptimizeInput {
include: vec!["plaincjs".into()],
conditions: vec!["browser".into(), "module".into(), "development".into()],
main_fields: vec!["browser".into(), "module".into(), "main".into()],
extensions: vec![".mjs".into(), ".js".into(), ".ts".into(), ".json".into()],
..Default::default()
};
let deps = OptimizedDeps::prepare(root, "0.0.1", input(), None);
let map = deps.ready().await;
let meta = map.get("plaincjs").expect("the included dep is bundled");
assert!(meta.needs_interop, "a plain-CJS bundle needs interop");
assert!(
meta.url.starts_with("/@oj-deps/") && meta.url.contains("?v="),
"versioned optimized-dep URL, got {}",
meta.url
);
let bundle = std::fs::read_to_string(deps.dir().join(&meta.file)).unwrap();
assert!(bundle.contains("export"), "an ESM pre-bundle was written");
let warm = OptimizedDeps::prepare(root, "0.0.1", input(), None)
.ready()
.await;
assert_eq!(
warm.get("plaincjs").map(|m| &m.file),
Some(&meta.file),
"warm manifest load returns the same bundle"
);
let write_dep = |name: &str, code: &str, esm: bool| {
let dir = root.join("node_modules").join(name);
std::fs::create_dir_all(&dir).unwrap();
let module_type = if esm { r#""type":"module","# } else { "" };
std::fs::write(
dir.join("package.json"),
format!(r#"{{"name":"{name}","version":"1.0.0",{module_type}"main":"index.js"}}"#),
)
.unwrap();
std::fs::write(dir.join("index.js"), code).unwrap();
};
write_dep("latedep", "export const l = 1;\n", true);
let deps = OptimizedDeps::prepare(root, "0.0.1", input(), None);
let before = deps.ready().await;
assert!(!before.contains_key("latedep"), "not scanned, not bundled");
let v0 = deps.browser_version();
let plaincjs_v0 = before["plaincjs"].url.clone();
let provisional = deps
.register_missing("latedep", false)
.expect("registration returns the future meta");
assert!(
provisional.url.starts_with("/@oj-deps/latedep.mjs?v="),
"the optimized URL is known before bundling: {}",
provisional.url
);
let wait_for = |pred: Box<dyn Fn(&oj_server::optimize::DepMap) -> bool>| {
let deps = &deps;
async move {
let deadline = std::time::Instant::now() + std::time::Duration::from_secs(60);
loop {
let m = deps.ready().await;
if pred(&m) {
break m;
}
assert!(
std::time::Instant::now() < deadline,
"the rerun never committed"
);
tokio::time::sleep(std::time::Duration::from_millis(100)).await;
}
}
};
let map = wait_for(Box::new(|m| {
m.get("latedep").is_some_and(|l| !l.file_hash.is_empty())
}))
.await;
assert_eq!(
deps.browser_version(),
v0,
"unchanged served entries: no version bump, no reload"
);
assert_eq!(
map["latedep"].url, provisional.url,
"the committed URL is the one importers already carry"
);
assert_eq!(map["plaincjs"].url, plaincjs_v0, "known URLs stay valid");
assert!(
!map["latedep"].needs_interop,
"bundle agrees with the guess"
);
write_dep(
"latedep2",
"const p = require(\"plaincjs\");\nexports.both = p.a;\n",
false,
);
deps.register_missing("latedep2", true)
.expect("second registration");
let map = wait_for(Box::new(|m| {
m.get("latedep2").is_some_and(|l| !l.file_hash.is_empty())
}))
.await;
let v2 = deps.browser_version();
assert_ne!(v2, v0, "a changed served entry bumps the version");
assert!(
map["plaincjs"].url.ends_with(&format!("?v={v2}"))
&& map["latedep"].url.ends_with(&format!("?v={v2}"))
&& map["latedep2"].url.ends_with(&format!("?v={v2}")),
"every URL moves to the batch version on reload commits"
);
let after = OptimizedDeps::prepare(root, "0.0.1", input(), None);
let warm2 = after.ready().await;
assert!(
warm2.contains_key("latedep") && warm2.contains_key("latedep2"),
"discovered deps persist in the manifest"
);
assert_eq!(after.browser_version(), v2, "persisted browser version");
let reloaded = std::sync::Arc::new(std::sync::atomic::AtomicBool::new(false));
{
let reloaded = std::sync::Arc::clone(&reloaded);
deps.set_on_commit(Box::new(move |_| {
reloaded.store(true, std::sync::atomic::Ordering::Release);
}));
}
write_dep("latedep3", "export const t = 3;\n", true);
write_dep("latedep4", "export const f = 4;\n", true);
let p3 = deps
.register_missing("latedep3", false)
.expect("third registration");
deps.register_missing("latedep4", true)
.expect("fourth registration, interop guess wrong on purpose");
let p3_version = p3
.url
.split("?v=")
.nth(1)
.expect("versioned URL")
.to_string();
let map = wait_for(Box::new(|m| {
m.get("latedep4").is_some_and(|l| !l.file_hash.is_empty())
}))
.await;
let batch = deps.browser_version();
assert_ne!(
batch, p3_version,
"the batch version is not the provisional"
);
assert_eq!(
map["latedep3"].url,
format!("/@oj-deps/latedep3.mjs?v={batch}"),
"a reload commit moves the discovered dep's URL to the batch version"
);
assert!(
reloaded.load(std::sync::atomic::Ordering::Acquire),
"the interop mismatch took the reload path"
);
assert!(
matches!(
deps.await_dep("latedep3.mjs", Some(&p3_version)).await,
oj_server::optimize::DepServe::Outdated
),
"the in-flight provisional request is Vite's outdated 504"
);
assert!(
matches!(
deps.await_dep("latedep3.mjs", Some(&batch)).await,
oj_server::optimize::DepServe::Ready
),
"the reloaded page's batch-version request serves"
);
}
#[tokio::test(flavor = "multi_thread")]
async fn a_failed_initial_run_turns_discovery_off() {
let dir = tempfile::tempdir().unwrap();
let root = dir.path();
std::fs::create_dir_all(root.join("node_modules")).unwrap();
std::fs::write(root.join("package.json"), r#"{"name":"fx"}"#).unwrap();
let deps = OptimizedDeps::prepare(root, "0.0.1", OptimizeInput::default(), None);
let map = deps.ready().await;
assert!(map.is_empty(), "no bundler: an empty pre-bundle");
assert!(!deps.may_register("lodash"), "discovery is dead");
assert!(
deps.register_missing("lodash", false).is_none(),
"no phantom optimized URL"
);
assert!(
deps.meta_now("lodash").is_none(),
"the live map stays untouched"
);
assert!(
!deps.dir().join("manifest.json").exists(),
"a failed run persists nothing"
);
}