mirror of
https://github.com/shadcn-ui/ui.git
synced 2026-06-29 23:55:02 +00:00
feat(shadcn): add next 16 to init (#8550)
* feat: add next 16 init * chore: changeset * fix: tests * fix
This commit is contained in:
5
.changeset/nine-steaks-rule.md
Normal file
5
.changeset/nine-steaks-rule.md
Normal file
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"shadcn": minor
|
||||
---
|
||||
|
||||
add Next.js 16 support for init command
|
||||
@@ -80,7 +80,8 @@ export const initOptionsSchema = z.object({
|
||||
return true
|
||||
},
|
||||
{
|
||||
message: "Invalid template. Please use 'next' or 'next-monorepo'.",
|
||||
message:
|
||||
"Invalid template. Please use 'next', 'next-16' or 'next-monorepo'.",
|
||||
}
|
||||
),
|
||||
baseColor: z
|
||||
@@ -109,7 +110,7 @@ export const init = new Command()
|
||||
.argument("[components...]", "names, url or local path to component")
|
||||
.option(
|
||||
"-t, --template <template>",
|
||||
"the template to use. (next, next-monorepo)"
|
||||
"the template to use. (next, next-16, next-monorepo)"
|
||||
)
|
||||
.option(
|
||||
"-b, --base-color <base-color>",
|
||||
|
||||
@@ -121,7 +121,33 @@ describe("createProject", () => {
|
||||
|
||||
expect(execa).toHaveBeenCalledWith(
|
||||
"npx",
|
||||
expect.arrayContaining(["create-next-app@latest", "/test/my-app"]),
|
||||
expect.arrayContaining(["create-next-app@15", "/test/my-app"]),
|
||||
expect.any(Object)
|
||||
)
|
||||
})
|
||||
|
||||
it("should create a Next.js 16 project when next-16 template is selected", async () => {
|
||||
vi.mocked(prompts).mockResolvedValue({ type: "next-16", name: "my-app" })
|
||||
|
||||
const result = await createProject({
|
||||
cwd: "/test",
|
||||
force: false,
|
||||
srcDir: false,
|
||||
})
|
||||
|
||||
expect(result).toEqual({
|
||||
projectPath: "/test/my-app",
|
||||
projectName: "my-app",
|
||||
template: TEMPLATES["next-16"],
|
||||
})
|
||||
|
||||
expect(execa).toHaveBeenCalledWith(
|
||||
"npx",
|
||||
expect.arrayContaining([
|
||||
"create-next-app@latest",
|
||||
"/test/my-app",
|
||||
"--no-react-compiler",
|
||||
]),
|
||||
expect.any(Object)
|
||||
)
|
||||
})
|
||||
@@ -195,4 +221,38 @@ describe("createProject", () => {
|
||||
|
||||
expect(mockExit).toHaveBeenCalledWith(1)
|
||||
})
|
||||
|
||||
it("should include --no-react-compiler flag for Next.js 16 (latest)", async () => {
|
||||
vi.mocked(prompts).mockResolvedValue({ type: "next-16", name: "my-app" })
|
||||
|
||||
await createProject({
|
||||
cwd: "/test",
|
||||
force: false,
|
||||
srcDir: false,
|
||||
})
|
||||
|
||||
expect(execa).toHaveBeenCalledWith(
|
||||
"npx",
|
||||
expect.arrayContaining(["--no-react-compiler"]),
|
||||
expect.any(Object)
|
||||
)
|
||||
})
|
||||
|
||||
it("should not include --no-react-compiler flag for Next.js 15", async () => {
|
||||
vi.mocked(prompts).mockResolvedValue({ type: "next", name: "my-app" })
|
||||
|
||||
await createProject({
|
||||
cwd: "/test",
|
||||
force: false,
|
||||
srcDir: false,
|
||||
})
|
||||
|
||||
const execaCalls = vi.mocked(execa).mock.calls
|
||||
const createNextCall = execaCalls.find(
|
||||
(call) => Array.isArray(call[1]) && call[1].includes("create-next-app@15")
|
||||
)
|
||||
|
||||
expect(createNextCall).toBeDefined()
|
||||
expect(createNextCall?.[1]).not.toContain("--no-react-compiler")
|
||||
})
|
||||
})
|
||||
|
||||
@@ -17,6 +17,7 @@ const MONOREPO_TEMPLATE_URL =
|
||||
|
||||
export const TEMPLATES = {
|
||||
next: "next",
|
||||
"next-16": "next-16",
|
||||
"next-monorepo": "next-monorepo",
|
||||
} as const
|
||||
|
||||
@@ -37,7 +38,7 @@ export async function createProject(
|
||||
: "next"
|
||||
let projectName: string =
|
||||
template === TEMPLATES.next ? "my-app" : "my-monorepo"
|
||||
let nextVersion = "latest"
|
||||
let nextVersion = "15"
|
||||
|
||||
const isRemoteComponent =
|
||||
options.components?.length === 1 &&
|
||||
@@ -72,7 +73,8 @@ export async function createProject(
|
||||
options.cwd
|
||||
)} does not contain a package.json file.\n Would you like to start a new project?`,
|
||||
choices: [
|
||||
{ title: "Next.js", value: "next" },
|
||||
{ title: "Next.js 15", value: "next" },
|
||||
{ title: "Next.js 16", value: "next-16" },
|
||||
{ title: "Next.js (Monorepo)", value: "next-monorepo" },
|
||||
],
|
||||
initial: 0,
|
||||
@@ -92,6 +94,10 @@ export async function createProject(
|
||||
|
||||
template = type ?? template
|
||||
projectName = name
|
||||
|
||||
if (type === "next-16") {
|
||||
nextVersion = "latest"
|
||||
}
|
||||
}
|
||||
|
||||
const packageManager = await getPackageManager(options.cwd, {
|
||||
@@ -125,7 +131,7 @@ export async function createProject(
|
||||
process.exit(1)
|
||||
}
|
||||
|
||||
if (template === TEMPLATES.next) {
|
||||
if (template === TEMPLATES.next || template === TEMPLATES["next-16"]) {
|
||||
await createNextProject(projectPath, {
|
||||
version: nextVersion,
|
||||
cwd: options.cwd,
|
||||
@@ -157,7 +163,9 @@ async function createNextProject(
|
||||
}
|
||||
) {
|
||||
const createSpinner = spinner(
|
||||
`Creating a new Next.js project. This may take a few minutes.`
|
||||
`Creating a new Next.js ${
|
||||
options.version.startsWith("latest") ? "16" : "15"
|
||||
} project. This may take a few minutes.`
|
||||
).start()
|
||||
|
||||
// Note: pnpm fails here. Fallback to npx with --use-PACKAGE-MANAGER.
|
||||
@@ -179,6 +187,13 @@ async function createNextProject(
|
||||
args.push("--turbopack")
|
||||
}
|
||||
|
||||
if (
|
||||
options.version.startsWith("latest") ||
|
||||
options.version.startsWith("canary")
|
||||
) {
|
||||
args.push("--no-react-compiler")
|
||||
}
|
||||
|
||||
try {
|
||||
await execa(
|
||||
"npx",
|
||||
@@ -195,7 +210,11 @@ async function createNextProject(
|
||||
process.exit(1)
|
||||
}
|
||||
|
||||
createSpinner?.succeed("Creating a new Next.js project.")
|
||||
createSpinner?.succeed(
|
||||
`Creating a new Next.js ${
|
||||
options.version.startsWith("latest") ? "16" : "15"
|
||||
} project.`
|
||||
)
|
||||
}
|
||||
|
||||
async function createMonorepoProject(
|
||||
|
||||
Reference in New Issue
Block a user