Skip to content

Commit

Permalink
review
Browse files Browse the repository at this point in the history
  • Loading branch information
sokra committed Apr 26, 2023
1 parent 584eaee commit d39051a
Show file tree
Hide file tree
Showing 4 changed files with 124 additions and 80 deletions.
138 changes: 86 additions & 52 deletions packages/next-swc/crates/napi/src/app_structure.rs
Expand Up @@ -41,7 +41,8 @@ async fn project_fs(project_dir: &str, watching: bool) -> Result<FileSystemVc> {
struct LoaderTreeForJs {
segment: String,
parallel_routes: HashMap<String, LoaderTreeForJsReadRef>,
components: serde_json::Value,
#[turbo_tasks(trace_ignore)]
components: ComponentsForJs,
}

#[derive(PartialEq, Eq, Serialize, Deserialize, ValueDebugFormat, TraceRawVcs)]
Expand Down Expand Up @@ -69,10 +70,57 @@ async fn fs_path_to_path(project_path: FileSystemPathVc, path: FileSystemPathVc)
}
}

#[derive(Default, Deserialize, Serialize, PartialEq, Eq, ValueDebugFormat)]
#[serde(rename_all = "camelCase")]
struct ComponentsForJs {
#[serde(skip_serializing_if = "Option::is_none")]
page: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
layout: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
error: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
loading: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
template: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
default: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
route: Option<String>,
metadata: MetadataForJs,
}

#[derive(Default, Deserialize, Serialize, PartialEq, Eq, ValueDebugFormat)]
#[serde(rename_all = "camelCase")]
struct MetadataForJs {
#[serde(skip_serializing_if = "Vec::is_empty")]
icon: Vec<MetadataForJsItem>,
#[serde(skip_serializing_if = "Vec::is_empty")]
apple: Vec<MetadataForJsItem>,
#[serde(skip_serializing_if = "Vec::is_empty")]
twitter: Vec<MetadataForJsItem>,
#[serde(skip_serializing_if = "Vec::is_empty")]
open_graph: Vec<MetadataForJsItem>,
#[serde(skip_serializing_if = "Vec::is_empty")]
favicon: Vec<MetadataForJsItem>,
}

#[derive(Deserialize, Serialize, PartialEq, Eq, ValueDebugFormat)]
#[serde(tag = "type", rename_all = "camelCase")]
enum MetadataForJsItem {
Static {
path: String,
alt_path: Option<String>,
},
Dynamic {
path: String,
},
}

async fn prepare_components_for_js(
project_path: FileSystemPathVc,
components: ComponentsVc,
) -> Result<serde_json::Value> {
) -> Result<ComponentsForJs> {
let Components {
page,
layout,
Expand All @@ -83,80 +131,66 @@ async fn prepare_components_for_js(
route,
metadata,
} = &*components.await?;
let mut map = serde_json::value::Map::new();
let mut result = ComponentsForJs::default();
async fn add(
map: &mut serde_json::value::Map<String, serde_json::Value>,
result: &mut Option<String>,
project_path: FileSystemPathVc,
key: &str,
value: &Option<FileSystemPathVc>,
) -> Result<()> {
if let Some(value) = value {
map.insert(
key.to_string(),
fs_path_to_path(project_path, *value).await?.into(),
);
*result = Some(fs_path_to_path(project_path, *value).await?);
}
Ok::<_, anyhow::Error>(())
}
add(&mut map, project_path, "page", page).await?;
add(&mut map, project_path, "layout", layout).await?;
add(&mut map, project_path, "error", error).await?;
add(&mut map, project_path, "loading", loading).await?;
add(&mut map, project_path, "template", template).await?;
add(&mut map, project_path, "default", default).await?;
add(&mut map, project_path, "route", route).await?;
let mut meta = serde_json::value::Map::new();
add(&mut result.page, project_path, page).await?;
add(&mut result.layout, project_path, layout).await?;
add(&mut result.error, project_path, error).await?;
add(&mut result.loading, project_path, loading).await?;
add(&mut result.template, project_path, template).await?;
add(&mut result.default, project_path, default).await?;
add(&mut result.route, project_path, route).await?;
async fn add_meta<'a>(
meta: &mut serde_json::value::Map<String, serde_json::Value>,
meta: &mut Vec<MetadataForJsItem>,
project_path: FileSystemPathVc,
key: &str,
value: impl Iterator<Item = &'a MetadataWithAltItem>,
) -> Result<()> {
let mut value = value.peekable();
if value.peek().is_some() {
meta.insert(
key.to_string(),
value
.map(|value| async move {
let mut map = serde_json::value::Map::new();
match value {
MetadataWithAltItem::Static { path, alt_path } => {
map.insert("type".to_string(), "static".into());
let path = fs_path_to_path(project_path, *path).await?;
map.insert("path".to_string(), path.into());
if let Some(alt_path) = alt_path {
let alt_path = fs_path_to_path(project_path, *alt_path).await?;
map.insert("altPath".to_string(), alt_path.into());
}
}
MetadataWithAltItem::Dynamic { path } => {
map.insert("type".to_string(), "dynamic".into());
let path = fs_path_to_path(project_path, *path).await?;
map.insert("path".to_string(), path.into());
}
*meta = value
.map(|value| async move {
Ok(match value {
MetadataWithAltItem::Static { path, alt_path } => {
let path = fs_path_to_path(project_path, *path).await?;
let alt_path = if let Some(alt_path) = alt_path {
Some(fs_path_to_path(project_path, *alt_path).await?)
} else {
None
};
MetadataForJsItem::Static { path, alt_path }
}
MetadataWithAltItem::Dynamic { path } => {
let path = fs_path_to_path(project_path, *path).await?;
MetadataForJsItem::Dynamic { path }
}
Ok(serde_json::Value::from(map))
})
.try_join()
.await?
.into(),
);
})
.try_join()
.await?;
}
Ok::<_, anyhow::Error>(())
}
add_meta(&mut meta, project_path, "icon", metadata.icon.iter()).await?;
add_meta(&mut meta, project_path, "apple", metadata.apple.iter()).await?;
add_meta(&mut meta, project_path, "twitter", metadata.twitter.iter()).await?;
let meta = &mut result.metadata;
add_meta(&mut meta.icon, project_path, metadata.icon.iter()).await?;
add_meta(&mut meta.apple, project_path, metadata.apple.iter()).await?;
add_meta(&mut meta.twitter, project_path, metadata.twitter.iter()).await?;
add_meta(
&mut meta,
&mut meta.open_graph,
project_path,
"openGraph",
metadata.open_graph.iter(),
)
.await?;
add_meta(&mut meta, project_path, "favicon", metadata.favicon.iter()).await?;
map.insert("metadata".to_string(), meta.into());
Ok(map.into())
add_meta(&mut meta.favicon, project_path, metadata.favicon.iter()).await?;
Ok(result)
}

#[tasks::function]
Expand Down
55 changes: 30 additions & 25 deletions packages/next-swc/crates/next-core/src/app_source.rs
Expand Up @@ -470,27 +470,27 @@ async fn create_global_metadata_source(
let metadata = metadata.await?;
let mut unsupported_metadata = Vec::new();
let mut sources = Vec::new();
let mut handle = |server_path, item| {
if let Some(item) = item {
match item {
MetadataItem::Static { path } => {
let asset = FixedStaticAssetVc::new(
server_root.join(server_path),
SourceAssetVc::new(path).into(),
);
sources.push(
AssetGraphContentSourceVc::new_eager(server_root, asset.into()).into(),
)
}
MetadataItem::Dynamic { path } => {
unsupported_metadata.push(path);
}
for (server_path, item) in [
("robots.txt", metadata.robots),
("favicon.ico", metadata.favicon),
("sitemap.xml", metadata.sitemap),
] {
let Some(item) = item else {
continue;
};
match item {
MetadataItem::Static { path } => {
let asset = FixedStaticAssetVc::new(
server_root.join(server_path),
SourceAssetVc::new(path).into(),
);
sources.push(AssetGraphContentSourceVc::new_eager(server_root, asset.into()).into())
}
MetadataItem::Dynamic { path } => {
unsupported_metadata.push(path);
}
}
};
handle("robots.txt", metadata.robots);
handle("favicon.ico", metadata.favicon);
handle("sitemap.xml", metadata.sitemap);
}
if !unsupported_metadata.is_empty() {
UnsupportedDynamicMetadataIssue {
app_dir,
Expand Down Expand Up @@ -630,6 +630,14 @@ impl AppRendererVc {
unsupported_metadata: Vec<FileSystemPathVc>,
}

impl State {
fn unique_number(&mut self) -> usize {
let i = self.counter;
self.counter += 1;
i
}
}

let mut state = State {
inner_assets: IndexMap::new(),
counter: 0,
Expand All @@ -647,8 +655,7 @@ impl AppRendererVc {
use std::fmt::Write;

if let Some(component) = component {
let i = state.counter;
state.counter += 1;
let i = state.unique_number();
let identifier = magic_identifier::mangle(&format!("{name} #{i}"));
let chunks_identifier = magic_identifier::mangle(&format!("chunks of {name} #{i}"));
writeln!(
Expand Down Expand Up @@ -708,8 +715,7 @@ import {}, {{ chunks as {} }} from "COMPONENT_{}";
match manifest {
MetadataItem::Static { path } => {
use std::fmt::Write;
let i = state.counter;
state.counter += 1;
let i = state.unique_number();
let identifier = magic_identifier::mangle(&format!("manifest #{i}"));
let inner_module_id = format!("METADATA_{i}");
state
Expand Down Expand Up @@ -754,8 +760,7 @@ import {}, {{ chunks as {} }} from "COMPONENT_{}";
item: &MetadataWithAltItem,
) -> Result<()> {
use std::fmt::Write;
let i = state.counter;
state.counter += 1;
let i = state.unique_number();
let identifier = magic_identifier::mangle(&format!("{name} #{i}"));
let inner_module_id = format!("METADATA_{i}");
state
Expand Down
9 changes: 7 additions & 2 deletions packages/next-swc/crates/next-core/src/app_structure.rs
Expand Up @@ -82,6 +82,7 @@ impl ComponentsVc {
}
}

/// A single metadata file plus an optional "alt" text file.
#[derive(Copy, Clone, Debug, Serialize, Deserialize, PartialEq, Eq, TraceRawVcs)]
pub enum MetadataWithAltItem {
Static {
Expand All @@ -93,12 +94,14 @@ pub enum MetadataWithAltItem {
},
}

/// A single metadata file.
#[derive(Copy, Clone, Debug, Serialize, Deserialize, PartialEq, Eq, TraceRawVcs)]
pub enum MetadataItem {
Static { path: FileSystemPathVc },
Dynamic { path: FileSystemPathVc },
}

/// Metadata file that can be placed in any segment of the app directory.
#[derive(Default, Clone, Debug, Serialize, Deserialize, PartialEq, Eq, TraceRawVcs)]
pub struct Metadata {
#[serde(skip_serializing_if = "Vec::is_empty")]
Expand Down Expand Up @@ -150,6 +153,7 @@ impl Metadata {
}
}

/// Metadata files that can be placed in the root of the app directory.
#[turbo_tasks::value]
#[derive(Default, Clone, Debug)]
pub struct GlobalMetadata {
Expand Down Expand Up @@ -277,7 +281,7 @@ fn match_metadata_file<'a>(
) -> Option<(&'a str, bool)> {
let (stem, ext) = basename.split_once('.')?;
static REGEX: Lazy<Regex> = Lazy::new(|| Regex::new("^(.*?)\\d*$").unwrap());
let captures = REGEX.captures(stem).unwrap();
let captures = REGEX.captures(stem).expect("the regex will always match");
let stem = captures.get(1).unwrap().as_str();
if page_extensions.iter().any(|e| e == ext) {
return Some((stem, true));
Expand Down Expand Up @@ -366,7 +370,7 @@ async fn get_directory_tree(
let result = get_directory_tree(dir, page_extensions);
subdirectories.insert(basename.to_string(), result);
}
// TODO handle symlinks in app dir
// TODO(WEB-952) handle symlinks in app dir
_ => {}
}
}
Expand Down Expand Up @@ -668,6 +672,7 @@ async fn directory_tree_to_entrypoints_internal(
Ok(EntrypointsVc::cell(result))
}

/// Returns the global metadata for an app directory.
#[turbo_tasks::function]
pub async fn get_global_metadata(
app_dir: FileSystemPathVc,
Expand Down
@@ -1 +1 @@
This is an alt text.
This is an alt text.

0 comments on commit d39051a

Please sign in to comment.