Skip to content

Commit

Permalink
[v4] compile sidebar components with react compiler (#3755)
Browse files Browse the repository at this point in the history
* more

* more

* more

* more

* more

* more

* more

* more

* more

* more

* more

* more

* more

* more

* more

* more

* fix

* fix

* more

* Update packages/nextra-theme-blog/src/components/navbar-link.tsx
  • Loading branch information
dimaMachina authored Dec 3, 2024
1 parent ea7bece commit 2cd964f
Show file tree
Hide file tree
Showing 42 changed files with 235 additions and 309 deletions.
9 changes: 8 additions & 1 deletion .changeset/config.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,12 @@
"___experimentalUnsafeOptions_WILL_CHANGE_IN_PATCH": {
"onlyUpdatePeerDependentsWhenOutOfRange": true
},
"ignore": ["example-blog", "example-docs", "swr-site", "docs"]
"ignore": [
"example-blog",
"example-docs",
"swr-site",
"docs",
"@nextra/prettier-config",
"@nextra/eslint-config"
]
}
5 changes: 5 additions & 0 deletions .changeset/smart-apricots-ring.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"nextra-theme-docs": minor
---

compile sidebar components with react compiler
4 changes: 3 additions & 1 deletion docs/app/docs/built-ins/head/page.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -74,9 +74,11 @@ export const metadata = {
### in [dynamic routes with Catch-all segment](https://nextjs.org/docs/app/building-your-application/routing/dynamic-routes#catch-all-segments)

```jsx filename="app/[[...mdxPath]]/page.jsx"
import { importPage } from 'nextra/pages'

export async function generateMetadata(props) {
const { mdxPath } = await props.params
const { metadata } = await loadPage(mdxPath)
const { metadata } = await importPage(mdxPath)
return {
title: metadata.title || 'Nextra',
description: metadata.description || 'The next site builder'
Expand Down
3 changes: 1 addition & 2 deletions docs/app/docs/guide/syntax-highlighting/_dynamic-code.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,7 @@ export const DynamicCode: FC<{ children: ReactNode }> = ({ children }) => {
// Find the corresponding token from the DOM
useEffect(() => {
tokenRef.current = [
// @ts-expect-error -- fixme
...ref.current.querySelectorAll('code > span > span')
...ref.current.querySelectorAll<HTMLSpanElement>('code > span > span')
].find(el => el.textContent === '1')
}, [])
return (
Expand Down
7 changes: 3 additions & 4 deletions docs/app/og/route.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,8 @@ import { NextraLogo } from '@components/icons'
import { ImageResponse } from 'next/og'

export const runtime = 'edge'

const font = fetch(new URL('Inter-SemiBold.otf', import.meta.url)).then(res =>
res.arrayBuffer()
const font = await fetch(new URL('Inter-SemiBold.otf', import.meta.url)).then(
res => res.arrayBuffer()
)

export async function GET(req: Request): Promise<Response> {
Expand Down Expand Up @@ -51,7 +50,7 @@ export async function GET(req: Request): Promise<Response> {
fonts: [
{
name: 'inter',
data: await font,
data: font,
style: 'normal'
}
]
Expand Down
2 changes: 1 addition & 1 deletion docs/tsconfig.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"compilerOptions": {
"baseUrl": ".",
"target": "es5",
"target": "es2022",
"lib": ["dom", "dom.iterable", "esnext"],
"allowJs": true,
"skipLibCheck": true,
Expand Down
10 changes: 5 additions & 5 deletions examples/blog/app/posts/page.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,12 @@ export const metadata = {
export default async function PostsPage() {
const tags = await getTags()
const posts = await getPosts()
const allTags = tags.reduce((acc, curr) => {
acc[curr] ??= 0
acc[curr] += 1
return acc
}, Object.create(null))
const allTags = Object.create(null)

for (const tag of tags) {
allTags[tag] ??= 0
allTags[tag] += 1
}
return (
<div data-pagefind-ignore="all">
<h1>{metadata.title}</h1>
Expand Down
4 changes: 2 additions & 2 deletions examples/swr-site/app/[lang]/[[...mdxPath]]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,12 @@ export async function generateMetadata(props: PageProps) {
return metadata
}

type PageProps = {
type PageProps = Readonly<{
params: Promise<{
mdxPath: string[]
lang: string
}>
}
}>
const Wrapper = useMDXComponents().wrapper

export default async function Page(props: PageProps) {
Expand Down
1 change: 0 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,6 @@
"[email protected]": "patches/esbuild-plugin-svgr.patch",
"@changesets/[email protected]": "patches/@changesets__assemble-release-plan.patch",
"[email protected]": "patches/[email protected]",
"[email protected]": "patches/eslint-plugin-deprecation.patch",
"[email protected]": "patches/[email protected]",
"[email protected]": "patches/eslint-plugin-tailwindcss.patch"
}
Expand Down
1 change: 0 additions & 1 deletion packages/eslint-config/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@
"@eslint/js": "9.15.0",
"@next/eslint-plugin-next": "15.0.3",
"eslint-config-prettier": "9.1.0",
"eslint-plugin-deprecation": "3.0.0",
"eslint-plugin-import-x": "4.4.3",
"eslint-plugin-react": "7.37.2",
"eslint-plugin-react-compiler": "19.0.0-beta-df7b47d-20241124",
Expand Down
76 changes: 41 additions & 35 deletions packages/eslint-config/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@ import { includeIgnoreFile } from '@eslint/compat'
import js from '@eslint/js'
// @ts-expect-error -- no types
import eslintPluginNext from '@next/eslint-plugin-next'
import type { Linter } from 'eslint'
// @ts-expect-error -- no types
import eslintConfigPrettier from 'eslint-config-prettier'
import eslintPluginDeprecation from 'eslint-plugin-deprecation'
import eslintPluginImport from 'eslint-plugin-import-x'
import eslintPluginReact from 'eslint-plugin-react'
// @ts-expect-error -- no types
Expand All @@ -29,12 +29,12 @@ const TAILWIND_CONFIG = {
'tailwindcss/enforces-shorthand': 'error',
'tailwindcss/migration-from-tailwind-2': 'error',
'tailwindcss/no-custom-classname': 'error'
}
} satisfies Linter.RulesRecord
}

const REACT_COMPILER_RESTRICT = {
name: 'react',
importNames: ['memo', 'useCallback', 'useMemo', 'forwardRef']
importNames: ['memo', 'useCallback', 'useMemo']
}

const config: Config = tseslint.config(
Expand All @@ -47,11 +47,11 @@ const config: Config = tseslint.config(
js.configs.recommended,
tseslint.configs.recommended,
eslintPluginUnicorn.configs['flat/recommended'],
eslintPluginSonarJs.configs.recommended,
eslintConfigPrettier
],
plugins: {
import: eslintPluginImport,
sonarjs: eslintPluginSonarJs
import: eslintPluginImport
},
rules: {
'no-extra-boolean-cast': ['error', { enforceForInnerExpressions: true }],
Expand Down Expand Up @@ -81,60 +81,67 @@ const config: Config = tseslint.config(
],
'prefer-object-spread': 'error',
'prefer-arrow-callback': ['error', { allowNamedFunctions: true }],
'sonarjs/no-small-switch': 'error',
'prefer-const': ['error', { destructuring: 'all' }],
'sonarjs/no-unused-collection': 'error',
eqeqeq: ['error', 'always', { null: 'ignore' }],
'unicorn/switch-case-braces': ['error', 'avoid'],
// todo: enable
'@typescript-eslint/no-explicit-any': 'off',
'@typescript-eslint/no-non-null-assertion': 'off',
'@typescript-eslint/no-var-requires': 'off',
'@typescript-eslint/ban-ts-comment': 'off',

'unicorn/no-hex-escape': 'off', // todo
'unicorn/escape-case': 'off', // todo
'unicorn/consistent-function-scoping': 'off', // todo
'unicorn/prefer-module': 'off',
'unicorn/no-array-reduce': 'off',
'unicorn/prefer-top-level-await': 'off', // Check if possible to refactor without breaking
'sonarjs/unused-named-groups': 'off', // todo
'sonarjs/cognitive-complexity': 'off', // todo
'sonarjs/prefer-nullish-coalescing': 'off', // todo
'sonarjs/no-nested-conditional': 'off', // todo
'sonarjs/slow-regex': 'off', // todo
'sonarjs/different-types-comparison': 'off', // todo
'sonarjs/default-param-last': 'off', // todo
'sonarjs/no-misleading-array-reverse': 'off', // todo
'sonarjs/sonar-prefer-regexp-exec': 'off', // todo
'sonarjs/no-nested-functions': 'off', // todo
'sonarjs/todo-tag': 'off', // todo
'sonarjs/no-unknown-property': 'off', // todo
'sonarjs/hook-use-state': 'off', // todo
'sonarjs/no-nested-template-literals': 'off', // todo
'sonarjs/label-has-associated-control': 'off', // todo
'sonarjs/no-nested-assignment': 'off', // todo
'sonarjs/function-return-type': 'off', // todo
'sonarjs/table-header': 'off', // todo
'sonarjs/anchor-is-valid': 'off', // todo
'sonarjs/sonar-no-unused-vars': 'off', // todo
'sonarjs/no-var': 'off', // todo
'sonarjs/argument-type': 'off', // todo
'sonarjs/no-array-index-key': 'off', // todo
'sonarjs/no-unstable-nested-components': 'off', // todo

'sonarjs/fixme-tag': 'off',
'@typescript-eslint/no-explicit-any': 'off', // Too many cases
'unicorn/prevent-abbreviations': 'off', // Too many cases
'unicorn/explicit-length-check': 'off', // I don't like
'unicorn/no-null': 'off', // I don't like
'unicorn/prefer-global-this': 'off', // Bundlers are smarter with window
'unicorn/prefer-global-this': 'off', // Bundlers are smarter with `typeof window === 'undefined'` checks
'unicorn/prefer-optional-catch-binding': 'off' // catch by @typescript-eslint/no-unused-vars
}
},
// Rules for React files
{
files: ['{packages,examples,docs}/**'],
extends: [
// @ts-expect-error
eslintPluginReact.configs.flat.recommended,
// @ts-expect-error
eslintPluginReact.configs.flat['jsx-runtime']
],
plugins: {
'react-hooks': eslintPluginReactHooks,
'@next/next': eslintPluginNext
},
extends: [
// @ts-expect-error -- always exist
eslintPluginReact.configs.flat.recommended,
// @ts-expect-error -- always exist
eslintPluginReact.configs.flat['jsx-runtime']
],
rules: {
...eslintPluginReactHooks.configs.recommended.rules,
...eslintPluginNext.configs.recommended.rules,
...eslintPluginNext.configs['core-web-vitals'].rules,
'react/prop-types': 'off',
'react/no-unknown-property': ['error', { ignore: ['jsx'] }],
'react-hooks/exhaustive-deps': 'error',
'react/self-closing-comp': 'error',
'no-restricted-syntax': [
'error',
{
// ❌ useMemo(…, [])
selector:
'CallExpression[callee.name=useMemo][arguments.1.type=ArrayExpression][arguments.1.elements.length=0]',
message:
"`useMemo` with an empty dependency array can't provide a stable reference, use `useRef` instead."
},
{
// ❌ z.object(…)
selector: 'MemberExpression[object.name=z] > .property[name=object]',
Expand All @@ -156,18 +163,17 @@ const config: Config = tseslint.config(
{
files: ['**/*.{ts,tsx,cts,mts}'],
plugins: {
deprecation: eslintPluginDeprecation,
'typescript-sort-keys': eslintPluginTsSortKeys
},
// TODO: fix errors
// 'plugin:@typescript-eslint/recommended-requiring-type-checking'
// extends: [tseslint.configs.recommendedTypeChecked],
languageOptions: {
parserOptions: {
projectService: true
}
},
rules: {
...eslintPluginDeprecation.configs.recommended.rules,
'@typescript-eslint/no-deprecated': 'error',
'@typescript-eslint/await-thenable': 'error',
'@typescript-eslint/no-unnecessary-type-assertion': 'error',
'@typescript-eslint/consistent-type-imports': 'error',
Expand Down
16 changes: 16 additions & 0 deletions packages/nextra-theme-blog/src/components/navbar-link.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
'use client'

import { Link } from 'next-view-transitions'
import { useFSRoute } from 'nextra/hooks'
import type { ComponentProps, FC } from 'react'

export const NavbarLink: FC<ComponentProps<typeof Link>> = props => {
const pathname = useFSRoute()
return (
<Link
className="x:aria-[current]:no-underline x:aria-[current]:opacity-60"
aria-current={props.href === pathname || undefined}
{...props}
/>
)
}
31 changes: 7 additions & 24 deletions packages/nextra-theme-blog/src/components/navbar.tsx
Original file line number Diff line number Diff line change
@@ -1,42 +1,25 @@
'use client'

import { Link } from 'next-view-transitions'
import type { PageMapItem } from 'nextra'
import { useFSRoute } from 'nextra/hooks'
import { normalizePages } from 'nextra/normalize-pages'
import type { FC, ReactNode } from 'react'
import { NavbarLink } from './navbar-link'

type NavbarProps = {
children?: ReactNode
pageMap: PageMapItem[]
}

export const Navbar: FC<NavbarProps> = ({ children, pageMap }) => {
const pathname = useFSRoute()
const { topLevelNavbarItems } = normalizePages({
list: pageMap,
route: pathname
})
const { topLevelNavbarItems } = normalizePages({ list: pageMap, route: '/' })
return (
<header
className="x:mb-8 x:flex x:items-center x:gap-3 x:justify-end"
data-pagefind-ignore="all"
>
{topLevelNavbarItems.map(nav => {
const url = nav.route
return url === pathname ? (
<span
key={url}
className="x:cursor-default x:dark:text-gray-400 x:text-gray-600"
>
{nav.title}
</span>
) : (
<Link key={url} href={url}>
{nav.title}
</Link>
)
})}
{topLevelNavbarItems.map(nav => (
<NavbarLink key={nav.route} href={nav.route}>
{nav.title}
</NavbarLink>
))}
{children}
</header>
)
Expand Down
Loading

0 comments on commit 2cd964f

Please sign in to comment.