Skip to content

Commit

Permalink
add RSC and RCC for turbopack to benchmarks (vercel/turbo#2620)
Browse files Browse the repository at this point in the history
* fixup ropes

* add RSC and RCC for turbopack to benchmarks

RSC: whole page is a server component
RCC: whole page is a client component

add `app` directory to test app
  • Loading branch information
sokra committed Nov 7, 2022
1 parent cf440bb commit d579daa
Show file tree
Hide file tree
Showing 6 changed files with 93 additions and 15 deletions.
2 changes: 1 addition & 1 deletion crates/next-core/src/app_source.rs
Expand Up @@ -500,7 +500,7 @@ impl NodeEntry for AppRenderer {

for (_, import) in segments.iter() {
if let Some((p, identifier, chunks_identifier)) = import {
result += r#"("TURBOPACK {{ transition: next-layout-entry; chunking-type: parallel }}");
result += r#"("TURBOPACK { transition: next-layout-entry; chunking-type: parallel }");
"#;
writeln!(
result,
Expand Down
25 changes: 23 additions & 2 deletions crates/next-dev/benches/bundlers/mod.rs
Expand Up @@ -29,6 +29,10 @@ pub trait Bundler {
fn has_server_rendered_html(&self) -> bool {
false
}
/// There is a hydration done event emitted by client side JavaScript
fn has_interactivity(&self) -> bool {
true
}
fn prepare(&self, _template_dir: &Path) -> Result<()> {
Ok(())
}
Expand All @@ -55,8 +59,25 @@ pub fn get_bundlers() -> Vec<Box<dyn Bundler>> {
}
let mut bundlers: Vec<Box<dyn Bundler>> = Vec::new();
if turbopack {
bundlers.push(Box::new(Turbopack::new("Turbopack CSR", "/", false)));
bundlers.push(Box::new(Turbopack::new("Turbopack SSR", "/page", true)));
bundlers.push(Box::new(Turbopack::new("Turbopack CSR", "/", false, true)));
bundlers.push(Box::new(Turbopack::new(
"Turbopack SSR",
"/page",
true,
true,
)));
bundlers.push(Box::new(Turbopack::new(
"Turbopack RSC",
"/app",
true,
false,
)));
bundlers.push(Box::new(Turbopack::new(
"Turbopack RCC",
"/client",
true,
true,
)));
}

if others {
Expand Down
13 changes: 12 additions & 1 deletion crates/next-dev/benches/bundlers/turbopack.rs
Expand Up @@ -18,14 +18,21 @@ pub struct Turbopack {
name: String,
path: String,
has_server_rendered_html: bool,
has_interactivity: bool,
}

impl Turbopack {
pub fn new(name: &str, path: &str, has_server_rendered_html: bool) -> Self {
pub fn new(
name: &str,
path: &str,
has_server_rendered_html: bool,
has_interactivity: bool,
) -> Self {
Turbopack {
name: name.to_owned(),
path: path.to_owned(),
has_server_rendered_html,
has_interactivity,
}
}
}
Expand All @@ -43,6 +50,10 @@ impl Bundler for Turbopack {
self.has_server_rendered_html
}

fn has_interactivity(&self) -> bool {
self.has_interactivity
}

fn prepare(&self, install_dir: &Path) -> Result<()> {
npm::install(
install_dir,
Expand Down
36 changes: 33 additions & 3 deletions crates/next-dev/benches/mod.rs
Expand Up @@ -56,6 +56,13 @@ fn bench_startup_internal(mut g: BenchmarkGroup<WallTime>, hydration: bool) {
} else {
true
}
} else if !bundler.has_interactivity() {
// For bundlers without interactivity there is no hydration event to wait for
if hydration {
continue;
} else {
false
}
} else {
hydration
};
Expand Down Expand Up @@ -119,6 +126,10 @@ fn bench_hmr_internal(mut g: BenchmarkGroup<WallTime>, location: CodeLocation) {
let browser = &runtime.block_on(create_browser());

for bundler in get_bundlers() {
// TODO HMR for RSC is broken, fix it and enable it here
if !bundler.has_interactivity() {
continue;
}
for module_count in get_module_counts() {
let test_app = Lazy::new(|| build_test(module_count, bundler.as_ref()));
let input = (bundler.as_ref(), &test_app);
Expand Down Expand Up @@ -206,11 +217,19 @@ fn bench_hmr_internal(mut g: BenchmarkGroup<WallTime>, location: CodeLocation) {
.await?;
app.start_server()?;
let mut guard = app.with_page(browser).await?;
guard.wait_for_hydration().await?;
if bundler.has_interactivity() {
guard.wait_for_hydration().await?;
} else {
guard.page().wait_for_navigation().await?;
}
guard
.page()
.evaluate_expression("globalThis.HMR_IS_HAPPENING = true")
.await?;
.await
.context(
"Unable to evaluate JavaScript in the page for HMR check \
flag",
)?;
Ok(guard)
},
|mut guard| async move {
Expand Down Expand Up @@ -283,6 +302,13 @@ fn bench_startup_cached_internal(mut g: BenchmarkGroup<WallTime>, hydration: boo
} else {
true
}
} else if !bundler.has_interactivity() {
// For bundlers without interactivity there is no hydration event to wait for
if hydration {
continue;
} else {
false
}
} else {
hydration
};
Expand All @@ -303,7 +329,11 @@ fn bench_startup_cached_internal(mut g: BenchmarkGroup<WallTime>, hydration: boo
.await?;
app.start_server()?;
let mut guard = app.with_page(browser).await?;
guard.wait_for_hydration().await?;
if bundler.has_interactivity() {
guard.wait_for_hydration().await?;
} else {
guard.page().wait_for_navigation().await?;
}

let mut app = guard.close_page().await?;

Expand Down
3 changes: 2 additions & 1 deletion crates/next-dev/benches/util/page_guard.rs
Expand Up @@ -100,7 +100,8 @@ impl<'a> PageGuard<'a> {
self.wait_for_binding(TEST_APP_HYDRATION_DONE),
)
.await
.context("Timeout happened while waiting for hydration")??;
.context("Timeout happened while waiting for hydration")?
.context("Error happened while waiting for hydration")?;
Ok(())
}
}
Expand Down
29 changes: 22 additions & 7 deletions crates/next-dev/benches/util/prepared_app.rs
Expand Up @@ -95,13 +95,27 @@ impl<'a> PreparedApp<'a> {

pub async fn with_page(self, browser: &Browser) -> Result<PageGuard<'a>> {
let server = self.server.as_ref().context("Server must be started")?;
let page = browser.new_page("about:blank").await?;
let page = browser
.new_page("about:blank")
.await
.context("Unable to open about:blank")?;
// Bindings survive page reloads. Set them up as early as possible.
add_binding(&page).await?;

let mut errors = page.event_listener::<EventExceptionThrown>().await?;
let binding_events = page.event_listener::<EventBindingCalled>().await?;
let mut network_response_events = page.event_listener::<EventResponseReceived>().await?;
add_binding(&page)
.await
.context("Failed to add bindings to the browser tab")?;

let mut errors = page
.event_listener::<EventExceptionThrown>()
.await
.context("Unable to listen to exception events")?;
let binding_events = page
.event_listener::<EventBindingCalled>()
.await
.context("Unable to listen to binding events")?;
let mut network_response_events = page
.event_listener::<EventResponseReceived>()
.await
.context("Unable to listen to response received events")?;

let destination = Url::parse(&server.1)?.join(self.bundler.get_path())?;
// We can't use page.goto() here since this will wait for the naviation to be
Expand All @@ -111,7 +125,8 @@ impl<'a> PreparedApp<'a> {
// So instead we navigate via JavaScript and wait only for the HTML response to
// be completed.
page.evaluate_expression(format!("window.location='{destination}'"))
.await?;
.await
.context("Unable to evaluate javascript to naviagate to target page")?;

// Wait for HTML response completed
loop {
Expand Down

0 comments on commit d579daa

Please sign in to comment.