Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

support _devPageManifest.json #2885

Merged
merged 6 commits into from
Dec 5, 2022
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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions crates/next-core/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ bench = false
[dependencies]
anyhow = "1.0.47"
indexmap = { workspace = true, features = ["serde"] }
mime = "0.3.16"
rand = "0.8.5"
serde = "1.0.136"
serde_json = "1.0.85"
Expand Down
2 changes: 1 addition & 1 deletion crates/next-core/js/src/dev/hmr-client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -300,7 +300,7 @@ function triggerUpdate(msg: ServerMessage) {
// They must be reloaded here instead.
function subscribeToInitialCssChunksUpdates(assetPrefix: string) {
const initialCssChunkLinks: NodeListOf<HTMLLinkElement> =
document.head.querySelectorAll("link");
document.head.querySelectorAll(`link[rel="stylesheet"]`);
const cssChunkPrefix = `${assetPrefix}/`;
initialCssChunkLinks.forEach((link) => {
const href = link.href;
Expand Down
13 changes: 12 additions & 1 deletion crates/next-core/js/src/entry/next-hydrate.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,19 @@ import * as page from ".";
assetPrefix,
});

const pagePath = window.__NEXT_DATA__.page;
window.__BUILD_MANIFEST = {
[pagePath]: [],
__rewrites: {
beforeFiles: [],
afterFiles: [],
fallback: [],
} as any,
ForsakenHarmony marked this conversation as resolved.
Show resolved Hide resolved
sortedPages: [pagePath, "/_app"],
};

window.__NEXT_P.push(["/_app", () => _app]);
window.__NEXT_P.push([window.__NEXT_DATA__.page, () => page]);
window.__NEXT_P.push([pagePath, () => page]);

console.debug("Hydrating the page");

Expand Down
2 changes: 1 addition & 1 deletion crates/next-core/js/src/entry/server-renderer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ async function runOperation(
...otherExports,
},
pathname: renderData.path,
buildId: "",
buildId: "development",

/* RenderOptsPartial */
runtimeConfig: {},
Expand Down
1 change: 1 addition & 0 deletions crates/next-core/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ mod app_source;
mod embed_js;
pub mod env;
mod fallback;
pub mod manifest;
pub mod next_client;
mod next_client_component;
pub mod next_image;
Expand Down
82 changes: 82 additions & 0 deletions crates/next-core/src/manifest.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
use anyhow::Result;
use indexmap::IndexSet;
use mime::APPLICATION_JSON;
use turbo_tasks::primitives::StringsVc;
use turbo_tasks_fs::File;
use turbopack_core::asset::AssetContentVc;
use turbopack_dev_server::source::{
ContentSource, ContentSourceContent, ContentSourceData, ContentSourceResultVc, ContentSourceVc,
};
use turbopack_node::{
node_api_source::NodeApiContentSourceVc, node_rendered_source::NodeRenderContentSourceVc,
};

/// A content source which creates the next.js `_devPagesManifest.json` and
/// `_devMiddlewareManifest.json` which are used for client side navigation.
#[turbo_tasks::value(shared)]
pub struct DevManifestContentSource {
ForsakenHarmony marked this conversation as resolved.
Show resolved Hide resolved
pub page_roots: Vec<ContentSourceVc>,
}

#[turbo_tasks::value_impl]
impl DevManifestContentSourceVc {
#[turbo_tasks::function]
async fn find_routes(self) -> Result<StringsVc> {
let this = &*self.await?;
let mut queue = this.page_roots.clone();
let mut routes = IndexSet::new();

while let Some(content_source) = queue.pop() {
queue.extend(content_source.get_children().await?.iter());

if let Some(api_source) = NodeApiContentSourceVc::resolve_from(content_source).await? {
routes.insert(format!("/{}", api_source.get_pathname().await?));

continue;
}

if let Some(page_source) =
NodeRenderContentSourceVc::resolve_from(content_source).await?
{
routes.insert(format!("/{}", page_source.get_pathname().await?));

continue;
}
}

routes.sort();
Copy link
Member

Choose a reason for hiding this comment

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

Alphabetical sorting is not completely correct. It need to sort by route specificity.

see CombinedContentSource::get, which gets the max by specificity.

see also NodeRenderContentSource::specificity and NodeApiContentSource::specificity


Ok(StringsVc::cell(routes.into_iter().collect()))
}
}

#[turbo_tasks::value_impl]
impl ContentSource for DevManifestContentSource {
#[turbo_tasks::function]
async fn get(
self_vc: DevManifestContentSourceVc,
path: &str,
_data: turbo_tasks::Value<ContentSourceData>,
) -> Result<ContentSourceResultVc> {
let manifest_content = match path {
"_next/static/development/_devPagesManifest.json" => {
let pages = &*self_vc.find_routes().await?;

serde_json::to_string(&serde_json::json!({
"pages": pages,
}))?
}
"_next/static/development/_devMiddlewareManifest.json" => {
// empty middleware manifest
"[]".to_string()
}
Comment on lines +62 to +72
Copy link
Member

Choose a reason for hiding this comment

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

Could we let the RouterContentSource take care of these static routes? That would make it more efficient to match them

_ => return Ok(ContentSourceResultVc::not_found()),
};

let file = File::from(manifest_content).with_content_type(APPLICATION_JSON);

Ok(ContentSourceResultVc::exact(
ContentSourceContent::Static(AssetContentVc::from(file).into()).cell(),
))
}
}
1 change: 1 addition & 0 deletions crates/next-core/src/server_rendered_source.rs
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,7 @@ async fn create_server_rendered_source_for_file(
create_node_api_source(
specificity,
server_root,
pathname,
path_regex,
SsrEntry {
context,
Expand Down
17 changes: 14 additions & 3 deletions crates/next-dev/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@ use anyhow::{anyhow, Context, Result};
use devserver_options::DevServerOptions;
use next_core::{
create_app_source, create_server_rendered_source, create_web_entry_source, env::load_env,
next_image::NextImageContentSourceVc, source_map::NextSourceMapTraceContentSourceVc,
manifest::DevManifestContentSource, next_image::NextImageContentSourceVc,
source_map::NextSourceMapTraceContentSourceVc,
};
use owo_colors::OwoColorize;
use turbo_tasks::{
Expand Down Expand Up @@ -325,8 +326,18 @@ async fn source(
.into();
let static_source =
StaticAssetsContentSourceVc::new(String::new(), project_path.join("public")).into();
let main_source =
CombinedContentSourceVc::new(vec![static_source, app_source, rendered_source, web_source]);
let manifest_source = DevManifestContentSource {
page_roots: vec![app_source, rendered_source],
Copy link
Member

Choose a reason for hiding this comment

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

Is the __devPagesManifest even used by app dir?

}
.cell()
.into();
let main_source = CombinedContentSourceVc::new(vec![
manifest_source,
static_source,
app_source,
rendered_source,
web_source,
]);
let introspect = IntrospectionSource {
roots: HashSet::from([main_source.into()]),
}
Expand Down
6 changes: 6 additions & 0 deletions crates/turbopack-dev-server/src/source/combined.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ use super::{
specificity::SpecificityReadRef, ContentSource, ContentSourceData, ContentSourceResultVc,
ContentSourceVc,
};
use crate::source::ContentSourcesVc;

/// Combines multiple [ContentSource]s by trying all content sources in order.
/// First [ContentSource] that responds with something other than NotFound will
Expand Down Expand Up @@ -50,6 +51,11 @@ impl ContentSource for CombinedContentSource {
Ok(ContentSourceResultVc::not_found())
}
}

#[turbo_tasks::function]
fn get_children(&self) -> ContentSourcesVc {
ContentSourcesVc::cell(self.sources.clone())
}
}

#[turbo_tasks::function]
Expand Down
6 changes: 6 additions & 0 deletions crates/turbopack-dev-server/src/source/conditional.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ use turbopack_core::introspect::{Introspectable, IntrospectableChildrenVc, Intro
use super::{
ContentSource, ContentSourceContent, ContentSourceData, ContentSourceResultVc, ContentSourceVc,
};
use crate::source::ContentSourcesVc;

/// Combines two [ContentSource]s like the [CombinedContentSource], but only
/// allows to serve from the second source when the first source has
Expand Down Expand Up @@ -99,6 +100,11 @@ impl ContentSource for ConditionalContentSource {
Ok(second)
}
}

#[turbo_tasks::function]
fn get_children(&self) -> ContentSourcesVc {
ContentSourcesVc::cell(vec![self.activator, self.action])
}
}

#[turbo_tasks::function]
Expand Down
16 changes: 16 additions & 0 deletions crates/turbopack-dev-server/src/source/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -306,6 +306,22 @@ pub trait ContentSource {
/// arguments, so we want to make the arguments contain as little
/// information as possible to increase cache hit ratio.
fn get(&self, path: &str, data: Value<ContentSourceData>) -> ContentSourceResultVc;

/// Gets any content sources wrapped in this content source.
fn get_children(&self) -> ContentSourcesVc {
ContentSourcesVc::empty()
}
}

#[turbo_tasks::value(transparent)]
pub struct ContentSources(Vec<ContentSourceVc>);

#[turbo_tasks::value_impl]
impl ContentSourcesVc {
#[turbo_tasks::function]
pub fn empty() -> Self {
ContentSourcesVc::cell(Vec::new())
}
}

/// An empty ContentSource implementation that responds with NotFound for every
Expand Down
11 changes: 11 additions & 0 deletions crates/turbopack-dev-server/src/source/router.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ use turbo_tasks::{primitives::StringVc, TryJoinIterExt, Value};
use turbopack_core::introspect::{Introspectable, IntrospectableChildrenVc, IntrospectableVc};

use super::{ContentSource, ContentSourceData, ContentSourceResultVc, ContentSourceVc};
use crate::source::ContentSourcesVc;

/// Binds different ContentSources to different subpaths. A fallback
/// ContentSource will serve all other subpaths.
Expand Down Expand Up @@ -31,6 +32,16 @@ impl ContentSource for RouterContentSource {
let (source, path) = self.get_source(path);
source.get(path, data)
}

#[turbo_tasks::function]
fn get_children(&self) -> ContentSourcesVc {
let mut sources = Vec::with_capacity(self.routes.len() + 1);

sources.extend(self.routes.iter().map(|r| r.1));
sources.push(self.fallback);

ContentSourcesVc::cell(sources)
}
}

#[turbo_tasks::function]
Expand Down
13 changes: 12 additions & 1 deletion crates/turbopack-node/src/node_api_source.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,15 @@ use crate::path_regex::PathRegexVc;
pub fn create_node_api_source(
specificity: SpecificityVc,
server_root: FileSystemPathVc,
pathname: StringVc,
path_regex: PathRegexVc,
entry: NodeEntryVc,
runtime_entries: EcmascriptChunkPlaceablesVc,
) -> ContentSourceVc {
NodeApiContentSource {
specificity,
server_root,
pathname,
path_regex,
entry,
runtime_entries,
Expand All @@ -44,14 +46,23 @@ pub fn create_node_api_source(
/// for Node.js execution during rendering. The `chunking_context` should emit
/// to this directory.
#[turbo_tasks::value]
struct NodeApiContentSource {
pub struct NodeApiContentSource {
specificity: SpecificityVc,
server_root: FileSystemPathVc,
pathname: StringVc,
path_regex: PathRegexVc,
entry: NodeEntryVc,
runtime_entries: EcmascriptChunkPlaceablesVc,
}

#[turbo_tasks::value_impl]
impl NodeApiContentSourceVc {
#[turbo_tasks::function]
pub async fn get_pathname(self) -> Result<StringVc> {
Ok(self.await?.pathname)
}
}

impl NodeApiContentSource {
/// Checks if a path matches the regular expression
async fn is_matching_path(&self, path: &str) -> Result<bool> {
Expand Down
10 changes: 9 additions & 1 deletion crates/turbopack-node/src/node_rendered_source.rs
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ pub fn create_node_rendered_source(

/// see [create_node_rendered_source]
#[turbo_tasks::value]
struct NodeRenderContentSource {
pub struct NodeRenderContentSource {
specificity: SpecificityVc,
server_root: FileSystemPathVc,
pathname: StringVc,
Expand All @@ -77,6 +77,14 @@ struct NodeRenderContentSource {
fallback_page: DevHtmlAssetVc,
}

#[turbo_tasks::value_impl]
impl NodeRenderContentSourceVc {
#[turbo_tasks::function]
pub async fn get_pathname(self) -> Result<StringVc> {
Ok(self.await?.pathname)
}
}

impl NodeRenderContentSource {
/// Checks if a path matches the regular expression
async fn is_matching_path(&self, path: &str) -> Result<bool> {
Expand Down
7 changes: 6 additions & 1 deletion crates/turbopack-node/src/source_map/content_source.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use turbopack_core::{
};
use turbopack_dev_server::source::{
ContentSource, ContentSourceContent, ContentSourceData, ContentSourceDataVary,
ContentSourceResultVc, ContentSourceVc,
ContentSourceResultVc, ContentSourceVc, ContentSourcesVc,
};
use url::Url;

Expand Down Expand Up @@ -100,6 +100,11 @@ impl ContentSource for NextSourceMapTraceContentSource {
ContentSourceContent::Static(traced.content().into()).cell(),
))
}

#[turbo_tasks::function]
fn get_children(&self) -> ContentSourcesVc {
ContentSourcesVc::cell(vec![self.asset_source])
}
}

#[turbo_tasks::value_impl]
Expand Down