这是indexloc提供的服务,不要输入任何密码
Skip to content
Merged
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
7 changes: 7 additions & 0 deletions crates/turborepo-lib/src/engine/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -394,6 +394,13 @@ impl Engine<Built> {
self.task_graph.node_weights()
}

pub fn task_ids(&self) -> impl Iterator<Item = &TaskId<'static>> {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Future work is removing the concept of a "root" task node since that only exists due to limitation of Go graphing library.

self.tasks().filter_map(|task| match task {
crate::engine::TaskNode::Task(task_id) => Some(task_id),
crate::engine::TaskNode::Root => None,
})
}

/// Return all tasks that have a command to be run
pub fn tasks_with_command(&self, pkg_graph: &PackageGraph) -> Vec<String> {
self.tasks()
Expand Down
141 changes: 110 additions & 31 deletions crates/turborepo-lib/src/microfrontends.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,8 @@ pub struct MicrofrontendsConfigs {

#[derive(Debug, Clone, Default, PartialEq)]
struct ConfigInfo {
tasks: HashSet<TaskId<'static>>,
// A map from tasks declared in the configuration to the application that they belong to
tasks: HashMap<TaskId<'static>, String>,
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We need to store the application name as that is what the microfrontends local proxy uses to identify locally running applications.

ports: HashMap<TaskId<'static>, u16>,
version: &'static str,
path: Option<RelativeUnixPathBuf>,
Expand All @@ -32,24 +33,33 @@ impl MicrofrontendsConfigs {
repo_root: &AbsoluteSystemPath,
package_graph: &PackageGraph,
) -> Result<Option<Self>, Error> {
Self::from_configs(package_graph.packages().map(|(name, info)| {
(
name.as_str(),
MFEConfig::load_from_dir(repo_root, info.package_path()),
)
}))
let package_names = package_graph
.packages()
.map(|(name, _)| name.as_str())
.collect();
Self::from_configs(
package_names,
package_graph.packages().map(|(name, info)| {
(
name.as_str(),
MFEConfig::load_from_dir(repo_root, info.package_path()),
)
}),
)
}

/// Constructs a collection of configurations from a list of configurations
pub fn from_configs<'a>(
package_names: HashSet<&str>,
configs: impl Iterator<Item = (&'a str, Result<Option<MFEConfig>, Error>)>,
) -> Result<Option<Self>, Error> {
let PackageGraphResult {
configs,
missing_default_apps,
missing_applications,
unsupported_version,
mfe_package,
} = PackageGraphResult::new(configs)?;
} = PackageGraphResult::new(package_names, configs)?;

for (package, err) in unsupported_version {
warn!("Ignoring {package}: {err}");
Expand All @@ -62,29 +72,34 @@ impl MicrofrontendsConfigs {
);
}

if !missing_applications.is_empty() {
warn!(
"Unable to find packages referenced in 'microfrontends.json' in workspace. Local \
proxy will not route to the following applications if they are running locally: \
{}",
missing_applications.join(", ")
);
}

Ok((!configs.is_empty()).then_some(Self {
configs,
mfe_package,
}))
}

pub fn contains_package(&self, package_name: &str) -> bool {
self.configs.contains_key(package_name)
}

pub fn configs(&self) -> impl Iterator<Item = (&String, &HashSet<TaskId<'static>>)> {
pub fn configs(&self) -> impl Iterator<Item = (&String, &HashMap<TaskId<'static>, String>)> {
self.configs.iter().map(|(pkg, info)| (pkg, &info.tasks))
}

pub fn get(&self, package_name: &str) -> Option<&HashSet<TaskId<'static>>> {
pub fn get(&self, package_name: &str) -> Option<&HashMap<TaskId<'static>, String>> {
let info = self.configs.get(package_name)?;
Some(&info.tasks)
}

pub fn task_has_mfe_proxy(&self, task_id: &TaskId) -> bool {
self.configs
.values()
.any(|info| info.tasks.contains(task_id))
.any(|info| info.tasks.contains_key(task_id))
}

pub fn config_filename(&self, package_name: &str) -> Option<&RelativeUnixPath> {
Expand Down Expand Up @@ -152,7 +167,7 @@ impl MicrofrontendsConfigs {
package_name: &PackageName,
) -> Option<FindResult<'a>> {
let results = self.configs.iter().filter_map(|(config, info)| {
let dev_task = info.tasks.iter().find_map(|task| {
let dev_task = info.tasks.iter().find_map(|(task, _)| {
(task.package() == package_name.as_str()).then(|| FindResult {
dev: Some(task.as_borrowed()),
proxy: TaskId::new(config, "proxy"),
Expand Down Expand Up @@ -186,16 +201,19 @@ impl MicrofrontendsConfigs {
struct PackageGraphResult {
configs: HashMap<String, ConfigInfo>,
missing_default_apps: Vec<String>,
missing_applications: Vec<String>,
unsupported_version: Vec<(String, String)>,
mfe_package: Option<&'static str>,
}

impl PackageGraphResult {
fn new<'a>(
packages_in_graph: HashSet<&str>,
packages: impl Iterator<Item = (&'a str, Result<Option<MFEConfig>, Error>)>,
) -> Result<Self, Error> {
let mut configs = HashMap::new();
let mut referenced_default_apps = HashSet::new();
let mut referenced_packages = HashSet::new();
let mut unsupported_version = Vec::new();
let mut mfe_package = None;
// We sort packages to ensure deterministic behavior
Expand Down Expand Up @@ -223,6 +241,8 @@ impl PackageGraphResult {
if let Some(path) = config.path() {
info.path = Some(path.to_unix());
}
referenced_packages.insert(package_name.to_string());
referenced_packages.extend(info.tasks.keys().map(|task| task.package().to_string()));
configs.insert(package_name.to_string(), info);
}
let default_apps_found = configs.keys().cloned().collect();
Expand All @@ -231,9 +251,15 @@ impl PackageGraphResult {
.cloned()
.collect::<Vec<_>>();
missing_default_apps.sort();
let mut missing_applications = referenced_packages
.into_iter()
.filter(|package| !packages_in_graph.contains(package.as_str()))
.collect::<Vec<_>>();
missing_applications.sort();
Ok(Self {
configs,
missing_default_apps,
missing_applications,
unsupported_version,
mfe_package,
})
Expand All @@ -250,13 +276,13 @@ struct FindResult<'a> {
impl ConfigInfo {
fn new(config: &MFEConfig) -> Self {
let mut ports = HashMap::new();
let mut tasks = HashSet::new();
for (application, dev_task) in config.development_tasks() {
let task = TaskId::new(application, dev_task.unwrap_or("dev")).into_owned();
if let Some(port) = config.port(application) {
let mut tasks = HashMap::new();
for dev_task in config.development_tasks() {
let task = TaskId::new(dev_task.package, dev_task.task.unwrap_or("dev")).into_owned();
if let Some(port) = config.port(dev_task.application_name) {
ports.insert(task.clone(), port);
}
tasks.insert(task);
tasks.insert(task, dev_task.application_name.to_owned());
}
let version = config.version();

Expand All @@ -281,9 +307,11 @@ mod test {
{
let mut _map = std::collections::HashMap::new();
$(
let mut _dev_tasks = std::collections::HashSet::new();
let mut _dev_tasks = std::collections::HashMap::new();
for _dev_task in $dev_tasks.as_slice() {
_dev_tasks.insert(crate::run::task_id::TaskName::from(*_dev_task).task_id().unwrap().into_owned());
let _dev_task_id = crate::run::task_id::TaskName::from(*_dev_task).task_id().unwrap().into_owned();
let _dev_application = _dev_task_id.package().to_owned();
_dev_tasks.insert(_dev_task_id, _dev_application);
}
_map.insert($config_owner.to_string(), ConfigInfo { tasks: _dev_tasks, version: "1", path: None, ports: std::collections::HashMap::new() });
)+
Expand Down Expand Up @@ -363,22 +391,28 @@ mod test {

#[test]
fn test_mfe_package_is_found() {
let result =
PackageGraphResult::new(vec![(MICROFRONTENDS_PACKAGE, Ok(None))].into_iter()).unwrap();
let result = PackageGraphResult::new(
HashSet::default(),
vec![(MICROFRONTENDS_PACKAGE, Ok(None))].into_iter(),
)
.unwrap();
assert_eq!(result.mfe_package, Some(MICROFRONTENDS_PACKAGE));
}

#[test]
fn test_no_mfe_package() {
let result =
PackageGraphResult::new(vec![("foo", Ok(None)), ("bar", Ok(None))].into_iter())
.unwrap();
let result = PackageGraphResult::new(
HashSet::default(),
vec![("foo", Ok(None)), ("bar", Ok(None))].into_iter(),
)
.unwrap();
assert_eq!(result.mfe_package, None);
}

#[test]
fn test_unsupported_versions_ignored() {
let result = PackageGraphResult::new(
HashSet::default(),
vec![("foo", Err(Error::UnsupportedVersion("bad version".into())))].into_iter(),
)
.unwrap();
Expand All @@ -388,6 +422,7 @@ mod test {
#[test]
fn test_child_configs_with_missing_default() {
let result = PackageGraphResult::new(
HashSet::default(),
vec![(
"child",
Err(Error::ChildConfig {
Expand All @@ -404,6 +439,7 @@ mod test {
#[test]
fn test_io_err_stops_traversal() {
let result = PackageGraphResult::new(
HashSet::default(),
vec![
(
"a",
Expand Down Expand Up @@ -442,8 +478,11 @@ mod test {
"something.txt",
)
.unwrap();
let mut result =
PackageGraphResult::new(vec![("web", Ok(Some(config)))].into_iter()).unwrap();
let mut result = PackageGraphResult::new(
HashSet::default(),
vec![("web", Ok(Some(config)))].into_iter(),
)
.unwrap();
result
.configs
.values_mut()
Expand All @@ -456,6 +495,42 @@ mod test {
)
}

#[test]
fn test_missing_packages() {
let config = MFEConfig::from_str(
&serde_json::to_string_pretty(&json!({
"version": "1",
"applications": {
"web": {},
"docs": {
"development": {
"task": "serve"
}
}
}
}))
.unwrap(),
"something.txt",
)
.unwrap();
let missing_result = PackageGraphResult::new(
HashSet::default(),
vec![("web", Ok(Some(config.clone())))].into_iter(),
)
.unwrap();
assert_eq!(missing_result.missing_applications, vec!["docs", "web"]);
let found_result = PackageGraphResult::new(
HashSet::from_iter(["docs", "web"].iter().copied()),
vec![("web", Ok(Some(config)))].into_iter(),
)
.unwrap();
assert!(
found_result.missing_applications.is_empty(),
"Expected no missing applications: {:?}",
found_result.missing_applications
);
}

#[test]
fn test_port_collection() {
let config = MFEConfig::from_str(
Expand All @@ -477,7 +552,11 @@ mod test {
"something.txt",
)
.unwrap();
let result = PackageGraphResult::new(vec![("web", Ok(Some(config)))].into_iter()).unwrap();
let result = PackageGraphResult::new(
HashSet::default(),
vec![("web", Ok(Some(config)))].into_iter(),
)
.unwrap();
let web_ports = result.configs["web"].ports.clone();
assert_eq!(
web_ports.get(&TaskId::new("docs", "serve")).copied(),
Expand Down
Loading
Loading