feat: support multi sources#311
Conversation
📝 WalkthroughWalkthrough将 ChangesEventSourceButton 多来源重构
依赖与 Yarn 配置升级
Sequence Diagram(s)sequenceDiagram
participant 用户
participant EventSourceButton
participant getUrl
participant navigator.clipboard
participant sendTrack
participant toast提示
用户->>EventSourceButton: 点击来源入口
alt 多来源
EventSourceButton->>用户: 展开 Menu 下拉列表
用户->>EventSourceButton: 选择某一来源
end
EventSourceButton->>getUrl: 校验 URL 协议(http/https)
alt 有效链接
getUrl-->>EventSourceButton: 返回 URL 对象
EventSourceButton->>sendTrack: 记录链接点击事件
EventSourceButton->>用户: 新标签页打开链接
else 非 http/https 链接
getUrl-->>EventSourceButton: 返回 null
EventSourceButton->>navigator.clipboard: writeText(url)
navigator.clipboard-->>EventSourceButton: 复制成功
EventSourceButton->>sendTrack: 记录复制事件
EventSourceButton->>toast提示: 显示本地化复制成功消息
end
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Warning There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure. 🔧 ESLint
ESLint install failed. For unrecoverable errors, disable the tool in CodeRabbit configuration. Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Code Review
This pull request updates various dependencies, upgrades Yarn, and refactors the EventSourceButton component to support multiple event sources via a dropdown menu using Headless UI. It also adds translation keys for source copying and navigation, and adjusts styling for EventMapCard and the event detail page. Feedback on the changes suggests importing and using ReactNode directly from 'react' to avoid relying on the global React namespace, and adding safety checks and error handling when using the navigator.clipboard API.
Important
The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.
| import { sendTrack } from "@/utils/track"; | ||
| import { Menu, MenuButton, MenuItem, MenuItems } from "@headlessui/react"; | ||
| import { useTranslation } from "next-i18next/pages"; | ||
| import toast from "react-hot-toast"; | ||
| import { IoChevronDown } from "react-icons/io5"; |
There was a problem hiding this comment.
Import ReactNode from 'react' to avoid relying on global React namespace types, which can cause compilation issues depending on the TypeScript configuration.
| import { sendTrack } from "@/utils/track"; | |
| import { Menu, MenuButton, MenuItem, MenuItems } from "@headlessui/react"; | |
| import { useTranslation } from "next-i18next/pages"; | |
| import toast from "react-hot-toast"; | |
| import { IoChevronDown } from "react-icons/io5"; | |
| import { sendTrack } from "@/utils/track"; | |
| import { Menu, MenuButton, MenuItem, MenuItems } from "@headlessui/react"; | |
| import { useTranslation } from "next-i18next/pages"; | |
| import { ReactNode } from "react"; | |
| import toast from "react-hot-toast"; | |
| import { IoChevronDown } from "react-icons/io5"; |
| track(source); | ||
| }; | ||
|
|
||
| const renderSourceAction = (source: EventSource, className: string, children: React.ReactNode) => { |
There was a problem hiding this comment.
Use the imported ReactNode type instead of React.ReactNode since React is not imported in this file.
| const renderSourceAction = (source: EventSource, className: string, children: React.ReactNode) => { | |
| const renderSourceAction = (source: EventSource, className: string, children: ReactNode) => { |
| const copySource = (source: EventSource) => { | ||
| navigator.clipboard | ||
| .writeText(source.url) | ||
| .then(() => toast.success(t("event.sourceCopySuccess", { name: source.name || source.url }))); | ||
| track(source); | ||
| }; |
There was a problem hiding this comment.
The navigator.clipboard API might not be available in all environments (e.g., non-secure HTTP contexts or older browsers) and can reject if permission is denied. To prevent runtime errors, we should check if navigator.clipboard is available and handle potential promise rejections.
| const copySource = (source: EventSource) => { | |
| navigator.clipboard | |
| .writeText(source.url) | |
| .then(() => toast.success(t("event.sourceCopySuccess", { name: source.name || source.url }))); | |
| track(source); | |
| }; | |
| const copySource = (source: EventSource) => { | |
| if (!source?.url) { | |
| toast.error("No URL available to copy"); | |
| return; | |
| } | |
| if (typeof navigator !== "undefined" && navigator.clipboard) { | |
| navigator.clipboard | |
| .writeText(source.url) | |
| .then(() => toast.success(t("event.sourceCopySuccess", { name: source.name || source.url }))) | |
| .catch((err) => { | |
| console.error("Failed to copy text: ", err); | |
| toast.error("Failed to copy to clipboard"); | |
| }); | |
| } else { | |
| console.warn("Clipboard API not available"); | |
| toast.error("Clipboard not supported in this browser"); | |
| } | |
| track(source); | |
| }; |
There was a problem hiding this comment.
Actionable comments posted: 3
🧹 Nitpick comments (3)
src/components/event/EventSourceButton/index.tsx (1)
94-95: 💤 Low value可以改进 key 的生成方式。
当前使用
${source.url}-${index}作为 key,如果同一 URL 出现多次,index 作为区分符是可以接受的,但更推荐使用稳定的唯一标识符(如果可用)。不过在当前场景下,由于列表是静态的且不会重新排序,这个实现是可接受的。♻️ 可选优化建议
如果数据源包含唯一 ID,可以使用:
-<MenuItem key={`${source.url}-${index}`}> +<MenuItem key={source.id || `${source.url}-${index}`}>或者,如果能确保 URL 唯一,直接使用 URL:
-<MenuItem key={`${source.url}-${index}`}> +<MenuItem key={source.url}>🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/components/event/EventSourceButton/index.tsx` around lines 94 - 95, In the MenuItem component rendered within sources.map(), consider improving the key generation from the current `${source.url}-${index}` approach. If the source object contains a stable unique identifier property (such as an id field), use that as the key instead. Alternatively, if URLs are guaranteed to be unique across all sources, use the URL directly as the key. The current implementation combining URL and index is acceptable for static, non-reordering lists, but these alternatives would be more robust if applicable to your data structure.src/pages/[organization]/[slug].tsx (1)
36-36: 💤 Low value
flex类名冗余。由于
flex-col已经包含了display: flex,显式添加flex是多余的。不过这不影响功能,仅是代码简洁性问题。♻️ 可选的简化建议
- <div className={clsx("relative z-20 flex border bg-white rounded-xl min-h-[500px]", "lg:flex-row flex-col")}> + <div className={clsx("relative z-20 border bg-white rounded-xl min-h-[500px]", "lg:flex-row flex-col")}>🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/pages/`[organization]/[slug].tsx at line 36, The `flex` class name is redundant in the clsx call for this div element. Since `flex-col` already includes `display: flex`, remove the explicit `flex` class from the first argument to clsx (in the string "relative z-20 flex border bg-white rounded-xl min-h-[500px]"). Keep all other classes including the second argument with `lg:flex-row flex-col` which will properly set the flex display and direction..yarnrc.yml (1)
1-2: 考虑更明确地配置 Git 仓库白名单。配置
approvedGitRepositories: ["**"]允许从任意 Git 仓库安装依赖。虽然当前项目未使用任何 Git 依赖,但若未来需要添加 Git 源依赖,建议提前更新此配置以显式列出受信任的仓库模式(如github.com/*),而非使用通配符。这有助于防止意外引入来自不受信任来源的代码。🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In @.yarnrc.yml around lines 1 - 2, The approvedGitRepositories configuration in .yarnrc.yml is currently set to a wildcard pattern ["**"] which permits installing dependencies from any Git repository, creating a security risk. Replace the wildcard pattern with explicit, trusted repository patterns that align with your organization's security policy, such as ["github.com/*"] or specific repository URLs, to restrict Git dependency sources to only approved repositories. This ensures that future Git-based dependencies cannot be accidentally pulled from untrusted sources.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In @.yarnrc.yml:
- Line 8: The `enableScripts: true` configuration in the Yarn configuration file
is unnecessary because the project does not declare any installation scripts
(install, postinstall, or preinstall hooks) in its dependencies. Following the
principle of least privilege, either remove the `enableScripts: true` line
entirely from the configuration or change it to `enableScripts: false` to
disable script execution by default. This reduces the security surface and makes
the configuration explicit about the project's actual needs.
In `@package.json`:
- Line 17: The project is using Next.js 16.2.9 which requires completing the
migration from Pages Router to App Router structure. Run the official Next.js
codemod with the command `npx `@next/codemod`@latest upgrade` to automate the
migration process. Additionally, ensure all async request APIs such as
cookies(), headers(), draftMode(), params, and searchParams are properly awaited
throughout the codebase, replace all getServerSideProps and getStaticProps
implementations with async Server Components using the 'use cache' directive,
and update any generateImageMetadata or sitemap functions to properly handle
Promise-based params and id parameters. These changes must be completed across
all affected routes and components to ensure compatibility with Next.js 16.x
requirements.
In `@src/components/event/EventSourceButton/index.tsx`:
- Around line 42-47: The copySource function in EventSourceButton/index.tsx is
missing error handling for the navigator.clipboard.writeText promise chain. Add
a .catch() handler to the clipboard operation to gracefully handle failures when
the clipboard API is unavailable or permission is denied. In the catch handler,
show a failure toast message using t("event.sourceCopyFailed") to inform the
user that the copy operation failed. Additionally, add the corresponding i18n
translation key event.sourceCopyFailed to your i18n translation files to support
the error message.
---
Nitpick comments:
In @.yarnrc.yml:
- Around line 1-2: The approvedGitRepositories configuration in .yarnrc.yml is
currently set to a wildcard pattern ["**"] which permits installing dependencies
from any Git repository, creating a security risk. Replace the wildcard pattern
with explicit, trusted repository patterns that align with your organization's
security policy, such as ["github.com/*"] or specific repository URLs, to
restrict Git dependency sources to only approved repositories. This ensures that
future Git-based dependencies cannot be accidentally pulled from untrusted
sources.
In `@src/components/event/EventSourceButton/index.tsx`:
- Around line 94-95: In the MenuItem component rendered within sources.map(),
consider improving the key generation from the current `${source.url}-${index}`
approach. If the source object contains a stable unique identifier property
(such as an id field), use that as the key instead. Alternatively, if URLs are
guaranteed to be unique across all sources, use the URL directly as the key. The
current implementation combining URL and index is acceptable for static,
non-reordering lists, but these alternatives would be more robust if applicable
to your data structure.
In `@src/pages/`[organization]/[slug].tsx:
- Line 36: The `flex` class name is redundant in the clsx call for this div
element. Since `flex-col` already includes `display: flex`, remove the explicit
`flex` class from the first argument to clsx (in the string "relative z-20 flex
border bg-white rounded-xl min-h-[500px]"). Keep all other classes including the
second argument with `lg:flex-row flex-col` which will properly set the flex
display and direction.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: c3bcf99a-5e2b-41f4-8aa0-2fe413d38d39
⛔ Files ignored due to path filters (1)
yarn.lockis excluded by!**/yarn.lock,!**/*.lock
📒 Files selected for processing (9)
.yarnrc.ymlpackage.jsonpublic/locales/en/common.jsonpublic/locales/ru/common.jsonpublic/locales/zh-Hans/common.jsonpublic/locales/zh-Hant/common.jsonsrc/components/event/EventMapCard.tsxsrc/components/event/EventSourceButton/index.tsxsrc/pages/[organization]/[slug].tsx
|
|
||
| enableGlobalCache: false | ||
|
|
||
| enableScripts: true |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# 检查 node_modules 中声明了 install/postinstall 脚本的包
echo "=== 检查声明了安装脚本的依赖 ==="
fd -t f package.json node_modules --max-depth 2 --exec jq -r 'select(.scripts.install or .scripts.postinstall or .scripts.preinstall) | .name + " (" + (.scripts.install // .scripts.postinstall // .scripts.preinstall) + ")"' 2>/dev/null | head -20 || echo "需要先安装依赖才能检查"Repository: FurryConsChina/website
Length of output: 87
🏁 Script executed:
# Check if .yarnrc.yml exists and its content
cat -n .yarnrc.yml 2>/dev/null || echo "File not found"Repository: FurryConsChina/website
Length of output: 351
🏁 Script executed:
# Check if node_modules exists
ls -la | grep node_modules || echo "node_modules directory not found"Repository: FurryConsChina/website
Length of output: 99
🏁 Script executed:
# Check yarn.lock for packages with install/postinstall/preinstall scripts
if [ -f yarn.lock ]; then
echo "=== Checking yarn.lock for packages with scripts ==="
grep -E '^\s*(install|postinstall|preinstall):' yarn.lock | head -20 || echo "No script declarations found in yarn.lock"
fiRepository: FurryConsChina/website
Length of output: 119
🏁 Script executed:
# Check package.json to see what dependencies are declared
if [ -f package.json ]; then
echo "=== Project dependencies ==="
jq '.dependencies, .devDependencies' package.json 2>/dev/null | head -30
fiRepository: FurryConsChina/website
Length of output: 919
🏁 Script executed:
# Check the format of yarn.lock to understand script declarations
if [ -f yarn.lock ]; then
echo "=== First 50 lines of yarn.lock to understand format ==="
head -50 yarn.lock
echo ""
echo "=== Sample entry checking for scripts ==="
grep -A 10 '"next@' yarn.lock | head -20
fiRepository: FurryConsChina/website
Length of output: 2482
🏁 Script executed:
# More comprehensive check - look for any script keys in yarn.lock
if [ -f yarn.lock ]; then
echo "=== Checking for all script declarations in yarn.lock ==="
rg '"(install|postinstall|preinstall)"' yarn.lock -A 1 -B 1 | head -30 || echo "No script declarations found with this pattern"
fiRepository: FurryConsChina/website
Length of output: 124
🏁 Script executed:
# Do a comprehensive check of yarn.lock for any lifecycle scripts at all
if [ -f yarn.lock ]; then
echo "=== Total lines in yarn.lock ==="
wc -l yarn.lock
echo ""
echo "=== Checking for lifecycle script patterns (install, postinstall, preinstall, prepublishOnly, etc) ==="
rg '^\s+(install|postinstall|preinstall|prepublishOnly|prepare|build):' yarn.lock | wc -l
echo ""
echo "=== Show any matches if they exist ==="
rg '^\s+(install|postinstall|preinstall|prepublishOnly|prepare|build):' yarn.lock | head -20
fiRepository: FurryConsChina/website
Length of output: 260
🏁 Script executed:
# Check if there's a git-revision-webpack-plugin which might have scripts
if [ -f yarn.lock ]; then
echo "=== Check git-revision-webpack-plugin entry in yarn.lock ==="
rg '"git-revision-webpack-plugin' yarn.lock -A 15 | head -30
fiRepository: FurryConsChina/website
Length of output: 793
移除不必要的 enableScripts: true 配置。
当前项目依赖中没有声明任何安装脚本(install/postinstall/preinstall),因此 enableScripts: true 是不必要的。为遵循最小权限原则,建议将其改为 enableScripts: false 或移除此配置项。若未来确实需要运行安装脚本,应建立严格的依赖审查流程。
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In @.yarnrc.yml at line 8, The `enableScripts: true` configuration in the Yarn
configuration file is unnecessary because the project does not declare any
installation scripts (install, postinstall, or preinstall hooks) in its
dependencies. Following the principle of least privilege, either remove the
`enableScripts: true` line entirely from the configuration or change it to
`enableScripts: false` to disable script execution by default. This reduces the
security surface and makes the configuration explicit about the project's actual
needs.
| "@headlessui/react": "^2.2.10", | ||
| "@next/third-parties": "^16.2.6", | ||
| "@sentry/nextjs": "^10.53.1", | ||
| "@next/third-parties": "^16.2.9", |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# 检查 Next.js 16.2.9 是否存在及其发布信息
echo "=== 检查 Next.js 16.2.9 版本信息 ==="
npm view next@16.2.9 version time 2>/dev/null || echo "版本不存在或无法访问"
echo -e "\n=== 检查 Next.js 最新版本 ==="
npm view next dist-tags.latest dist-tags.canary
echo -e "\n=== 检查代码中是否存在 Next.js 15→16 迁移标记 ==="
rg -n '`@next/codemod`|npx.*codemod.*next' --type md --type json --type ts --type tsx 2>/dev/null || echo "未发现迁移脚本记录"Repository: FurryConsChina/website
Length of output: 152
🌐 Web query:
Next.js 16.2.9 release notes breaking changes migration guide
💡 Result:
Next.js version 16.2.9 was released on June 9, 2026 [1][2]. There are no specific release notes, breaking changes, or migration guides associated with version 16.2.9 [3]. This release was an empty, maintenance-only release created to correct the npm dist-tag for next@latest, which had incorrectly pointed to a pre-release version [3][4]. It does not introduce new features, bug fixes, or breaking changes [3][4]. If you are looking for information regarding major changes in the Next.js 16.x line, you should refer to the documentation for upgrading to version 16, which covers significant breaking changes such as the removal of synchronous access to Async Request APIs and updates to image and sitemap generation parameters [5]. For recent minor or patch-level features and bug fixes within the 16.2.x series, refer to the release notes for version 16.2 [6] and the detailed changelogs for preceding patches like 16.2.7 [7].
Citations:
- 1: https://www.npmjs.com/package/next?activeTab=versions
- 2: https://eosl.date/eol/product/nextjs/
- 3: Docs: Release notes missing for 16.2.8 & 16.2.9 vercel/next.js#94638
- 4: https://releases.sh/vercel/nextjs
- 5: https://github.com/vercel/next.js/blob/v16.2.1/docs/01-app/02-guides/upgrading/version-16.mdx
- 6: https://nextjs.org/blog/next-16-2
- 7: https://github.com/vercel/next.js/releases/tag/v16.2.7
🏁 Script executed:
#!/bin/bash
# 检查代码库中是否存在 Next.js 15 的过时模式
echo "=== 检查是否存在 getServerSideProps/getStaticProps (Next.js 15 模式) ==="
rg -n 'getServerSideProps|getStaticProps' --type ts --type tsx --type js --type jsx 2>/dev/null | head -20 || echo "未发现"
echo -e "\n=== 检查 App Router 使用情况 ==="
rg -n 'app/' --type-list | head -5
echo -e "\n=== 查找 package.json 所在目录结构 ==="
fd -H 'next.config\.(js|ts|mjs)' | head -5
echo -e "\n=== 检查 .next 或 build 输出 ==="
fd -H 'tsconfig.json' -x head -20 {} \;Repository: FurryConsChina/website
Length of output: 1112
🌐 Web query:
Next.js 16 breaking changes async request API image generation sitemap 迁移指南
💡 Result:
Next.js 16 introduces significant breaking changes centered on enforcing asynchronous access for Request-time APIs and metadata generation functions [1][2]. Async Request APIs In Next.js 16, synchronous access to Request-time APIs is fully removed [3][1]. You must now use await to access these values [4]. Affected APIs include: - cookies, headers, and draftMode [1][2]. - params in layout.js, page.js, route.js, default.js, and metadata image routes (opengraph-image, twitter-image, icon, apple-icon) [3][1]. - searchParams in page.js [1]. Migration Example: // Next.js 16 - asynchronous access export default async function Page({ params, searchParams }) { const resolvedParams = await params; const resolvedSearchParams = await searchParams; const cookieStore = await cookies; //... } Image Generation Image generation functions (e.g., opengraph-image) now receive both params and id as Promises [3][5]. - The props (params, id) passed to image generation functions must be awaited [3][6]. - generateImageMetadata continues to receive synchronous params [3][5]. Sitemap Generation In Next.js 16, the id parameter passed to the sitemap generation function is now a Promise [3][7]. - You must await the id inside your sitemap function [3][8]: export default async function sitemap({ id }) { const resolvedId = await id; //... } Migration Guidance - Use the official Next.js codemods to automate the migration of synchronous Request-time APIs to their async counterparts [3][4]. - Run npx next typegen to generate updated, type-safe helpers for async params and searchParams [3][1]. - Audit all Server Actions, Route Handlers, and Metadata files for synchronous usage of the affected APIs [4]. Additional Next.js 16 Image Changes - The images.minimumCacheTTL default increased from 1 minute to 4 hours [6]. - The 16px width is removed from default images.imageSizes [9][10]. - Local image sources with query strings now require images.localPatterns configuration for security [2][6]. - The priority prop is deprecated in next/image, replaced by the preload property [11]. Top Results: [3], [1], [2], [4], [8]
Citations:
- 1: https://nextjs.org/docs/app/guides/upgrading/version-16
- 2: https://nextjs.org/blog/next-16
- 3: https://rc.nextjs.org/docs/app/guides/upgrading/version-16
- 4: https://www.mohdsaif.in/blog/fix-nextjs-16-async-apis
- 5: https://github.com/vercel/next.js/blob/v16.2.1/docs/01-app/02-guides/upgrading/version-16.mdx
- 6: https://contextqmd.com/libraries/next-js/versions/16.2.1/pages/docs/01-app/02-guides/upgrading/version-16
- 7: https://nextjs.org/docs/app/api-reference/file-conventions/metadata/sitemap
- 8: https://nextjs.org/docs/app/api-reference/functions/generate-sitemaps
- 9: https://github.com/vercel/next.js/releases/tag/v16.0.0
- 10: breaking(next/image)!: remove 16px from default
images.imageSizesconfig vercel/next.js#84647 - 11: https://nextjs.org/docs/app/api-reference/components/image
🏁 Script executed:
#!/bin/bash
# 检查代码库中的异步 API 使用情况
echo "=== 检查是否存在 async 页面/布局函数 ==="
rg -n 'async.*function.*Page|async.*function.*Layout' --type ts --type tsx | head -10
echo -e "\n=== 检查 params/searchParams 使用情况 ==="
rg -n 'await (params|searchParams|cookies|headers|draftMode)' --type ts --type tsx | head -10
echo -e "\n=== 检查图片生成函数 ==="
rg -n 'generateImageMetadata|opengraph-image|twitter-image' --type ts --type tsx --type js | head -10
echo -e "\n=== 查看 pages 或 app 目录结构 ==="
fd -H '(pages|app)' -t d | head -10
echo -e "\n=== 检查是否使用了 Server Components ==="
rg -n "'use server'|'use client'" --type ts --type tsx | head -10Repository: FurryConsChina/website
Length of output: 355
🏁 Script executed:
#!/bin/bash
# 使用正确的方式检查 Pages Router 代码库
echo "=== 检查 Pages Router 文件结构 ==="
fd -H '\.(js|jsx)$' src/pages/ | head -20
echo -e "\n=== 检查 _app/_document 文件 ==="
fd -H '(_app|_document)\.' src/pages/
echo -e "\n=== 搜索 getServerSideProps 和 getStaticProps ==="
rg -n 'export.*get(ServerSideProps|StaticProps)' --type js 2>/dev/null | head -10
echo -e "\n=== 检查 src 目录结构 ==="
tree -L 2 src/ 2>/dev/null || fd -H '.' src/ -t d | head -20Repository: FurryConsChina/website
Length of output: 1484
🌐 Web query:
Next.js 16 Pages Router breaking changes migration getServerSideProps getStaticProps
💡 Result:
In Next.js 16, the Pages Router has reached a critical stage where it is strongly recommended to migrate to the App Router, as the framework has fully transitioned to a new architecture [1][2]. While you can perform an incremental migration, the core data-fetching APIs used in the Pages Router (getServerSideProps and getStaticProps) have direct, simplified equivalents in the App Router [3][4]. Key Migration Patterns getServerSideProps to Async Server Components In the Pages Router, getServerSideProps was used to fetch data on every request [4]. In the App Router, you simply use an async Server Component [3][2]. Because fetch is uncached by default in Next.js 16, this behavior is equivalent to getServerSideProps [3]. For non-fetch data sources, you can opt out of caching by using cache: 'no-store' or unstable_cache with a revalidation time of 0 [4]. getStaticProps to 'use cache' Components getStaticProps pages were statically generated by default [3]. To achieve this in the App Router, you use an async Server Component combined with the 'use cache' directive [1][3]. This allows for fine-grained control over caching and revalidation, replacing the old page-level static generation model [1][4]. Breaking Changes in Next.js 16 If you are still maintaining Pages Router code within a project upgrading to Next.js 16, be aware of these global breaking changes: 1. Async Request APIs: Synchronous access to cookies(), headers(), draftMode(), params, and searchParams is fully removed [5][1]. Any code still using these synchronously will throw a runtime error; they must now be awaited as promises [5][6]. 2. Middleware renamed to Proxy: The middleware.ts convention has been updated to proxy.ts [1]. 3. Turbopack Default: Turbopack is now the default bundler for both development and production, replacing webpack [1]. 4. Async Parameters: Image metadata generation and sitemap generation functions now receive params and id as promises [5]. Recommendation for Migration Do not attempt to keep getServerSideProps or getStaticProps while upgrading to Next.js 16, as they are not supported in the App Router and your application should be moved entirely to the app/ directory [2]. Follow these steps for an efficient migration: 1. Run the official migration codemods (npx @next/codemod@latest upgrade) to help handle baseline breaking changes [3]. 2. Identify routes using getServerSideProps and convert them to async Server Components first, as this is the simplest path [4][2]. 3. Use the 'use cache' directive to replicate static caching behavior formerly managed by getStaticProps [3]. 4. Replace next/router with next/navigation hooks [3]. top_results: [5][6][1][3][4][2]
Citations:
- 1: https://www.codewithseb.com/blog/nextjs-16-migration-guide-breaking-changes
- 2: https://thecodeforge.io/javascript/next-js-react-migration-guide/
- 3: https://toolchew.com/en/how-to-migrate-nextjs-pages-to-app-router/
- 4: https://www.logic-leap.co.uk/blog/nextjs-app-router-migration-guide
- 5: https://nextjs.org/docs/app/guides/upgrading/version-16
- 6: https://nextjs.org/blog/next-16
Next.js 16.2.9 版本确认无虞,但需完成 Pages Router 至 App Router 的迁移。
Next.js 16.2.9 已于 2026 年 6 月 9 日正式发布,是一个维护版本,自身无破坏性变更。然而,Next.js 16.x 包含多项重大破坏性变更,需要立即处理:
- 异步请求 API:
cookies()、headers()、draftMode()、params和searchParams必须 await,同步访问将抛出运行时错误。 - Pages Router 至 App Router 迁移:Next.js 16 强烈建议将 Pages Router 完全迁移至 App Router。
getServerSideProps和getStaticProps在 App Router 中不支持,应改用异步 Server Component 结合'use cache'指令。 - 图片和站点地图生成:
generateImageMetadata和 sitemap 函数的params/id参数现为 Promise,需要 await。 - 中间件重命名:
middleware.ts→proxy.ts(已完成)。 - 默认打包工具:Turbopack 现为默认打包工具。
代码库当前仍使用 Pages Router 结构,需执行完整迁移。建议运行官方迁移 codemod:npx @next/codemod@latest upgrade。
Also applies to: 27-27, 30-30, 31-31, 47-47
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@package.json` at line 17, The project is using Next.js 16.2.9 which requires
completing the migration from Pages Router to App Router structure. Run the
official Next.js codemod with the command `npx `@next/codemod`@latest upgrade` to
automate the migration process. Additionally, ensure all async request APIs such
as cookies(), headers(), draftMode(), params, and searchParams are properly
awaited throughout the codebase, replace all getServerSideProps and
getStaticProps implementations with async Server Components using the 'use
cache' directive, and update any generateImageMetadata or sitemap functions to
properly handle Promise-based params and id parameters. These changes must be
completed across all affected routes and components to ensure compatibility with
Next.js 16.x requirements.
| const copySource = (source: EventSource) => { | ||
| navigator.clipboard | ||
| .writeText(source.url) | ||
| .then(() => toast.success(t("event.sourceCopySuccess", { name: source.name || source.url }))); | ||
| track(source); | ||
| }; |
There was a problem hiding this comment.
剪贴板操作缺少错误处理。
navigator.clipboard.writeText 返回的 Promise 没有 .catch() 处理,可能导致以下问题:
- 在非 HTTPS 环境下(除 localhost 外),剪贴板 API 可能不可用
- 部分浏览器或权限设置可能阻止剪贴板访问
- 当前实现即使复制失败也会显示成功提示,误导用户
🛡️ 建议添加错误处理
const copySource = (source: EventSource) => {
navigator.clipboard
.writeText(source.url)
- .then(() => toast.success(t("event.sourceCopySuccess", { name: source.name || source.url })));
+ .then(() => toast.success(t("event.sourceCopySuccess", { name: source.name || source.url })))
+ .catch(() => {
+ toast.error(t("event.sourceCopyFailed", { name: source.name || source.url }));
+ });
track(source);
};注:需在 i18n 文件中添加 event.sourceCopyFailed 键。
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| const copySource = (source: EventSource) => { | |
| navigator.clipboard | |
| .writeText(source.url) | |
| .then(() => toast.success(t("event.sourceCopySuccess", { name: source.name || source.url }))); | |
| track(source); | |
| }; | |
| const copySource = (source: EventSource) => { | |
| navigator.clipboard | |
| .writeText(source.url) | |
| .then(() => toast.success(t("event.sourceCopySuccess", { name: source.name || source.url }))) | |
| .catch(() => { | |
| toast.error(t("event.sourceCopyFailed", { name: source.name || source.url })); | |
| }); | |
| track(source); | |
| }; |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src/components/event/EventSourceButton/index.tsx` around lines 42 - 47, The
copySource function in EventSourceButton/index.tsx is missing error handling for
the navigator.clipboard.writeText promise chain. Add a .catch() handler to the
clipboard operation to gracefully handle failures when the clipboard API is
unavailable or permission is denied. In the catch handler, show a failure toast
message using t("event.sourceCopyFailed") to inform the user that the copy
operation failed. Additionally, add the corresponding i18n translation key
event.sourceCopyFailed to your i18n translation files to support the error
message.
📦 Next.js Bundle Analysis for furrycons-siteThis analysis was generated by the Next.js Bundle Analysis action. 🤖 🎉 Global Bundle Size Decreased
DetailsThe global bundle is the javascript bundle that loads alongside every page. It is in its own category because its impact is much higher - an increase to its size means that every page on your website loads slower, and a decrease means every page loads faster. Any third party scripts you have added directly to your app using the If you want further insight into what is behind the changes, give @next/bundle-analyzer a try! Ten Pages Changed SizeThe following pages changed size from the code in this PR compared to its base branch:
DetailsOnly the gzipped size is provided here based on an expert tip. First Load is the size of the global bundle plus the bundle for the individual page. If a user were to show up to your website and land on a given page, the first load size represents the amount of javascript that user would need to download. If Any third party scripts you have added directly to your app using the The "Budget %" column shows what percentage of your performance budget the First Load total takes up. For example, if your budget was 100kb, and a given page's first load size was 10kb, it would be 10% of your budget. You can also see how much this has increased or decreased compared to the base branch of your PR. If this percentage has increased by 20% or more, there will be a red status indicator applied, indicating that special attention should be given to this. If you see "+/- <0.01%" it means that there was a change in bundle size, but it is a trivial enough amount that it can be ignored. |
Summary by CodeRabbit
发布说明
新特性
Chores