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
1 change: 1 addition & 0 deletions crates/next-api/src/project.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1078,6 +1078,7 @@ impl Project {
no_mangling: self.no_mangling(),
scope_hoisting: self.next_config().turbo_scope_hoisting(self.next_mode()),
debug_ids: self.next_config().turbopack_debug_ids(),
should_use_absolute_url_references: self.next_config().inline_css(),
}))
}

Expand Down
5 changes: 4 additions & 1 deletion crates/next-core/src/next_client/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -427,6 +427,7 @@ pub struct ClientChunkingContextOptions {
pub no_mangling: Vc<bool>,
pub scope_hoisting: Vc<bool>,
pub debug_ids: Vc<bool>,
pub should_use_absolute_url_references: Vc<bool>,
}

#[turbo_tasks::function]
Expand All @@ -448,6 +449,7 @@ pub async fn get_client_chunking_context(
no_mangling,
scope_hoisting,
debug_ids,
should_use_absolute_url_references,
} = options;

let next_mode = mode.await?;
Expand Down Expand Up @@ -481,7 +483,8 @@ pub async fn get_client_chunking_context(
.current_chunk_method(CurrentChunkMethod::DocumentCurrentScript)
.export_usage(*export_usage.await?)
.module_id_strategy(module_id_strategy.to_resolved().await?)
.debug_ids(*debug_ids.await?);
.debug_ids(*debug_ids.await?)
.should_use_absolute_url_references(*should_use_absolute_url_references.await?);

if next_mode.is_development() {
builder = builder
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,13 @@ export function getClientStyleLoader({
isAppDir,
isDevelopment,
assetPrefix,
experimentalInlineCss,
}: {
hasAppDir: boolean
isAppDir?: boolean
isDevelopment: boolean
assetPrefix: string
experimentalInlineCss?: boolean
}): webpack.RuleSetUseItem {
const isRspack = Boolean(process.env.NEXT_RSPACK)
const shouldEnableApp = typeof isAppDir === 'boolean' ? isAppDir : hasAppDir
Expand Down Expand Up @@ -52,7 +54,7 @@ export function getClientStyleLoader({
return {
loader: MiniCssExtractPlugin.loader,
options: {
publicPath: `${assetPrefix}/_next/`,
publicPath: experimentalInlineCss ? '/' : `${assetPrefix}/_next/`,
esModule: false,
},
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ export function getGlobalCssLoader(
isAppDir: ctx.isAppDir,
isDevelopment: ctx.isDevelopment,
assetPrefix: ctx.assetPrefix,
experimentalInlineCss: ctx.experimental.inlineCss,
})
)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ export function getCssModuleLoader(
isAppDir: ctx.isAppDir,
isDevelopment: ctx.isDevelopment,
assetPrefix: ctx.assetPrefix,
experimentalInlineCss: ctx.experimental.inlineCss,
})
)
}
Expand Down
Binary file not shown.
6 changes: 6 additions & 0 deletions test/e2e/app-dir/app-inline-css/app/font.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import localFont from 'next/font/local'

export const font = localFont({
src: './font-noto-sans.woff2',
variable: '--font-1',
})
4 changes: 4 additions & 0 deletions test/e2e/app-dir/app-inline-css/app/global.css
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
p {
color: yellow;
}

body {
font-family: var(--font-1);
}
3 changes: 2 additions & 1 deletion test/e2e/app-dir/app-inline-css/app/layout.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import Link from 'next/link'
import './global.css'
import { font } from './font'

export default function RootLayout({ children }) {
return (
<html>
<html className={font.variable}>
<body>
<nav>
<Link href="/" prefetch={false}>
Expand Down
11 changes: 10 additions & 1 deletion test/e2e/app-dir/app-inline-css/app/page.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,12 @@
import { font } from './font'

export default function Home() {
return <p>Home</p>
return (
<div>
<p>Home</p>
<p id="with-font" className={font.className}>
Text with custom font
</p>
</div>
)
}
41 changes: 41 additions & 0 deletions test/e2e/app-dir/app-inline-css/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,5 +52,46 @@ describe('app dir - css - experimental inline css', () => {
expect(styleTags).toHaveLength(1)
expect(linkTags).toHaveLength(0)
})

it('should apply font styles correctly via className', async () => {
const browser = await next.browser('/')

const fontElement = await browser.elementByCss('#with-font')
const computedFontFamily = await fontElement.getComputedCss('fontFamily')

expect(computedFontFamily).toBeTruthy()
expect(computedFontFamily).not.toBe('Times')
})

it('should apply font styles correctly via CSS variable', async () => {
const browser = await next.browser('/')

const bodyElement = await browser.elementByCss('body')
const computedFontFamily = await bodyElement.getComputedCss('fontFamily')

expect(computedFontFamily).toBeTruthy()
expect(computedFontFamily).not.toBe('Times')
})

it('should inline font-face with absolute src URL', async () => {
const $ = await next.render$('/')

const styleTag = $('style')
expect(styleTag.length).toBeGreaterThan(0)

const styleContent = styleTag.html()
expect(styleContent).toMatch(/@font-face/)
expect(styleContent).toMatch(/font-family/)

const srcMatch = styleContent.match(/src:\s*url\(([^)]+)\)/)
expect(srcMatch).toBeTruthy()

const fontUrl = srcMatch[1].replace(/['"]/g, '')
expect(fontUrl).toMatch(/^\//)

const res = await next.fetch(fontUrl)
expect(res.status).toBe(200)
expect(res.headers.get('content-type')).toContain('font')
})
})
})
17 changes: 17 additions & 0 deletions turbopack/crates/turbopack-browser/src/chunking_context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,15 @@ impl BrowserChunkingContextBuilder {
self
}

pub fn should_use_absolute_url_references(
mut self,
should_use_absolute_url_references: bool,
) -> Self {
self.chunking_context.should_use_absolute_url_references =
should_use_absolute_url_references;
self
}

pub fn asset_root_path_override(mut self, tag: RcStr, path: FileSystemPath) -> Self {
self.chunking_context.asset_root_paths.insert(tag, path);
self
Expand Down Expand Up @@ -278,6 +287,8 @@ pub struct BrowserChunkingContext {
export_usage: Option<ResolvedVc<ExportUsageInfo>>,
/// The chunking configs
chunking_configs: Vec<(ResolvedVc<Box<dyn ChunkType>>, ChunkingConfig)>,
/// Whether to use absolute URLs for static assets (e.g. in CSS: `url("/absolute/path")`)
should_use_absolute_url_references: bool,
}

impl BrowserChunkingContext {
Expand Down Expand Up @@ -322,6 +333,7 @@ impl BrowserChunkingContext {
module_id_strategy: ResolvedVc::upcast(DevModuleIdStrategy::new_resolved()),
export_usage: None,
chunking_configs: Default::default(),
should_use_absolute_url_references: false,
},
}
}
Expand Down Expand Up @@ -629,6 +641,11 @@ impl ChunkingContext for BrowserChunkingContext {
self.minify_type.cell()
}

#[turbo_tasks::function]
fn should_use_absolute_url_references(&self) -> Vc<bool> {
Vc::cell(self.should_use_absolute_url_references)
}

#[turbo_tasks::function]
async fn chunk_group(
self: ResolvedVc<Self>,
Expand Down
5 changes: 5 additions & 0 deletions turbopack/crates/turbopack-core/src/chunk/chunking_context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -239,6 +239,11 @@ pub trait ChunkingContext {
MinifyType::NoMinify.cell()
}

#[turbo_tasks::function]
fn should_use_absolute_url_references(self: Vc<Self>) -> Vc<bool> {
Vc::cell(false)
}

#[turbo_tasks::function]
fn async_loader_chunk_item(
&self,
Expand Down
19 changes: 13 additions & 6 deletions turbopack/crates/turbopack-css/src/references/url.rs
Original file line number Diff line number Diff line change
Expand Up @@ -101,15 +101,22 @@ pub async fn resolve_url_reference(
url: Vc<UrlAssetReference>,
chunking_context: Vc<Box<dyn ChunkingContext>>,
) -> Result<Vc<Option<RcStr>>> {
let context_path = chunking_context.chunk_root_path().await?;

if let ReferencedAsset::Some(asset) = &*url.get_referenced_asset(chunking_context).await? {
let path = asset.path().await?;
let relative_path = context_path
.get_relative_path_to(&path)
.unwrap_or_else(|| format!("/{}", path.path).into());

return Ok(Vc::cell(Some(relative_path)));
let url_path = if *chunking_context
.should_use_absolute_url_references()
.await?
{
format!("/{}", path.path).into()
} else {
let context_path = chunking_context.chunk_root_path().await?;
context_path
.get_relative_path_to(&path)
.unwrap_or_else(|| format!("/{}", path.path).into())
};

return Ok(Vc::cell(Some(url_path)));
}

Ok(Vc::cell(None))
Expand Down
Loading