use std::fs;
use super::{build_app, js_under, scratch, write_files};
#[tokio::test]
async fn generate_bundle_sees_rollup_chunks_and_can_rename_or_delete_them() {
let root = scratch("gbf-fidelity");
write_files(
&root,
&[
("package.json", r#"{"name":"gb-app","version":"1.0.0"}"#),
("src/dep.js", "export const dep = 42;\n"),
(
"src/entry.js",
"import { dep } from \"./dep.js\";\nexport const v = dep;\nconsole.log(v);\n",
),
("src/keep.js", "export const keep = \"keep-chunk-body\";\n"),
("src/gone.js", "export const gone = \"gone-chunk-body\";\n"),
(
"index.html",
r#"<!doctype html><html><head><title>t</title></head><body><script type="module" src="/src/entry.js"></script></body></html>"#,
),
(
"oj.plugins.mjs",
r#"import path from "node:path";
import { fileURLToPath } from "node:url";
const root = path.dirname(fileURLToPath(import.meta.url));
export default [{
name: "gb-fidelity",
buildStart(options) {
if (typeof options.input !== "undefined") {
this.emitFile({ type: "chunk", id: path.join(root, "src", "keep.js"), name: "keepme" });
this.emitFile({ type: "chunk", id: path.join(root, "src", "gone.js"), name: "goneme" });
}
},
generateBundle(options, bundle) {
let info = null;
for (const key of Object.keys(bundle)) {
const c = bundle[key];
if (c.type === "chunk" && c.isEntry && c.facadeModuleId && c.facadeModuleId.endsWith("entry.js")) {
info = {
facadeModuleId: c.facadeModuleId,
imports: c.imports,
exports: c.exports,
moduleCount: Object.keys(c.modules).length,
hasEntry: Object.keys(c.modules).some((m) => m.endsWith("entry.js")),
moduleIds: c.moduleIds,
};
}
if (c.type === "chunk" && c.name === "keepme") c.fileName = "assets/renamed-keepme.js";
if (c.type === "chunk" && c.name === "goneme") delete bundle[key];
}
this.emitFile({ type: "asset", fileName: "gb-info.json", source: JSON.stringify(info) });
},
}];
"#,
),
],
);
build_app(&root).await.expect("the app builds");
let dist = root.join("dist");
let raw =
fs::read_to_string(dist.join("gb-info.json")).expect("generateBundle wrote gb-info.json");
let info: serde_json::Value = serde_json::from_str(&raw).expect("gb-info.json is json");
assert!(
info.is_object(),
"the entry chunk was found in generateBundle: {raw}"
);
assert!(
info["facadeModuleId"]
.as_str()
.is_some_and(|id| id.ends_with("entry.js")),
"facadeModuleId is the entry's source id: {raw}"
);
assert!(
info["imports"].is_array(),
"chunk.imports is an array: {raw}"
);
let exports = info["exports"]
.as_array()
.unwrap_or_else(|| panic!("chunk.exports is an array: {raw}"));
assert!(
exports.iter().any(|e| e == "v"),
"chunk.exports lists the entry's export: {raw}"
);
assert!(
info["moduleCount"].as_u64().is_some_and(|n| n >= 1),
"chunk.modules is a populated map keyed by module id: {raw}"
);
assert_eq!(
info["hasEntry"], true,
"chunk.modules includes the entry module id: {raw}"
);
assert!(
info["moduleIds"]
.as_array()
.is_some_and(|ids| !ids.is_empty()),
"chunk.moduleIds is populated: {raw}"
);
let renamed = fs::read_to_string(dist.join("assets/renamed-keepme.js"))
.expect("renamed chunk exists at its new fileName");
assert!(
renamed.contains("keep-chunk-body"),
"renamed chunk keeps its content:\n{renamed}"
);
let all_js = js_under(&dist);
assert!(
!all_js.contains("gone-chunk-body"),
"deleted chunk was not written:\n{all_js}"
);
}