Files
61bf6f633f Turbopack: Fix next/font preloading for page.mdx (#88848)
## What?

This PR fixes font preloading for MDX pages in Turbopack and adds an e2e
test to verify the fix.

## Why?

When using `next/font` with MDX pages, font preloading was failing with
Turbopack because the LoaderTree was storing the **transformed module
path** instead of the **original source path**.

## The Bug

In Turbopack, MDX files are transformed by adding a `.tsx` extension:
- Source file: `app/page.mdx`
- After transform: `app/page.mdx.tsx`

The `create_module_tuple_code` function in `base_loader_tree.rs` was
using `module.ident().path()` (the transformed path) instead of the
original `path` parameter.

This caused a mismatch at runtime:
- Font manifest key: `[project]/app/page`
- LoaderTree stored: `[project]/app/page.mdx.tsx`
- After stripping `.tsx`: `[project]/app/page.mdx`
- **No match** → fonts not preloaded

## The Fix

Changed `crates/next-core/src/base_loader_tree.rs` to use the original
source path:

```rust
// Before
let module_path = module.ident().path().to_string().await?;

// After
let module_path = path.value_to_string().await?;
```

Now the LoaderTree stores `[project]/app/page.mdx`, which after
stripping `.mdx` at runtime becomes `[project]/app/page`, matching the
font manifest key.

## Test

Added `test/e2e/app-dir/mdx-font-preload/` which verifies:
1. MDX page renders correctly
2. Font class from layout is applied
3. Font is correctly preloaded

## How I tested these changes

```bash
pnpm test-start-turbo test/e2e/app-dir/mdx-font-preload/mdx-font-preload.test.ts
```

---------

Co-authored-by: Niklas Mischkulnig <[email protected]>
2026-01-22 15:56:50 +01:00

48 lines
1.5 KiB
TypeScript

import { nextTestSetup } from 'e2e-utils'
describe('mdx-font-preload', () => {
const { next } = nextTestSetup({
files: __dirname,
dependencies: {
'@next/mdx': 'canary',
'@mdx-js/loader': '^2.2.1',
'@mdx-js/react': '^2.2.1',
},
})
it('should render MDX page', async () => {
const browser = await next.browser('/')
expect(await browser.elementByCss('h1').text()).toBe('MDX Page')
expect(await browser.elementByCss('p').text()).toBe(
'This is an MDX page with font preloading.'
)
})
it('should apply font class from layout', async () => {
const browser = await next.browser('/')
const fontFamily = await browser.eval(
'getComputedStyle(document.body).fontFamily'
)
expect(fontFamily).toMatch(/myFont/)
})
it('should preload font from layout on MDX page', async () => {
const browser = await next.browser('/')
// Check for font preload link in DOM
const fontPreloadLinks = await browser.elementsByCss('link[as="font"]')
expect(fontPreloadLinks.length).toBeGreaterThan(0)
// Verify the preload link attributes
const rel = await fontPreloadLinks[0].getAttribute('rel')
const as = await fontPreloadLinks[0].getAttribute('as')
const type = await fontPreloadLinks[0].getAttribute('type')
const crossorigin = await fontPreloadLinks[0].getAttribute('crossorigin')
expect(rel).toBe('preload')
expect(as).toBe('font')
expect(type).toBe('font/woff2')
expect(crossorigin).toBe('')
})
})