use farmfe_core::{
config::Mode,
module::{
module_graph::ModuleGraph,
module_group::{ModuleGroupGraph, ModuleGroupId, ModuleGroupType},
ModuleId,
},
resource::{resource_pot_map::ResourcePotMap, Resource, ResourceType},
HashMap,
};
pub fn get_dynamic_resources_map(
module_group_graph: &ModuleGroupGraph,
module_group_id: &ModuleGroupId,
resource_pot_map: &ResourcePotMap,
resources_map: &HashMap<String, Resource>,
module_graph: &ModuleGraph,
) -> HashMap<ModuleId, Vec<(String, ResourceType)>> {
let mut dep_module_groups = vec![];
module_group_graph.bfs(&module_group_id, &mut |mg_id| {
if mg_id != module_group_id {
dep_module_groups.push(mg_id.clone());
}
});
let mut dynamic_resources_map = HashMap::<ModuleId, Vec<(String, ResourceType)>>::default();
for mg_id in dep_module_groups {
let mg = module_group_graph.module_group(&mg_id).unwrap();
for rp_id in &mg.sorted_resource_pots(module_graph, resource_pot_map) {
let rp = resource_pot_map.resource_pot(rp_id).unwrap_or_else(|| {
panic!(
"Resource pot {} not found in resource pot map",
rp_id.to_string()
)
});
let resources = dynamic_resources_map
.entry(mg.entry_module_id.clone())
.or_default();
for r in rp.resources() {
let resource = resources_map
.get(r)
.unwrap_or_else(|| panic!("{r} not found"));
if !is_resource_supported(resource) {
continue;
}
resources.push((resource.name.clone(), resource.resource_type.clone()));
}
}
}
dynamic_resources_map
}
pub fn get_dynamic_resources_code(
dynamic_resources_map: &HashMap<ModuleId, Vec<(String, ResourceType)>>,
mode: Mode,
) -> (String, String) {
let mut dynamic_resources_code_vec = vec![];
let mut dynamic_resources = vec![];
let mut visited_resources = HashMap::default();
let mut dynamic_resources_map_vec = dynamic_resources_map.iter().collect::<Vec<_>>();
dynamic_resources_map_vec.sort_by_key(|(module_id, _)| module_id.to_string());
for (module_id, resources) in dynamic_resources_map_vec {
let mut dynamic_resources_index = vec![];
for (resource_name, resource_type) in resources {
let key = format!("{resource_name}{resource_type:?}");
if let Some(index) = visited_resources.get(&key) {
dynamic_resources_index.push(format!("{}", *index));
continue;
}
match resource_type {
ResourceType::Js => {
dynamic_resources.push(format!(r#"{{ path: '{resource_name}', type: 0 }}"#));
}
ResourceType::Css => {
dynamic_resources.push(format!(r#"{{ path: '{resource_name}', type: 1 }}"#));
}
_ => {
panic!("unsupported type ({resource_type:?}) when injecting dynamic resources")
}
}
dynamic_resources_index.push(format!("{}", dynamic_resources.len() - 1));
visited_resources.insert(key, dynamic_resources.len() - 1);
}
let id = module_id.id(mode.clone()).replace(r"\", r"\\");
dynamic_resources_code_vec.push((id, dynamic_resources_index.join(",")));
}
let mut dynamic_resources_code = dynamic_resources_code_vec
.into_iter()
.map(|(id, resources_code)| format!(r#"'{id}': [{resources_code}]"#))
.collect::<Vec<_>>()
.join(",");
dynamic_resources_code = format!("{{ {dynamic_resources_code} }}");
(
format!("[{}]", dynamic_resources.join(",")),
dynamic_resources_code,
)
}
#[derive(Debug, Default)]
pub struct InitialResources {
pub entry_resource_name: String,
pub entry_resource_sourcemap_name: Option<String>,
pub initial_resources: Vec<(String, ResourceType)>,
}
pub fn get_initial_resources(
entry_module_id: &ModuleId,
module_graph: &ModuleGraph,
module_group_graph: &ModuleGroupGraph,
resource_pot_map: &ResourcePotMap,
resources_map: &HashMap<String, Resource>,
) -> InitialResources {
let mut result = InitialResources::default();
let module = module_graph.module(entry_module_id).unwrap();
for resource_pot in &module.resource_pots {
let resource_pot = resource_pot_map.resource_pot(resource_pot).unwrap();
if resource_pot.is_dynamic_entry {
continue;
}
for resource_name in resource_pot.resources() {
let resource = resources_map.get(resource_name).unwrap();
if let ResourceType::SourceMap(_) = &resource.resource_type {
result.entry_resource_sourcemap_name = Some(resource_name.clone());
} else {
result.entry_resource_name = resource_name.clone();
}
}
}
let mut initial_resources = vec![];
let module_group_id = ModuleGroupId::new(entry_module_id, &ModuleGroupType::Entry);
let module_group = module_group_graph.module_group(&module_group_id).unwrap();
let sorted_resource_pots = module_group.sorted_resource_pots(&module_graph, &resource_pot_map);
for rp_id in &sorted_resource_pots {
let rp = resource_pot_map.resource_pot(rp_id).unwrap_or_else(|| {
panic!(
"Resource pot {} not found in resource pot map",
rp_id.to_string()
)
});
let filtered_resources = rp
.resources()
.into_iter()
.filter_map(|r| {
resources_map
.get(r)
.filter(|resource| is_resource_supported(resource))
})
.map(|resource| (resource.name.to_string(), resource.resource_type.clone()));
initial_resources.extend(filtered_resources);
}
result.initial_resources = initial_resources;
result
}
fn is_resource_supported(resource: &Resource) -> bool {
matches!(resource.resource_type, ResourceType::Js | ResourceType::Css)
}