Skip to content

Commit dd32eca

Browse files
Jeremy-HibikidimaMachina
andauthoredFeb 4, 2025··
fix: normalize path with nextjs normalizeAppPath utility function (#4149)
* fix: normalize path with nextjs `normalizeAppPath` utility function * fix: import next.js utils with `.js` suffix * add changeset * Update packages/eslint-config/src/index.ts --------- Co-authored-by: Dimitri POSTOLOV <dmytropostolov@gmail.com>
1 parent 2c752aa commit dd32eca

File tree

6 files changed

+61
-23
lines changed

6 files changed

+61
-23
lines changed
 

‎.changeset/friendly-windows-count.md

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"nextra": patch
3+
---
4+
5+
fix route group within `app/` dir crash the `convertToPageMap`

‎docs/app/_components/i18n-demo.tsx

-1
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,6 @@ export const I18n: FC = () => {
3434
<div
3535
key={lang}
3636
onPointerOver={() => setActive(lang)}
37-
// eslint-disable-next-line tailwindcss/no-custom-classname -- TODO: configure eslint-plugin-tailwindcss to import nextra-theme-docs styles so below classes could be removed
3837
className={cn(
3938
'relative cursor-default px-4 py-1.5 whitespace-nowrap select-none',
4039
active === lang
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
/**
2+
* @see https://github.com/shuding/nextra/issues/4148
3+
*/
4+
5+
export const metadata = {}
6+
7+
export default function Page() {
8+
return (
9+
<h1
10+
style={{
11+
textAlign: 'center',
12+
fontSize: 64,
13+
margin: '25vh 0',
14+
fontWeight: 'bold'
15+
}}
16+
>
17+
Showcase
18+
</h1>
19+
)
20+
}

‎packages/eslint-config/src/index.ts

+21-21
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { includeIgnoreFile } from '@eslint/compat'
33
import js from '@eslint/js'
44
// @ts-expect-error -- no types
55
import eslintPluginNext from '@next/eslint-plugin-next'
6-
import type { Linter } from 'eslint'
6+
// import type { Linter } from 'eslint'
77
// @ts-expect-error -- no types
88
import eslintConfigPrettier from 'eslint-config-prettier'
99
import eslintPluginImport from 'eslint-plugin-import-x'
@@ -13,24 +13,24 @@ import * as eslintPluginReactCompiler from 'eslint-plugin-react-compiler'
1313
// @ts-expect-error -- no types
1414
import eslintPluginReactHooks from 'eslint-plugin-react-hooks'
1515
import eslintPluginSonarJs from 'eslint-plugin-sonarjs'
16-
// @ts-expect-error -- no types
17-
import eslintPluginTailwindCss from 'eslint-plugin-tailwindcss'
16+
// import eslintPluginTailwindCss from 'eslint-plugin-tailwindcss'
1817
// @ts-expect-error -- no types
1918
import eslintPluginTsSortKeys from 'eslint-plugin-typescript-sort-keys'
2019
import eslintPluginUnicorn from 'eslint-plugin-unicorn'
2120
import tseslint from 'typescript-eslint'
2221
import type { Config } from 'typescript-eslint'
2322

24-
const TAILWIND_CONFIG = {
25-
extends: [eslintPluginTailwindCss.configs['flat/recommended']],
26-
rules: {
27-
'tailwindcss/classnames-order': 'off', // conflicts with prettier-plugin-tailwindcss
28-
'tailwindcss/enforces-negative-arbitrary-values': 'error',
29-
'tailwindcss/enforces-shorthand': 'error',
30-
'tailwindcss/migration-from-tailwind-2': 'error',
31-
'tailwindcss/no-custom-classname': 'error'
32-
} satisfies Linter.RulesRecord
33-
}
23+
// TODO: Enable once `eslint-plugin-tailwindcss` will support Tailwind CSS v4
24+
// const TAILWIND_CONFIG = {
25+
// extends: [eslintPluginTailwindCss.configs['flat/recommended']],
26+
// rules: {
27+
// 'tailwindcss/classnames-order': 'off', // conflicts with prettier-plugin-tailwindcss
28+
// 'tailwindcss/enforces-negative-arbitrary-values': 'error',
29+
// 'tailwindcss/enforces-shorthand': 'error',
30+
// 'tailwindcss/migration-from-tailwind-2': 'error',
31+
// 'tailwindcss/no-custom-classname': 'error'
32+
// } satisfies Linter.RulesRecord
33+
// }
3434

3535
const REACT_COMPILER_RESTRICT = {
3636
name: 'react',
@@ -201,7 +201,7 @@ const config: Config = tseslint.config(
201201
},
202202
// ⚙️ nextra-theme-docs
203203
{
204-
...TAILWIND_CONFIG,
204+
// ...TAILWIND_CONFIG,
205205
files: ['packages/nextra-theme-docs/**'],
206206
settings: {
207207
tailwindcss: {
@@ -217,7 +217,7 @@ const config: Config = tseslint.config(
217217
}
218218
},
219219
rules: {
220-
...TAILWIND_CONFIG.rules,
220+
// ...TAILWIND_CONFIG.rules,
221221
'no-restricted-imports': [
222222
'error',
223223
{ name: 'next/link', message: 'Use `<Anchor>` instead' },
@@ -229,10 +229,10 @@ const config: Config = tseslint.config(
229229
},
230230
// ⚙️ nextra-theme-blog
231231
{
232-
...TAILWIND_CONFIG,
232+
// ...TAILWIND_CONFIG,
233233
files: ['packages/nextra-theme-blog/**'],
234234
rules: {
235-
...TAILWIND_CONFIG.rules,
235+
// ...TAILWIND_CONFIG.rules,
236236
'no-restricted-imports': [
237237
'error',
238238
{
@@ -252,7 +252,7 @@ const config: Config = tseslint.config(
252252
},
253253
// ⚙️ nextra
254254
{
255-
...TAILWIND_CONFIG,
255+
// ...TAILWIND_CONFIG,
256256
files: ['packages/nextra/**'],
257257
settings: {
258258
tailwindcss: {
@@ -267,15 +267,15 @@ const config: Config = tseslint.config(
267267
}
268268
},
269269
rules: {
270-
...TAILWIND_CONFIG.rules,
270+
// ...TAILWIND_CONFIG.rules,
271271
'import/extensions': ['error', 'ignorePackages'],
272272
// False positive due Tailwind CSS v4
273273
'tailwindcss/no-custom-classname': 'off'
274274
}
275275
},
276276
// ⚙️ Docs
277277
{
278-
...TAILWIND_CONFIG,
278+
// ...TAILWIND_CONFIG,
279279
files: ['docs/**'],
280280
settings: {
281281
tailwindcss: {
@@ -307,7 +307,7 @@ const config: Config = tseslint.config(
307307
},
308308
// ⚙️ SWR-site example
309309
{
310-
...TAILWIND_CONFIG,
310+
// ...TAILWIND_CONFIG,
311311
files: ['examples/swr-site/**'],
312312
settings: {
313313
tailwindcss: {

‎packages/nextra/src/server/__tests__/to-page-map.test.ts

+11
Original file line numberDiff line numberDiff line change
@@ -873,6 +873,7 @@ describe('generatePageMap()', () => {
873873
"src/app/_meta.js",
874874
"src/app/blog/page.jsx",
875875
"src/app/page.jsx",
876+
"src/app/showcase/(overview)/page.jsx",
876877
"src/content/_meta.js",
877878
"src/content/advanced/code-highlighting.mdx",
878879
"src/content/features/_meta.js",
@@ -1011,6 +1012,11 @@ describe('generatePageMap()', () => {
10111012
"name": "index",
10121013
"route": "/",
10131014
},
1015+
{
1016+
"__pagePath": "src/app/showcase/(overview)/page.jsx",
1017+
"name": "showcase",
1018+
"route": "/showcase",
1019+
},
10141020
{
10151021
"children": [
10161022
{
@@ -1220,6 +1226,11 @@ describe('generatePageMap()', () => {
12201226
"name": "index",
12211227
"route": "/",
12221228
},
1229+
{
1230+
"__pagePath": "src/app/showcase/(overview)/page.jsx",
1231+
"name": "showcase",
1232+
"route": "/showcase",
1233+
},
12231234
]
12241235
`)
12251236
})

‎packages/nextra/src/server/page-map/to-page-map.ts

+4-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import path from 'node:path'
2+
import { normalizeAppPath } from 'next/dist/shared/lib/router/utils/app-paths.js'
23
import type { TItem } from '../../types.js'
34

45
interface NestedMap {
@@ -54,7 +55,9 @@ export function convertToPageMap({
5455
//
5556
// will be normalized to:
5657
// app/posts/aaron-swartz-a-programmable-web/page.mdx
57-
dir.replaceAll(/\(.*?\)(\/|$)/g, '')
58+
//
59+
// The `normalizeAppPath` function ensures a leading slash is present, so we slice it off.
60+
normalizeAppPath(dir).slice(1)
5861
: [dir, name !== 'index' && name].filter(Boolean).join('/')
5962
pages[key] = filePath
6063
}

0 commit comments

Comments
 (0)
Please sign in to comment.