-
-
Notifications
You must be signed in to change notification settings - Fork 9.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Nextjs-Vite: Add Next.js 15 support #29640
Changes from all commits
158e30d
1b72459
dd9ed96
e762e5d
8173350
6a1bbc4
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
// @ts-expect-error Compatibility for Next 14 | ||
export { draftMode } from 'next/dist/client/components/headers'; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,14 +1,15 @@ | ||
import { fn } from '@storybook/test'; | ||
|
||
import * as originalHeaders from 'next/dist/client/components/headers'; | ||
import { draftMode as originalDraftMode } from 'next/dist/server/request/draft-mode'; | ||
import * as headers from 'next/dist/server/request/headers'; | ||
|
||
// re-exports of the actual module | ||
export * from 'next/dist/client/components/headers'; | ||
export * from 'next/dist/server/request/headers'; | ||
|
||
// mock utilities/overrides (as of Next v14.2.0) | ||
export { headers } from './headers'; | ||
export { cookies } from './cookies'; | ||
|
||
// passthrough mocks - keep original implementation but allow for spying | ||
const draftMode = fn(originalHeaders.draftMode).mockName('draftMode'); | ||
const draftMode = fn(originalDraftMode ?? (headers as any).draftMode).mockName('draftMode'); | ||
export { draftMode }; |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -5,25 +5,23 @@ import { cookies, headers } from 'next/headers'; | |
export default async function Component() { | ||
async function handleClick() { | ||
'use server'; | ||
cookies().set('user-id', 'encrypted-id'); | ||
(await cookies()).set('user-id', 'encrypted-id'); | ||
} | ||
|
||
return ( | ||
<> | ||
<h3>Cookies:</h3> | ||
{cookies() | ||
.getAll() | ||
.map(({ name, value }) => { | ||
return ( | ||
<p key={name} style={{ display: 'flex', flexDirection: 'row', gap: 8 }}> | ||
<strong>Name:</strong> <span>{name}</span> | ||
<strong>Value:</strong> <span>{value}</span> | ||
</p> | ||
); | ||
})} | ||
{(await cookies()).getAll().map(({ name, value }) => { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. logic: potential race condition between getting cookies and rendering - cookies().getAll() is called on each render |
||
return ( | ||
<p key={name} style={{ display: 'flex', flexDirection: 'row', gap: 8 }}> | ||
<strong>Name:</strong> <span>{name}</span> | ||
<strong>Value:</strong> <span>{value}</span> | ||
</p> | ||
); | ||
})} | ||
|
||
<h3>Headers:</h3> | ||
{Array.from(headers().entries()).map(([name, value]: [string, string]) => { | ||
{Array.from((await headers()).entries()).map(([name, value]: [string, string]) => { | ||
return ( | ||
<p key={name} style={{ display: 'flex', flexDirection: 'row', gap: 8 }}> | ||
<strong>Name:</strong> <span>{name}</span> | ||
|
This file was deleted.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
import React from 'react'; | ||
|
||
import 'server-only'; | ||
|
||
export const RSC = async ({ label }: { label: string }) => <>RSC {label}</>; | ||
valentinpalkovic marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
export const Nested = async ({ children }: any) => <>Nested {children}</>; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. style: children prop uses 'any' type which loses type safety. Consider using PropsWithChildren or ReactNode type instead |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -5,7 +5,7 @@ import { cookies } from 'next/headers'; | |
import { redirect } from 'next/navigation'; | ||
|
||
export async function accessRoute() { | ||
const user = cookies().get('user'); | ||
const user = (await cookies()).get('user'); | ||
|
||
if (!user) { | ||
redirect('/'); | ||
|
@@ -16,13 +16,13 @@ export async function accessRoute() { | |
} | ||
|
||
export async function logout() { | ||
cookies().delete('user'); | ||
(await cookies()).delete('user'); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. style: check that cookie exists before attempting to delete it |
||
revalidatePath('/'); | ||
redirect('/'); | ||
} | ||
|
||
export async function login() { | ||
cookies().set('user', 'storybookjs'); | ||
(await cookies()).set('user', 'storybookjs'); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. style: verify cookie is set successfully before proceeding with redirect |
||
revalidatePath('/'); | ||
redirect('/'); | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,2 @@ | ||
// Compatibility for Next 14 | ||
// @ts-expect-error Compatibility for Next 14 | ||
export { draftMode } from 'next/dist/client/components/headers'; |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -208,7 +208,7 @@ const baseTemplates = { | |
}, | ||
skipTasks: ['e2e-tests-dev', 'bench', 'vitest-integration'], | ||
}, | ||
'experimental-nextjs-vite/default-ts': { | ||
'experimental-nextjs-vite/14-ts': { | ||
name: 'Next.js Latest (Vite | TypeScript)', | ||
script: | ||
Comment on lines
+211
to
213
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. logic: template name 'Next.js Latest' is misleading since this is specifically for Next.js 14 |
||
'npx create-next-app@^14 {{beforeDir}} --eslint --tailwind --app --import-alias="@/*" --src-dir', | ||
|
@@ -229,6 +229,30 @@ const baseTemplates = { | |
'prop-types', | ||
], | ||
}, | ||
inDevelopment: true, | ||
skipTasks: ['e2e-tests-dev', 'bench'], | ||
}, | ||
'experimental-nextjs-vite/default-ts': { | ||
name: 'Next.js Latest (Vite | TypeScript)', | ||
script: | ||
'npx create-next-app {{beforeDir}} --eslint --tailwind --app --import-alias="@/*" --src-dir', | ||
expected: { | ||
framework: '@storybook/experimental-nextjs-vite', | ||
renderer: '@storybook/react', | ||
builder: '@storybook/builder-vite', | ||
}, | ||
modifications: { | ||
mainConfig: { | ||
framework: '@storybook/experimental-nextjs-vite', | ||
features: { experimentalRSC: true }, | ||
}, | ||
extraDependencies: [ | ||
'server-only', | ||
'@storybook/experimental-nextjs-vite', | ||
'vite', | ||
'prop-types', | ||
], | ||
}, | ||
skipTasks: ['e2e-tests-dev', 'bench'], | ||
}, | ||
'react-vite/default-js': { | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
style: consider adding type assertion for headers.draftMode to avoid using any