diff --git a/app/navigation.ts b/app/navigation.ts
new file mode 100644
index 000000000000..e69de29bb2d1
diff --git a/packages/next/src/build/webpack/config/blocks/css/index.ts b/packages/next/src/build/webpack/config/blocks/css/index.ts
index 965b983e1502..08aef7d270d4 100644
--- a/packages/next/src/build/webpack/config/blocks/css/index.ts
+++ b/packages/next/src/build/webpack/config/blocks/css/index.ts
@@ -208,6 +208,30 @@ export const css = curry(async function css(
const fns: ConfigurationFn[] = []
+ // Handle raw-loader imports before any CSS processing
+ // This prevents CSS files imported with raw-loader from being processed as CSS
+ fns.push(
+ loader({
+ oneOf: [
+ {
+ test: regexLikeCss,
+ resourceQuery: /raw/,
+ type: 'asset/source',
+ },
+ {
+ test: regexLikeCss,
+ resourceQuery: /raw-loader/,
+ type: 'asset/source',
+ },
+ {
+ test: regexLikeCss,
+ resourceQuery: /!!raw-loader!/,
+ type: 'asset/source',
+ },
+ ],
+ })
+ )
+
const googleLoader = require.resolve(
'next/dist/compiled/@next/font/google/loader'
)
diff --git a/src/app/MdxLoader.jsx b/src/app/MdxLoader.jsx
new file mode 100644
index 000000000000..065d18ba9926
--- /dev/null
+++ b/src/app/MdxLoader.jsx
@@ -0,0 +1,24 @@
+'use client'
+
+import React from 'react'
+
+// This will be a mapping object for all your MDX files
+import StuffMdx from './stuff.mdx'
+import AnotherMdx from './another.mdx'
+// ... import all your MDX files
+
+const mdxComponents = {
+ './stuff.mdx': StuffMdx,
+ './another.mdx': AnotherMdx,
+ // ... map all your imports
+}
+
+export default function MdxLoader({ filePath }) {
+ const Component = mdxComponents[filePath]
+
+ if (!Component) {
+ return
MDX file not found: {filePath}
+ }
+
+ return
+}
diff --git a/src/app/MdxWrapper.jsx b/src/app/MdxWrapper.jsx
new file mode 100644
index 000000000000..c1e371c20a2f
--- /dev/null
+++ b/src/app/MdxWrapper.jsx
@@ -0,0 +1,27 @@
+'use client'
+
+import React, { useState, useEffect } from 'react'
+
+export default function MdxWrapper({ filePath }) {
+ const [Component, setComponent] = useState(null)
+ const [error, setError] = useState(null)
+
+ useEffect(() => {
+ async function loadMdx() {
+ try {
+ const module = await import(`${filePath}`)
+ setComponent(() => module.default)
+ } catch (err) {
+ console.error(`Error loading MDX file: ${filePath}`, err)
+ setError(err)
+ }
+ }
+
+ loadMdx()
+ }, [filePath])
+
+ if (error) return Error loading MDX content
+ if (!Component) return Loading...
+
+ return
+}
diff --git a/src/app/navigation.ts b/src/app/navigation.ts
new file mode 100644
index 000000000000..b62c182388eb
--- /dev/null
+++ b/src/app/navigation.ts
@@ -0,0 +1,11 @@
+import { redirect as nextRedirect } from 'next/dist/client/components/redirect'
+
+export function redirect(path: string): ReturnType {
+ if (path === '' || path === undefined) {
+ throw new Error(
+ 'Redirect path cannot be empty. This would cause an infinite loop.'
+ )
+ }
+
+ return nextRedirect(path)
+}
diff --git a/src/app/page.jsx b/src/app/page.jsx
new file mode 100644
index 000000000000..d2ce51e1bd1f
--- /dev/null
+++ b/src/app/page.jsx
@@ -0,0 +1,22 @@
+import { Suspense } from 'react'
+// import { redirect } from './navigation' - removed
+
+// Instead of importing dynamically, create an async component
+async function MdxContent({ filePath }) {
+ // This works in a server component
+ const { default: Content } = await import(`${filePath}`)
+ return
+}
+
+export default function Home() {
+ // This will now throw an error instead of causing an infinite loop
+ // redirect("");
+
+ return (
+
+ Loading MDX...
}>
+
+
+
+ )
+}
diff --git a/src/app/utils/mdxUtils.js b/src/app/utils/mdxUtils.js
new file mode 100644
index 000000000000..0cca0a530491
--- /dev/null
+++ b/src/app/utils/mdxUtils.js
@@ -0,0 +1,14 @@
+import fs from 'fs'
+import path from 'path'
+
+// This function can be used at build time to generate a mapping of MDX files
+export function getMdxFiles(dir) {
+ const mdxDir = path.join(process.cwd(), dir)
+ const filenames = fs.readdirSync(mdxDir)
+ const mdxFiles = filenames.filter((name) => name.endsWith('.mdx'))
+
+ return mdxFiles.map((filename) => ({
+ filename,
+ path: `${dir}/${filename}`,
+ }))
+}
diff --git a/test/integration/css-fixtures/raw-loader-import/next.config.js b/test/integration/css-fixtures/raw-loader-import/next.config.js
new file mode 100644
index 000000000000..b84b3fb8f9e7
--- /dev/null
+++ b/test/integration/css-fixtures/raw-loader-import/next.config.js
@@ -0,0 +1,14 @@
+/** @type {import('next').NextConfig} */
+const nextConfig = {
+ webpack: (config) => {
+ // This is the problematic configuration mentioned in the GitHub issue
+ // It should work with our fix
+ config.module.rules.push({
+ resourceQuery: /raw/,
+ type: 'asset/source',
+ })
+ return config
+ },
+}
+
+module.exports = nextConfig
diff --git a/test/integration/css-fixtures/raw-loader-import/pages/index.js b/test/integration/css-fixtures/raw-loader-import/pages/index.js
new file mode 100644
index 000000000000..79a1ff684cf8
--- /dev/null
+++ b/test/integration/css-fixtures/raw-loader-import/pages/index.js
@@ -0,0 +1,44 @@
+import React from 'react'
+
+// Import CSS with raw-loader - this should return raw source, not processed CSS
+const rawCss = require('!!raw-loader!./styles.css')
+
+export default function HomePage() {
+ return (
+
+
Raw Loader Test
+
+ This page tests that CSS imported with raw-loader returns raw source
+ instead of processed CSS.
+
+
+
Raw CSS Content:
+
+ {rawCss}
+
+
+
Test Results:
+
+ -
+ If the CSS content above shows raw CSS (like{' '}
+
+ .test {'{'} color: red; {'}'}
+
+ ), the fix is working ✅
+
+ -
+ If the page has a red background (from the CSS being applied), the fix
+ is not working ❌
+
+
+
+ )
+}
diff --git a/test/integration/css-fixtures/raw-loader-import/pages/styles.css b/test/integration/css-fixtures/raw-loader-import/pages/styles.css
new file mode 100644
index 000000000000..3f7475472afc
--- /dev/null
+++ b/test/integration/css-fixtures/raw-loader-import/pages/styles.css
@@ -0,0 +1,14 @@
+/* This CSS file is imported with raw-loader */
+/* If the fix is working, this should be returned as raw text, not applied as styles */
+
+body {
+ background-color: red !important;
+ color: white !important;
+}
+
+.test {
+ color: red;
+ font-weight: bold;
+}
+
+/* This should not be applied to the page when imported with raw-loader */
diff --git a/test/integration/css-fixtures/raw-loader-import/test/raw-loader.test.js b/test/integration/css-fixtures/raw-loader-import/test/raw-loader.test.js
new file mode 100644
index 000000000000..1d562563d0a6
--- /dev/null
+++ b/test/integration/css-fixtures/raw-loader-import/test/raw-loader.test.js
@@ -0,0 +1,46 @@
+/* eslint-env jest */
+import { join } from 'path'
+import { createNext, FileRef } from 'e2e-utils'
+import { fetchViaHTTP } from 'next-test-utils'
+
+describe('Raw Loader CSS Import', () => {
+ let next
+
+ beforeAll(async () => {
+ const files = {
+ 'pages/index.js': new FileRef(join(__dirname, '../pages/index.js')),
+ 'pages/styles.css': new FileRef(join(__dirname, '../pages/styles.css')),
+ 'next.config.js': new FileRef(join(__dirname, '../next.config.js')),
+ }
+
+ next = await createNext({
+ files,
+ dependencies: {
+ 'raw-loader': '^4.0.2',
+ },
+ })
+ })
+
+ afterAll(async () => {
+ await next.destroy()
+ })
+
+ it('should return raw CSS content instead of applying styles', async () => {
+ const res = await fetchViaHTTP(next.url, '/')
+ const html = await res.text()
+
+ // The page should NOT have a red background (which would indicate CSS was applied)
+ expect(html).not.toContain('background-color: red')
+
+ // The page should contain the raw CSS content
+ expect(html).toContain('/* This CSS file is imported with raw-loader */')
+ expect(html).toContain('body {')
+ expect(html).toContain('background-color: red !important;')
+ expect(html).toContain('.test {')
+ expect(html).toContain('color: red;')
+
+ // The page should show the test instructions
+ expect(html).toContain('Raw Loader Test')
+ expect(html).toContain('If the CSS content above shows raw CSS')
+ })
+})