Next.js 16 (#351)
* Upgrade to next.js 16 * Allow static generation on preview * Add note for disabled ref rule * Report Next.js version in App Insights * Link Next.js version
This commit is contained in:
parent
3f1a36354d
commit
c8ea51cdd1
@ -18,6 +18,7 @@ const eslintConfig = defineConfig([
|
||||
'@stylistic': stylistic,
|
||||
},
|
||||
rules: {
|
||||
// Disable rule during Next.js 16 migration
|
||||
'react-hooks/refs': 'off',
|
||||
'@next/next/no-img-element': 'off',
|
||||
'@typescript-eslint/no-explicit-any': 'off',
|
||||
|
||||
30
package.json
30
package.json
@ -8,12 +8,12 @@
|
||||
"test": "jest --watch --transformIgnorePatterns 'node_modules/(?!my-library-dir)/'",
|
||||
"analyze": "ANALYZE=true next build"
|
||||
},
|
||||
"packageManager": "pnpm@10.19.0",
|
||||
"packageManager": "pnpm@10.20.0",
|
||||
"dependencies": {
|
||||
"@ai-sdk/openai": "^2.0.54",
|
||||
"@ai-sdk/rsc": "^1.0.81",
|
||||
"@aws-sdk/client-s3": "3.917.0",
|
||||
"@aws-sdk/s3-request-presigner": "3.917.0",
|
||||
"@ai-sdk/openai": "^2.0.59",
|
||||
"@ai-sdk/rsc": "^1.0.86",
|
||||
"@aws-sdk/client-s3": "3.922.0",
|
||||
"@aws-sdk/s3-request-presigner": "3.922.0",
|
||||
"@radix-ui/react-dialog": "^1.1.15",
|
||||
"@radix-ui/react-dropdown-menu": "^2.1.16",
|
||||
"@radix-ui/react-tooltip": "^1.2.8",
|
||||
@ -24,8 +24,8 @@
|
||||
"@vercel/analytics": "^1.5.0",
|
||||
"@vercel/blob": "^2.0.0",
|
||||
"@vercel/speed-insights": "^1.2.0",
|
||||
"ai": "^5.0.81",
|
||||
"camelcase-keys": "^10.0.0",
|
||||
"ai": "^5.0.86",
|
||||
"camelcase-keys": "^10.0.1",
|
||||
"clsx": "^2.1.1",
|
||||
"cmdk": "^1.1.1",
|
||||
"culori": "^4.0.2",
|
||||
@ -37,8 +37,8 @@
|
||||
"fast-deep-equal": "^3.1.3",
|
||||
"framer-motion": "^12.23.24",
|
||||
"nanoid": "^5.1.6",
|
||||
"next": "15.5.5",
|
||||
"next-auth": "5.0.0-beta.29",
|
||||
"next": "16.0.1",
|
||||
"next-auth": "5.0.0-beta.30",
|
||||
"next-themes": "^0.4.6",
|
||||
"ol": "^10.6.1",
|
||||
"pg": "^8.16.3",
|
||||
@ -58,8 +58,8 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@eslint/eslintrc": "^3.3.1",
|
||||
"@next/bundle-analyzer": "15.5.5",
|
||||
"@next/eslint-plugin-next": "15.5.5",
|
||||
"@next/bundle-analyzer": "16.0.1",
|
||||
"@next/eslint-plugin-next": "16.0.1",
|
||||
"@stylistic/eslint-plugin": "^5.5.0",
|
||||
"@tailwindcss/postcss": "^4.1.16",
|
||||
"@testing-library/dom": "^10.4.1",
|
||||
@ -67,14 +67,14 @@
|
||||
"@testing-library/react": "^16.3.0",
|
||||
"@types/culori": "^4.0.1",
|
||||
"@types/jest": "^30.0.0",
|
||||
"@types/node": "^24.9.1",
|
||||
"@types/pg": "^8.15.5",
|
||||
"@types/node": "^24.9.2",
|
||||
"@types/pg": "^8.15.6",
|
||||
"@types/react": "19.2.2",
|
||||
"@types/react-dom": "19.2.2",
|
||||
"@types/sanitize-html": "^2.16.0",
|
||||
"cross-fetch": "^4.1.0",
|
||||
"eslint": "9.38.0",
|
||||
"eslint-config-next": "15.5.5",
|
||||
"eslint": "9.39.0",
|
||||
"eslint-config-next": "16.0.1",
|
||||
"jest": "^30.2.0",
|
||||
"jest-environment-jsdom": "^30.2.0",
|
||||
"postcss": "8.5.6",
|
||||
|
||||
1649
pnpm-lock.yaml
generated
1649
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
@ -10,7 +10,7 @@ import {
|
||||
PREFIX_TAG,
|
||||
} from './src/app/path';
|
||||
|
||||
export default function middleware(req: NextRequest, res:NextResponse) {
|
||||
export function proxy(req: NextRequest, res:NextResponse) {
|
||||
const pathname = req.nextUrl.pathname;
|
||||
|
||||
if (pathname === PATH_ADMIN) {
|
||||
@ -11,6 +11,7 @@ import {
|
||||
import AdminAppInsightsClient from './AdminAppInsightsClient';
|
||||
import { getAllInsights, getGitHubMetaForCurrentApp } from '.';
|
||||
import { USED_DEPRECATED_ENV_VARS } from '@/app/config';
|
||||
import { dependencies } from '../../../package.json';
|
||||
|
||||
export default async function AdminAppInsights() {
|
||||
const [
|
||||
@ -42,6 +43,7 @@ export default async function AdminAppInsights() {
|
||||
return (
|
||||
<AdminAppInsightsClient
|
||||
codeMeta={codeMeta}
|
||||
nextVersion={dependencies.next}
|
||||
insights={getAllInsights({
|
||||
codeMeta,
|
||||
photosCount,
|
||||
|
||||
@ -48,6 +48,8 @@ import IconPhoto from '@/components/icons/IconPhoto';
|
||||
import { HiOutlineDocumentText } from 'react-icons/hi';
|
||||
import { ReactNode } from 'react';
|
||||
import MaskedScroll from '@/components/MaskedScroll';
|
||||
import IconNext from '@/components/icons/IconNext';
|
||||
import Link from 'next/link';
|
||||
|
||||
const DEBUG_COMMIT_SHA = '4cd29ed';
|
||||
const DEBUG_COMMIT_MESSAGE = 'Long commit message for debugging purposes';
|
||||
@ -113,6 +115,7 @@ const renderWarningIconSmall =
|
||||
|
||||
export default function AdminAppInsightsClient({
|
||||
codeMeta,
|
||||
nextVersion,
|
||||
insights,
|
||||
usedDeprecatedEnvVars,
|
||||
photoStats: {
|
||||
@ -129,6 +132,7 @@ export default function AdminAppInsightsClient({
|
||||
},
|
||||
}: {
|
||||
codeMeta?: Awaited<ReturnType<typeof getGitHubMetaForCurrentApp>>
|
||||
nextVersion: string
|
||||
insights: ReturnType<typeof getAllInsights>
|
||||
usedDeprecatedEnvVars: typeof USED_DEPRECATED_ENV_VARS
|
||||
photoStats: PhotoStats
|
||||
@ -276,6 +280,16 @@ export default function AdminAppInsightsClient({
|
||||
</span>
|
||||
</a>}
|
||||
/>
|
||||
<ScoreCardRow
|
||||
icon={<IconNext className="self-start translate-y-px" />}
|
||||
content={<Link
|
||||
// eslint-disable-next-line max-len
|
||||
href={`https://github.com/vercel/next.js/releases/tag/v${nextVersion}`}
|
||||
target="blank"
|
||||
>
|
||||
Next.js {nextVersion}
|
||||
</Link>}
|
||||
/>
|
||||
</ScoreCard>
|
||||
</>}
|
||||
<ScoreCard title="Template recommendations">
|
||||
|
||||
@ -2,7 +2,6 @@ import { CategoryKey } from '../category';
|
||||
import {
|
||||
CATEGORY_VISIBILITY,
|
||||
IS_BUILDING,
|
||||
IS_PRODUCTION,
|
||||
STATICALLY_OPTIMIZED_PHOTO_CATEGORIES,
|
||||
STATICALLY_OPTIMIZED_PHOTO_CATEGORY_OG_IMAGES,
|
||||
STATICALLY_OPTIMIZED_PHOTO_OG_IMAGES,
|
||||
@ -21,11 +20,10 @@ const logStaticGenerationDetails = (count: number, content: string) => {
|
||||
}
|
||||
};
|
||||
|
||||
export const staticallyGeneratePhotosIfConfigured = (type: StaticOutput) =>
|
||||
IS_PRODUCTION && (
|
||||
export const staticallyGeneratePhotosIfConfigured = (type: StaticOutput) => (
|
||||
(type === 'page' && STATICALLY_OPTIMIZED_PHOTOS) ||
|
||||
(type === 'image' && STATICALLY_OPTIMIZED_PHOTO_OG_IMAGES)
|
||||
)
|
||||
)
|
||||
? async () => {
|
||||
const photoIds = await getPublicPhotoIds({
|
||||
limit: GENERATE_STATIC_PARAMS_LIMIT,
|
||||
@ -47,8 +45,7 @@ export const staticallyGenerateCategoryIfConfigured = <T, K>(
|
||||
getData: () => Promise<T[]>,
|
||||
formatData: (data: T[]) => K[],
|
||||
): (() => Promise<K[]>) | undefined =>
|
||||
CATEGORY_VISIBILITY.includes(key) &&
|
||||
IS_PRODUCTION && (
|
||||
CATEGORY_VISIBILITY.includes(key) && (
|
||||
(type === 'page' && STATICALLY_OPTIMIZED_PHOTO_CATEGORIES) ||
|
||||
(type === 'image' && STATICALLY_OPTIMIZED_PHOTO_CATEGORY_OG_IMAGES)
|
||||
)
|
||||
|
||||
43
src/components/icons/IconNext.tsx
Normal file
43
src/components/icons/IconNext.tsx
Normal file
@ -0,0 +1,43 @@
|
||||
/* eslint-disable max-len */
|
||||
|
||||
import clsx from 'clsx/lite';
|
||||
|
||||
export default function IconNext({
|
||||
className,
|
||||
}: {
|
||||
className?: string
|
||||
}) {
|
||||
return (
|
||||
<span className={clsx(
|
||||
'text-main dark:text-black',
|
||||
'border border-transparent dark:border-white/40 rounded-full',
|
||||
className,
|
||||
)}>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 180 180" width="1em" height="1em">
|
||||
<mask height="180" id=":r8:mask0_408_134" maskUnits="userSpaceOnUse" width="180" x="0" y="0" style={{ maskType: 'alpha' }}>
|
||||
<circle cx="90" cy="90" fill="black" r="90"></circle>
|
||||
</mask>
|
||||
<g mask="url(#:r8:mask0_408_134)">
|
||||
<circle cx="90" cy="90" data-circle="true" fill="currentColor" r="90"></circle>
|
||||
<path
|
||||
d="M149.508 157.52L69.142 54H54V125.97H66.1136V69.3836L139.999 164.845C143.333 162.614 146.509 160.165 149.508 157.52Z"
|
||||
fill="url(#:r8:paint0_linear_408_134)">
|
||||
</path>
|
||||
<rect fill="url(#:r8:paint1_linear_408_134)" height="72" width="12" x="115" y="54"></rect>
|
||||
</g>
|
||||
<defs>
|
||||
<linearGradient gradientUnits="userSpaceOnUse" id=":r8:paint0_linear_408_134" x1="109"
|
||||
x2="144.5" y1="116.5" y2="160.5">
|
||||
<stop stopColor="white"></stop>
|
||||
<stop offset="1" stopColor="white" stopOpacity="0"></stop>
|
||||
</linearGradient>
|
||||
<linearGradient gradientUnits="userSpaceOnUse" id=":r8:paint1_linear_408_134" x1="121"
|
||||
x2="120.799" y1="54" y2="106.875">
|
||||
<stop stopColor="white"></stop>
|
||||
<stop offset="1" stopColor="white" stopOpacity="0"></stop>
|
||||
</linearGradient>
|
||||
</defs>
|
||||
</svg>
|
||||
</span>
|
||||
);
|
||||
}
|
||||
@ -102,31 +102,31 @@ const getPhotosCacheKeys = (options: PhotoQueryOptions = {}) => {
|
||||
};
|
||||
|
||||
export const revalidatePhotosKey = () =>
|
||||
revalidateTag(KEY_PHOTOS);
|
||||
revalidateTag(KEY_PHOTOS, 'max');
|
||||
|
||||
export const revalidateAlbumsKey = () =>
|
||||
revalidateTag(KEY_ALBUMS);
|
||||
revalidateTag(KEY_ALBUMS, 'max');
|
||||
|
||||
export const revalidateTagsKey = () =>
|
||||
revalidateTag(KEY_TAGS);
|
||||
revalidateTag(KEY_TAGS, 'max');
|
||||
|
||||
export const revalidateRecipesKey = () =>
|
||||
revalidateTag(KEY_RECIPES);
|
||||
revalidateTag(KEY_RECIPES, 'max');
|
||||
|
||||
export const revalidateCamerasKey = () =>
|
||||
revalidateTag(KEY_CAMERAS);
|
||||
revalidateTag(KEY_CAMERAS, 'max');
|
||||
|
||||
export const revalidateLensesKey = () =>
|
||||
revalidateTag(KEY_LENSES);
|
||||
revalidateTag(KEY_LENSES, 'max');
|
||||
|
||||
export const revalidateFilmsKey = () =>
|
||||
revalidateTag(KEY_FILMS);
|
||||
revalidateTag(KEY_FILMS, 'max');
|
||||
|
||||
export const revalidateFocalLengthsKey = () =>
|
||||
revalidateTag(KEY_FOCAL_LENGTHS);
|
||||
revalidateTag(KEY_FOCAL_LENGTHS, 'max');
|
||||
|
||||
export const revalidateYearsKey = () =>
|
||||
revalidateTag(KEY_YEARS);
|
||||
revalidateTag(KEY_YEARS, 'max');
|
||||
|
||||
export const revalidateAllKeys = () => {
|
||||
revalidatePhotosKey();
|
||||
@ -151,7 +151,7 @@ export const revalidateAllKeysAndPaths = () => {
|
||||
|
||||
export const revalidatePhoto = (photoId: string) => {
|
||||
// Tags
|
||||
revalidateTag(photoId);
|
||||
revalidateTag(photoId, 'max');
|
||||
revalidateYearsKey();
|
||||
revalidateCamerasKey();
|
||||
revalidateLensesKey();
|
||||
|
||||
@ -15,7 +15,7 @@
|
||||
"moduleResolution": "bundler",
|
||||
"resolveJsonModule": true,
|
||||
"isolatedModules": true,
|
||||
"jsx": "preserve",
|
||||
"jsx": "react-jsx",
|
||||
"incremental": true,
|
||||
"plugins": [
|
||||
{
|
||||
|
||||
Loading…
Reference in New Issue
Block a user