use crate::{App, INDEX_HTML};
const PLUGINS: &str = r#"export default [{
name: "dep-aware",
load: {
filter: { id: /node_modules\/fake-dep\// },
handler(id) { return id.includes("fake-dep") ? "export const WHO = \"FROM_PLUGIN\";\n" : null; },
},
transform(code, id) {
if (code.includes("__UI_MARKER__")) return code.replace("__UI_MARKER__", "TRANSFORMED_LINKED");
if (code.includes("virtual:outside")) return code.replace(__FROM__, __TO__);
return null;
},
}];
"#;
#[tokio::test(flavor = "multi_thread")]
async fn dep_load_filter_linked_package_transform_and_outside_root_fs_import() {
let tmp = App::new(&[]);
let outside = tmp.root.join("shared/util.js");
let quoted = |s: &str| serde_json::to_string(&serde_json::to_string(s).unwrap()).unwrap();
let plugins = PLUGINS
.replace("__FROM__", "ed("virtual:outside"))
.replace("__TO__", "ed(&outside.display().to_string()));
tmp.write(&[
(
"app/package.json",
r#"{"name":"dep-load-app","version":"1.0.0","dependencies":{"fake-dep":"1.0.0","@ws/ui":"1.0.0"}}"#,
),
(
"app/node_modules/fake-dep/package.json",
r#"{"name":"fake-dep","version":"1.0.0","main":"index.js","type":"module"}"#,
),
(
"app/node_modules/fake-dep/index.js",
"export const WHO = \"FROM_DISK\";\n",
),
(
"packages/ui/package.json",
r#"{"name":"@ws/ui","version":"1.0.0","main":"index.js","type":"module"}"#,
),
("packages/ui/index.js", "export const UI = \"__UI_MARKER__\";\n"),
(
"shared/package.json",
r#"{"name":"shared","version":"1.0.0","type":"module"}"#,
),
("shared/util.js", "export const OUTSIDE = \"outside-root\";\n"),
(
"app/src/main.js",
"import { WHO } from \"fake-dep\";\nimport { UI } from \"@ws/ui\";\nimport { OUTSIDE } from \"virtual:outside\";\nwindow.__R = [WHO, UI, OUTSIDE];\n",
),
("app/index.html", INDEX_HTML),
(
"app/oj.config.json",
r#"{"optimizeDeps":{"exclude":["fake-dep"]}}"#,
),
("app/oj.plugins.mjs", &plugins),
]);
std::fs::create_dir_all(tmp.root.join("app/node_modules/@ws")).unwrap();
std::os::unix::fs::symlink(
tmp.root.join("packages/ui"),
tmp.root.join("app/node_modules/@ws/ui"),
)
.unwrap();
let mut dev = tmp.dev();
dev.root = tmp.root.join("app");
let server = crate::serve(dev).await;
let main = server.text("/src/main.js").await;
let urls: Vec<String> = regex::Regex::new(r#"from\s+"([^"]+)""#)
.unwrap()
.captures_iter(&main)
.map(|c| c[1].to_string())
.collect();
assert_eq!(urls.len(), 3, "three rewritten imports:\n{main}");
let (dep_url, linked_url, outside_url) = (&urls[0], &urls[1], &urls[2]);
let dep = server.get(dep_url).await.body;
assert!(
dep.contains("FROM_PLUGIN"),
"filtered plugin load did not run for the dep ({dep_url}):\n{dep}"
);
let ui = server.get(linked_url).await.body;
assert!(
ui.contains("TRANSFORMED_LINKED"),
"plugin transform skipped the linked package ({linked_url}):\n{ui}"
);
assert!(
outside_url.starts_with("/@fs/"),
"outside-root path not served via /@fs: {outside_url}"
);
let res = server.get(outside_url).await;
assert_eq!(
res.status, 200,
"outside-root module not served:\n{}",
res.body
);
assert!(res.body.contains("outside-root"), "{}", res.body);
}