next/font: Align with Next.js integration test suite (vercel/turbo#4039)

This:
* Adds a compile-time feature, `__internal_nextjs_integration_test`,
which is set when building Turbopack for the Next.js integration test
suite.
* When built with `__internal_nextjs_integration_test`, expects the
environment variable `NEXT_FONT_GOOGLE_MOCKED_RESPONSES` to be set with
an absolute path to a JavaScript file exporting a mapping of urls to
stylesheet text. This is used in place of making real requests to Google
Fonts.
* Addresses some small bugs in next/font/google to bring the
implementation in line with the urls generated by Next.js without
Turbopack.
* Changes classnames generated by next/font to use 6 character hashes,
bringing it in alignment with Next.js without Turbopack.

Test Plan:
* Adjusted existing unit tests
* In Next.js, `node run-tests.js -c 1 test/e2e/next-font/index.test.ts`

### Description

<!--
  ✍️ Write a short summary of your work.
  If necessary, include relevant screenshots.
-->

### Testing Instructions

<!--
  Give a quick description of steps to test your changes.
-->

<!--
  When the below is checked (default) our PR bot will automatically
  assign labels to your PR based on the content to help the team
  organize and review it faster.
-->

- [x] Auto label
This commit is contained in:
Will Binns-Smith 2023-03-03 16:12:36 -08:00 committed by GitHub
parent ad12551513
commit 5f76b5d9e4
19 changed files with 339 additions and 127 deletions

View file

@ -40,3 +40,5 @@ turbo-tasks-build = { workspace = true }
next-font-local = []
native-tls = ["turbo-tasks-fetch/native-tls"]
rustls-tls = ["turbo-tasks-fetch/rustls-tls"]
# Internal only. Enabled when building for the Next.js integration test suite.
__internal_nextjs_integration_test = []

View file

@ -99,9 +99,10 @@ async fn next_client_transition(
ty,
next_config,
);
let client_runtime_entries = get_client_runtime_entries(project_path, env, ty, next_config);
let client_runtime_entries =
get_client_runtime_entries(project_path, env, ty, next_config, execution_context);
let client_resolve_options_context =
get_client_resolve_options_context(project_path, ty, next_config);
get_client_resolve_options_context(project_path, ty, next_config, execution_context);
Ok(NextClientTransition {
is_app: true,
@ -137,6 +138,7 @@ fn next_ssr_client_module_transition(
project_path,
ty,
next_config,
execution_context,
),
ssr_environment: get_server_compile_time_info(ty, process_env, server_addr),
}
@ -157,7 +159,7 @@ fn next_layout_entry_transition(
let ty = Value::new(ServerContextType::AppRSC { app_dir });
let rsc_compile_time_info = get_server_compile_time_info(ty, process_env, server_addr);
let rsc_resolve_options_context =
get_server_resolve_options_context(project_path, ty, next_config);
get_server_resolve_options_context(project_path, ty, next_config, execution_context);
let rsc_module_options_context =
get_server_module_options_context(project_path, execution_context, ty, next_config);
@ -179,6 +181,7 @@ fn next_route_transition(
next_config: NextConfigVc,
server_addr: ServerAddrVc,
output_path: FileSystemPathVc,
execution_context: ExecutionContextVc,
) -> TransitionVc {
let server_ty = Value::new(ServerContextType::AppRoute { app_dir });
@ -194,7 +197,7 @@ fn next_route_transition(
)
.build();
let edge_resolve_options_context =
get_edge_resolve_options_context(project_path, server_ty, next_config);
get_edge_resolve_options_context(project_path, server_ty, next_config, execution_context);
NextEdgeTransition {
edge_compile_time_info,
@ -235,6 +238,7 @@ fn app_context(
next_config,
server_addr,
output_path,
execution_context,
),
);
transitions.insert(
@ -295,7 +299,7 @@ fn app_context(
TransitionsByNameVc::cell(transitions),
get_server_compile_time_info(ssr_ty, env, server_addr),
get_server_module_options_context(project_path, execution_context, ssr_ty, next_config),
get_server_resolve_options_context(project_path, ssr_ty, next_config),
get_server_resolve_options_context(project_path, ssr_ty, next_config, execution_context),
)
.into()
}

View file

@ -36,7 +36,8 @@ pub async fn get_fallback_page(
next_config: NextConfigVc,
) -> Result<DevHtmlAssetVc> {
let ty = Value::new(ClientContextType::Fallback);
let resolve_options_context = get_client_resolve_options_context(project_path, ty, next_config);
let resolve_options_context =
get_client_resolve_options_context(project_path, ty, next_config, execution_context);
let module_options_context = get_client_module_options_context(
project_path,
execution_context,
@ -50,10 +51,10 @@ pub async fn get_fallback_page(
client_compile_time_info.environment(),
ty,
);
let entries = get_client_runtime_entries(project_path, env, ty, next_config);
let entries = get_client_runtime_entries(project_path, env, ty, next_config, execution_context);
let mut import_map = ImportMap::empty();
insert_next_shared_aliases(&mut import_map, project_path).await?;
insert_next_shared_aliases(&mut import_map, project_path, execution_context).await?;
insert_alias_option(
&mut import_map,
project_path,

View file

@ -84,8 +84,10 @@ pub async fn get_client_resolve_options_context(
project_path: FileSystemPathVc,
ty: Value<ClientContextType>,
next_config: NextConfigVc,
execution_context: ExecutionContextVc,
) -> Result<ResolveOptionsContextVc> {
let next_client_import_map = get_next_client_import_map(project_path, ty, next_config);
let next_client_import_map =
get_next_client_import_map(project_path, ty, next_config, execution_context);
let next_client_fallback_import_map = get_next_client_fallback_import_map(ty);
let next_client_resolved_map = get_next_client_resolved_map(project_path, project_path);
let module_options_context = ResolveOptionsContext {
@ -119,7 +121,8 @@ pub async fn get_client_module_options_context(
next_config: NextConfigVc,
) -> Result<ModuleOptionsContextVc> {
let custom_rules = get_next_client_transforms_rules(ty.into_value()).await?;
let resolve_options_context = get_client_resolve_options_context(project_path, ty, next_config);
let resolve_options_context =
get_client_resolve_options_context(project_path, ty, next_config, execution_context);
let enable_react_refresh =
assert_can_resolve_react_refresh(project_path, resolve_options_context)
.await?
@ -182,7 +185,8 @@ pub fn get_client_asset_context(
ty: Value<ClientContextType>,
next_config: NextConfigVc,
) -> AssetContextVc {
let resolve_options_context = get_client_resolve_options_context(project_path, ty, next_config);
let resolve_options_context =
get_client_resolve_options_context(project_path, ty, next_config, execution_context);
let module_options_context = get_client_module_options_context(
project_path,
execution_context,
@ -244,8 +248,10 @@ pub async fn get_client_runtime_entries(
env: ProcessEnvVc,
ty: Value<ClientContextType>,
next_config: NextConfigVc,
execution_context: ExecutionContextVc,
) -> Result<RuntimeEntriesVc> {
let resolve_options_context = get_client_resolve_options_context(project_root, ty, next_config);
let resolve_options_context =
get_client_resolve_options_context(project_root, ty, next_config, execution_context);
let enable_react_refresh =
assert_can_resolve_react_refresh(project_root, resolve_options_context)
.await?

View file

@ -63,6 +63,7 @@ impl NextClientChunksTransitionVc {
project_path,
ty,
next_config,
execution_context,
),
client_compile_time_info,
server_root,

View file

@ -10,6 +10,7 @@ use turbopack_core::{
ServerAddrVc,
},
};
use turbopack_node::execution_context::ExecutionContextVc;
use crate::{
next_config::NextConfigVc, next_import_map::get_next_edge_import_map,
@ -47,8 +48,10 @@ pub async fn get_edge_resolve_options_context(
project_path: FileSystemPathVc,
ty: Value<ServerContextType>,
next_config: NextConfigVc,
execution_context: ExecutionContextVc,
) -> Result<ResolveOptionsContextVc> {
let next_edge_import_map = get_next_edge_import_map(project_path, ty, next_config);
let next_edge_import_map =
get_next_edge_import_map(project_path, ty, next_config, execution_context);
let resolve_options_context = ResolveOptionsContext {
enable_node_modules: Some(project_path.root().resolve().await?),

View file

@ -3,11 +3,9 @@ use indexmap::IndexMap;
use indoc::formatdoc;
use once_cell::sync::Lazy;
use turbo_tasks::primitives::{OptionStringVc, OptionU16Vc, StringVc, U32Vc};
use turbo_tasks_fetch::fetch;
use turbo_tasks_fs::{json::parse_json_with_source_context, FileContent, FileSystemPathVc};
use turbo_tasks_hash::hash_xxh3_hash64;
use turbopack_core::{
issue::IssueSeverity,
resolve::{
options::{
ImportMapResult, ImportMapResultVc, ImportMapping, ImportMappingReplacement,
@ -19,6 +17,7 @@ use turbopack_core::{
},
virtual_asset::VirtualAssetVc,
};
use turbopack_node::execution_context::ExecutionContextVc;
use self::options::FontWeights;
use crate::{
@ -123,13 +122,17 @@ impl ImportMappingReplacement for NextFontGoogleReplacer {
#[turbo_tasks::value(shared)]
pub struct NextFontGoogleCssModuleReplacer {
project_path: FileSystemPathVc,
execution_context: ExecutionContextVc,
}
#[turbo_tasks::value_impl]
impl NextFontGoogleCssModuleReplacerVc {
#[turbo_tasks::function]
pub fn new(project_path: FileSystemPathVc) -> Self {
Self::cell(NextFontGoogleCssModuleReplacer { project_path })
pub fn new(project_path: FileSystemPathVc, execution_context: ExecutionContextVc) -> Self {
Self::cell(NextFontGoogleCssModuleReplacer {
project_path,
execution_context,
})
}
}
@ -158,22 +161,31 @@ impl ImportMappingReplacement for NextFontGoogleCssModuleReplacer {
let css_virtual_path = next_js_file_path("internal/font/google")
.join(&format!("/{}.module.css", get_request_id(*query_vc).await?));
// When running Next.js integration tests, use the mock data available in
// process.env.NEXT_FONT_GOOGLE_MOCKED_RESPONSES instead of making real
// requests to Google Fonts.
#[cfg(feature = "__internal_nextjs_integration_test")]
let stylesheet_str = get_mock_stylesheet(&stylesheet_url.await?, self.execution_context)
.await?
.map(StringVc::cell);
#[cfg(not(feature = "__internal_nextjs_integration_test"))]
let stylesheet_str = {
use turbo_tasks_fetch::fetch;
use turbopack_core::issue::IssueSeverity;
let stylesheet_res = fetch(
stylesheet_url,
OptionStringVc::cell(Some(
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like \
Gecko) Chrome/104.0.0.0 Safari/537.36"
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, \
like Gecko) Chrome/104.0.0.0 Safari/537.36"
.to_owned(),
)),
)
.await?;
let stylesheet = match &*stylesheet_res {
Ok(r) => Some(
update_stylesheet(r.await?.body.to_string(), options, scoped_font_family)
.await?
.clone_value(),
),
match &*stylesheet_res {
Ok(r) => Some(r.await?.body.to_string()),
Err(err) => {
// Inform the user of the failure to retreive the stylesheet, but don't
// propagate this error. We don't want e.g. offline connections to prevent page
@ -188,6 +200,16 @@ impl ImportMappingReplacement for NextFontGoogleCssModuleReplacer {
None
}
}
};
let stylesheet = match stylesheet_str {
Some(s) => Some(
update_stylesheet(s, options, scoped_font_family)
.await?
.clone_value(),
),
None => None,
};
let properties = get_font_css_properties(scoped_font_family, options).await?;
@ -252,11 +274,16 @@ async fn update_stylesheet(
#[turbo_tasks::function]
async fn get_scoped_font_family(query_vc: QueryMapVc) -> Result<StringVc> {
let options = font_options_from_query_map(query_vc).await?;
let hash = {
let mut hash = format!("{:x?}", *get_request_hash(query_vc).await?);
hash.truncate(6);
hash
};
Ok(StringVc::cell(format!(
"__{}_{:x?}",
"__{}_{}",
options.font_family.replace(' ', "_"),
*get_request_hash(query_vc).await?
hash
)))
}
@ -378,3 +405,99 @@ async fn font_options_from_query_map(query: QueryMapVc) -> Result<NextFontGoogle
self::options::options_from_request(&parse_json_with_source_context(json)?, &FONT_DATA)
.map(NextFontGoogleOptionsVc::cell)
}
#[cfg(feature = "__internal_nextjs_integration_test")]
async fn get_mock_stylesheet(
url: &str,
execution_context: ExecutionContextVc,
) -> Result<Option<String>> {
use std::{collections::HashMap, path::Path};
use turbo_tasks::{CompletionVc, Value};
use turbo_tasks_env::{CommandLineProcessEnvVc, ProcessEnv};
use turbo_tasks_fs::{
json::parse_json_rope_with_source_context, DiskFileSystemVc, File, FileSystem,
};
use turbopack::evaluate_context::node_evaluate_asset_context;
use turbopack_core::{context::AssetContext, ident::AssetIdentVc};
use turbopack_ecmascript::{
EcmascriptInputTransformsVc, EcmascriptModuleAssetType, EcmascriptModuleAssetVc,
};
use turbopack_node::{
evaluate::{evaluate, JavaScriptValue},
execution_context::ExecutionContext,
};
let env = CommandLineProcessEnvVc::new().as_process_env();
let mocked_response_js = &*env.read("NEXT_FONT_GOOGLE_MOCKED_RESPONSES").await?;
let mocked_response_js = mocked_response_js
.as_ref()
.context("Expected env NEXT_FONT_GOOGLE_MOCKED_RESPONSES")?;
let response_path = Path::new(&mocked_response_js);
let mock_fs = DiskFileSystemVc::new(
"mock".to_string(),
response_path
.parent()
.context("Must be valid path")?
.to_str()
.context("Must exist")?
.to_string(),
)
.as_file_system();
let ExecutionContext {
env,
project_root: _,
intermediate_output_path,
} = *execution_context.await?;
let context = node_evaluate_asset_context(None, None);
let loader_path = mock_fs.root().join("loader.js");
let mocked_response_asset = EcmascriptModuleAssetVc::new(
VirtualAssetVc::new(
loader_path,
File::from(format!(
"import data from './{}'; export default function load() {{ return data; }};",
response_path
.file_name()
.context("Must exist")?
.to_string_lossy(),
))
.into(),
)
.into(),
context,
Value::new(EcmascriptModuleAssetType::Ecmascript),
EcmascriptInputTransformsVc::cell(vec![]),
context.compile_time_info(),
)
.into();
let root = mock_fs.root();
let val = evaluate(
loader_path,
mocked_response_asset,
root,
env,
AssetIdentVc::from_path(loader_path),
context,
intermediate_output_path,
None,
vec![],
CompletionVc::immutable(),
/* debug */ false,
)
.await?;
match &*val {
JavaScriptValue::Value(val) => {
let mock_map: HashMap<String, Option<String>> =
parse_json_rope_with_source_context(val)?;
Ok((mock_map.get(url).context("url not found")?).clone())
}
JavaScriptValue::Error => panic!("Unexpected error evaluating JS"),
JavaScriptValue::Stream(_) => {
unimplemented!("Stream not supported now");
}
}
}

View file

@ -144,7 +144,7 @@ pub fn options_from_request(
let display = argument
.and_then(|a| a.display.to_owned())
.unwrap_or_else(|| "optional".to_owned());
.unwrap_or_else(|| "swap".to_owned());
if !ALLOWED_DISPLAY_VALUES.contains(&display.as_ref()) {
return Err(anyhow!(
@ -247,7 +247,7 @@ mod tests {
font_family: "ABeeZee".to_owned(),
weights: FontWeights::Variable,
styles: indexset! {"normal".to_owned()},
display: "optional".to_owned(),
display: "swap".to_owned(),
preload: true,
selected_variable_axes: None,
fallback: None,

View file

@ -116,11 +116,13 @@ pub(crate) fn get_stylesheet_url(
if axes.wght.is_empty() {
let mut variant = vec![];
if let Some(variable_axes) = &axes.variable_axes {
if !variable_axes.is_empty() {
for (key, val) in variable_axes {
variant.push((key.as_str(), &val[..]));
}
}
variants.push(variant);
}
}
} else {
for wght in &axes.wght {
if axes.ital.is_empty() {
@ -135,6 +137,10 @@ pub(crate) fn get_stylesheet_url(
} else {
for ital in &axes.ital {
let mut variant = vec![];
// If Normal is the only requested variant, it's safe to omit the ital axis
// entirely. Otherwise, include all variants.
if matches!(ital, FontItal::Italic) || axes.ital.len() > 1 {
variant.push((
"ital",
match ital {
@ -142,6 +148,8 @@ pub(crate) fn get_stylesheet_url(
FontItal::Italic => "1",
},
));
}
variant.push(("wght", &wght[..]));
if let Some(variable_axes) = &axes.variable_axes {
for (key, val) in variable_axes {
@ -170,9 +178,15 @@ pub(crate) fn get_stylesheet_url(
});
}
let first_variant = variants
.first()
.context("Requires at least one font variant")?;
let first_variant = variants.first();
match first_variant {
None => Ok(format!(
"{}?family={}&display={}",
root_url,
font_family.replace(' ', "+"),
display
)),
Some(first_variant) => {
// Always use the first variant's keys. There's an implicit invariant from the
// code above that the keys across each variant are identical, and therefore
// will be sorted identically across variants.
@ -195,6 +209,7 @@ pub(crate) fn get_stylesheet_url(
})
.collect::<Vec<String>>();
variant_values.sort();
// An encoding of the series of sorted variant values, with variants delimited
// by `;` and the values within a variant delimited by `,` e.g.
// `"0,10..100,500;1,10.100;500"`
@ -209,6 +224,8 @@ pub(crate) fn get_stylesheet_url(
display
))
}
}
}
#[cfg(test)]
mod tests {
@ -418,7 +435,7 @@ mod tests {
},
"optional"
)?,
"https://fonts.googleapis.com/css2?family=Roboto+Mono:ital,wght@0,500&display=optional"
"https://fonts.googleapis.com/css2?family=Roboto+Mono:wght@500&display=optional"
);
Ok(())
@ -441,7 +458,7 @@ mod tests {
},
"optional"
)?,
"https://fonts.googleapis.com/css2?family=Roboto+Serif:ital,opsz,wdth,wght,GRAD@0,8..144,50..150,500,-50..100&display=optional"
"https://fonts.googleapis.com/css2?family=Roboto+Serif:opsz,wdth,wght,GRAD@8..144,50..150,500,-50..100&display=optional"
);
Ok(())
@ -493,6 +510,44 @@ mod tests {
Ok(())
}
#[test]
fn test_stylesheet_url_variable_font_without_anything() -> Result<()> {
assert_eq!(
get_stylesheet_url(
GOOGLE_FONTS_STYLESHEET_URL,
"Nabla",
&FontAxes {
wght: indexset! {},
ital: indexset! {},
variable_axes: None,
},
"swap"
)?,
"https://fonts.googleapis.com/css2?family=Nabla&display=swap"
);
Ok(())
}
#[test]
fn test_stylesheet_url_variable_font_with_empty_variable_axes() -> Result<()> {
assert_eq!(
get_stylesheet_url(
GOOGLE_FONTS_STYLESHEET_URL,
"Nabla",
&FontAxes {
wght: indexset! {},
ital: indexset! {},
variable_axes: Some(vec![]),
},
"swap"
)?,
"https://fonts.googleapis.com/css2?family=Nabla&display=swap"
);
Ok(())
}
#[test]
fn test_stylesheet_url_no_variable() -> Result<()> {
assert_eq!(

View file

@ -16,6 +16,7 @@ use turbopack_core::{
resolve, AliasPattern, ExportsValue, ResolveAliasMapVc,
},
};
use turbopack_node::execution_context::ExecutionContextVc;
use crate::{
embed_js::{next_js_fs, VIRTUAL_PACKAGE_NAME},
@ -31,10 +32,11 @@ pub async fn get_next_client_import_map(
project_path: FileSystemPathVc,
ty: Value<ClientContextType>,
next_config: NextConfigVc,
execution_context: ExecutionContextVc,
) -> Result<ImportMapVc> {
let mut import_map = ImportMap::empty();
insert_next_shared_aliases(&mut import_map, project_path).await?;
insert_next_shared_aliases(&mut import_map, project_path, execution_context).await?;
insert_alias_option(
&mut import_map,
@ -166,10 +168,11 @@ pub async fn get_next_server_import_map(
project_path: FileSystemPathVc,
ty: Value<ServerContextType>,
next_config: NextConfigVc,
execution_context: ExecutionContextVc,
) -> Result<ImportMapVc> {
let mut import_map = ImportMap::empty();
insert_next_shared_aliases(&mut import_map, project_path).await?;
insert_next_shared_aliases(&mut import_map, project_path, execution_context).await?;
insert_alias_option(
&mut import_map,
@ -223,10 +226,11 @@ pub async fn get_next_edge_import_map(
project_path: FileSystemPathVc,
ty: Value<ServerContextType>,
next_config: NextConfigVc,
execution_context: ExecutionContextVc,
) -> Result<ImportMapVc> {
let mut import_map = ImportMap::empty();
insert_next_shared_aliases(&mut import_map, project_path).await?;
insert_next_shared_aliases(&mut import_map, project_path, execution_context).await?;
insert_alias_option(
&mut import_map,
@ -354,6 +358,7 @@ pub async fn insert_next_server_special_aliases(
pub async fn insert_next_shared_aliases(
import_map: &mut ImportMap,
project_path: FileSystemPathVc,
execution_context: ExecutionContextVc,
) -> Result<()> {
let package_root = next_js_fs().root();
@ -384,7 +389,10 @@ pub async fn insert_next_shared_aliases(
import_map.insert_alias(
AliasPattern::exact("@vercel/turbopack-next/internal/font/google/cssmodule.module.css"),
ImportMapping::Dynamic(NextFontGoogleCssModuleReplacerVc::new(project_path).into()).into(),
ImportMapping::Dynamic(
NextFontGoogleCssModuleReplacerVc::new(project_path, execution_context).into(),
)
.into(),
);
import_map.insert_singleton_alias("@swc/helpers", get_next_package(project_path));

View file

@ -47,8 +47,10 @@ pub async fn get_server_resolve_options_context(
project_path: FileSystemPathVc,
ty: Value<ServerContextType>,
next_config: NextConfigVc,
execution_context: ExecutionContextVc,
) -> Result<ResolveOptionsContextVc> {
let next_server_import_map = get_next_server_import_map(project_path, ty, next_config);
let next_server_import_map =
get_next_server_import_map(project_path, ty, next_config, execution_context);
let foreign_code_context_condition = foreign_code_context_condition(next_config).await?;
let root_dir = project_path.root().resolve().await?;

View file

@ -105,7 +105,7 @@ pub async fn create_page_source(
next_config,
);
let client_resolve_options_context =
get_client_resolve_options_context(project_path, client_ty, next_config);
get_client_resolve_options_context(project_path, client_ty, next_config, execution_context);
let client_chunking_context = get_client_chunking_context(
project_path,
@ -115,7 +115,7 @@ pub async fn create_page_source(
);
let client_runtime_entries =
get_client_runtime_entries(project_path, env, client_ty, next_config);
get_client_runtime_entries(project_path, env, client_ty, next_config, execution_context);
let next_client_transition = NextClientTransition {
is_app: false,
@ -144,7 +144,7 @@ pub async fn create_page_source(
)
.build();
let edge_resolve_options_context =
get_edge_resolve_options_context(project_path, server_ty, next_config);
get_edge_resolve_options_context(project_path, server_ty, next_config, execution_context);
let next_edge_transition = NextEdgeTransition {
edge_compile_time_info,
@ -160,7 +160,7 @@ pub async fn create_page_source(
let server_compile_time_info = get_server_compile_time_info(server_ty, env, server_addr);
let server_resolve_options_context =
get_server_resolve_options_context(project_path, server_ty, next_config);
get_server_resolve_options_context(project_path, server_ty, next_config, execution_context);
let server_module_options_context =
get_server_module_options_context(project_path, execution_context, server_ty, next_config);

View file

@ -262,6 +262,7 @@ fn edge_transition_map(
project_path: FileSystemPathVc,
output_path: FileSystemPathVc,
next_config: NextConfigVc,
execution_context: ExecutionContextVc,
) -> TransitionsByNameVc {
let edge_compile_time_info = get_edge_compile_time_info(server_addr, Value::new(Middleware));
@ -278,6 +279,7 @@ fn edge_transition_map(
project_path,
Value::new(ServerContextType::Middleware),
next_config,
execution_context,
);
let next_edge_transition = NextEdgeTransition {
@ -322,6 +324,7 @@ pub async fn route(
project_path,
intermediate_output_path,
next_config,
execution_context,
)),
);

View file

@ -48,7 +48,7 @@ pub async fn create_web_entry_source(
compile_time_info.environment(),
ty,
);
let entries = get_client_runtime_entries(project_path, env, ty, next_config);
let entries = get_client_runtime_entries(project_path, env, ty, next_config, execution_context);
let runtime_entries = entries.resolve_entries(context);

View file

@ -3,9 +3,9 @@ when:
path: /css2
query_param:
- name: family
value: "Inter:ital,wght@0,100..900"
value: "Inter:wght@100..900"
- name: display
value: optional
value: swap
then:
status: 200
body: |-
@ -14,7 +14,7 @@ then:
font-family: 'Inter';
font-style: normal;
font-weight: 100 900;
font-display: optional;
font-display: swap;
src: url(https://fonts.gstatic.com/s/inter/v12/UcC73FwrK3iLTeHuS_fvQtMwCp50KnMa2JL7W0Q5n-wU.woff2) format('woff2');
unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;
}
@ -23,7 +23,7 @@ then:
font-family: 'Inter';
font-style: normal;
font-weight: 100 900;
font-display: optional;
font-display: swap;
src: url(https://fonts.gstatic.com/s/inter/v12/UcC73FwrK3iLTeHuS_fvQtMwCp50KnMa0ZL7W0Q5n-wU.woff2) format('woff2');
unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}
@ -32,7 +32,7 @@ then:
font-family: 'Inter';
font-style: normal;
font-weight: 100 900;
font-display: optional;
font-display: swap;
src: url(https://fonts.gstatic.com/s/inter/v12/UcC73FwrK3iLTeHuS_fvQtMwCp50KnMa2ZL7W0Q5n-wU.woff2) format('woff2');
unicode-range: U+1F00-1FFF;
}
@ -41,7 +41,7 @@ then:
font-family: 'Inter';
font-style: normal;
font-weight: 100 900;
font-display: optional;
font-display: swap;
src: url(https://fonts.gstatic.com/s/inter/v12/UcC73FwrK3iLTeHuS_fvQtMwCp50KnMa1pL7W0Q5n-wU.woff2) format('woff2');
unicode-range: U+0370-03FF;
}
@ -50,7 +50,7 @@ then:
font-family: 'Inter';
font-style: normal;
font-weight: 100 900;
font-display: optional;
font-display: swap;
src: url(https://fonts.gstatic.com/s/inter/v12/UcC73FwrK3iLTeHuS_fvQtMwCp50KnMa2pL7W0Q5n-wU.woff2) format('woff2');
unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+1EA0-1EF9, U+20AB;
}
@ -59,7 +59,7 @@ then:
font-family: 'Inter';
font-style: normal;
font-weight: 100 900;
font-display: optional;
font-display: swap;
src: url(https://fonts.gstatic.com/s/inter/v12/UcC73FwrK3iLTeHuS_fvQtMwCp50KnMa25L7W0Q5n-wU.woff2) format('woff2');
unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@ -68,7 +68,7 @@ then:
font-family: 'Inter';
font-style: normal;
font-weight: 100 900;
font-display: optional;
font-display: swap;
src: url(https://fonts.gstatic.com/s/inter/v12/UcC73FwrK3iLTeHuS_fvQtMwCp50KnMa1ZL7W0Q5nw.woff2) format('woff2');
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

View file

@ -17,7 +17,7 @@ function runTests() {
expect(interNoArgs).toEqual({
className: "className__inter_34ab8b4d__7bdff866",
style: {
fontFamily: "'__Inter_34ab8b4d'",
fontFamily: "'__Inter_34ab8b'",
fontStyle: "normal",
},
});

View file

@ -3,9 +3,9 @@ when:
path: /css2
query_param:
- name: family
value: "Inter:ital,wght@0,100..900"
value: "Inter:wght@100..900"
- name: display
value: optional
value: swap
then:
status: 200
body: |-
@ -14,7 +14,7 @@ then:
font-family: 'Inter';
font-style: normal;
font-weight: 100 900;
font-display: optional;
font-display: swap;
src: url(https://fonts.gstatic.com/s/inter/v12/UcC73FwrK3iLTeHuS_fvQtMwCp50KnMa2JL7W0Q5n-wU.woff2) format('woff2');
unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;
}
@ -23,7 +23,7 @@ then:
font-family: 'Inter';
font-style: normal;
font-weight: 100 900;
font-display: optional;
font-display: swap;
src: url(https://fonts.gstatic.com/s/inter/v12/UcC73FwrK3iLTeHuS_fvQtMwCp50KnMa0ZL7W0Q5n-wU.woff2) format('woff2');
unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}
@ -32,7 +32,7 @@ then:
font-family: 'Inter';
font-style: normal;
font-weight: 100 900;
font-display: optional;
font-display: swap;
src: url(https://fonts.gstatic.com/s/inter/v12/UcC73FwrK3iLTeHuS_fvQtMwCp50KnMa2ZL7W0Q5n-wU.woff2) format('woff2');
unicode-range: U+1F00-1FFF;
}
@ -41,7 +41,7 @@ then:
font-family: 'Inter';
font-style: normal;
font-weight: 100 900;
font-display: optional;
font-display: swap;
src: url(https://fonts.gstatic.com/s/inter/v12/UcC73FwrK3iLTeHuS_fvQtMwCp50KnMa1pL7W0Q5n-wU.woff2) format('woff2');
unicode-range: U+0370-03FF;
}
@ -50,7 +50,7 @@ then:
font-family: 'Inter';
font-style: normal;
font-weight: 100 900;
font-display: optional;
font-display: swap;
src: url(https://fonts.gstatic.com/s/inter/v12/UcC73FwrK3iLTeHuS_fvQtMwCp50KnMa2pL7W0Q5n-wU.woff2) format('woff2');
unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+1EA0-1EF9, U+20AB;
}
@ -59,7 +59,7 @@ then:
font-family: 'Inter';
font-style: normal;
font-weight: 100 900;
font-display: optional;
font-display: swap;
src: url(https://fonts.gstatic.com/s/inter/v12/UcC73FwrK3iLTeHuS_fvQtMwCp50KnMa25L7W0Q5n-wU.woff2) format('woff2');
unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@ -68,7 +68,7 @@ then:
font-family: 'Inter';
font-style: normal;
font-weight: 100 900;
font-display: optional;
font-display: swap;
src: url(https://fonts.gstatic.com/s/inter/v12/UcC73FwrK3iLTeHuS_fvQtMwCp50KnMa1ZL7W0Q5nw.woff2) format('woff2');
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

View file

@ -20,7 +20,7 @@ function runTests() {
expect(interNoArgs).toEqual({
className: "className__inter_34ab8b4d__7bdff866",
style: {
fontFamily: "'__Inter_34ab8b4d'",
fontFamily: "'__Inter_34ab8b'",
fontStyle: "normal",
},
});
@ -29,7 +29,7 @@ function runTests() {
it("includes a rule styling the exported className", async () => {
const matchingRule = await getRuleMatchingClassName(interNoArgs.className);
expect(matchingRule).toBeTruthy();
expect(matchingRule.style.fontFamily).toEqual("__Inter_34ab8b4d");
expect(matchingRule.style.fontFamily).toEqual("__Inter_34ab8b");
expect(matchingRule.style.fontStyle).toEqual("normal");
});
@ -37,7 +37,7 @@ function runTests() {
expect(interWithVariableName).toEqual({
className: "className__inter_c6e282f1__e152ac0c",
style: {
fontFamily: "'__Inter_c6e282f1'",
fontFamily: "'__Inter_c6e282'",
fontStyle: "normal",
},
variable: "variable__inter_c6e282f1__e152ac0c",
@ -47,7 +47,7 @@ function runTests() {
interWithVariableName.variable
);
expect(matchingRule.styleMap.get("--my-font").toString().trim()).toBe(
'"__Inter_c6e282f1"'
'"__Inter_c6e282"'
);
});
}

View file

@ -37,6 +37,10 @@ custom_allocator = ["turbo-malloc/custom_allocator"]
next-font-local = ["next-core/next-font-local"]
native-tls = ["next-core/native-tls"]
rustls-tls = ["next-core/rustls-tls"]
# Internal only. Enabled when building for the Next.js integration test suite.
__internal_nextjs_integration_test = [
"next-core/__internal_nextjs_integration_test",
]
[dependencies]
anyhow = { workspace = true, features = ["backtrace"] }