mirror of
https://github.com/stack-auth/stack.git
synced 2026-06-04 21:04:37 +08:00
Support create-next-app@15 with the setup wizard (#340)
This commit is contained in:
parent
968802690f
commit
c2bc80bda5
@ -12,7 +12,7 @@ export default function GlobalError({ error }: any) {
|
||||
|
||||
return (
|
||||
<html>
|
||||
<body suppressHydrationWarning>
|
||||
<body>
|
||||
[An unhandled error occurred.]
|
||||
<Error
|
||||
statusCode={500}
|
||||
|
||||
@ -13,8 +13,8 @@ export default function RootLayout({
|
||||
children: React.ReactNode,
|
||||
}) {
|
||||
return (
|
||||
<html lang="en" suppressHydrationWarning>
|
||||
<body suppressHydrationWarning>
|
||||
<html lang="en">
|
||||
<body>
|
||||
{children}
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@ -26,7 +26,7 @@ export default function GlobalError({ error }: any) {
|
||||
|
||||
return (
|
||||
<html>
|
||||
<body suppressHydrationWarning>
|
||||
<body>
|
||||
{isProdLike ? (
|
||||
<Spinner />
|
||||
) : (
|
||||
|
||||
@ -67,7 +67,7 @@ export default function RootLayout({
|
||||
}
|
||||
|
||||
return (
|
||||
<html lang="en" className={`${GeistSans.variable} ${GeistMono.variable}`} suppressHydrationWarning>
|
||||
<html lang="en" className={`${GeistSans.variable} ${GeistMono.variable}`}>
|
||||
<head>
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" />
|
||||
<StyleLink href="https://fonts.googleapis.com/css2?family=Material+Symbols+Rounded&display=block" />
|
||||
@ -85,10 +85,9 @@ export default function RootLayout({
|
||||
<CSPostHogProvider>
|
||||
<body
|
||||
className={cn(
|
||||
"min-h-screen bg-background font-sans antialiased",
|
||||
fontSans.variable
|
||||
)}
|
||||
suppressHydrationWarning
|
||||
"min-h-screen bg-background font-sans antialiased",
|
||||
fontSans.variable
|
||||
)}
|
||||
>
|
||||
<Analytics />
|
||||
<PageView />
|
||||
|
||||
14
apps/e2e/tests/general/setup-wizard.ts
Normal file
14
apps/e2e/tests/general/setup-wizard.ts
Normal file
@ -0,0 +1,14 @@
|
||||
import { exec } from "child_process";
|
||||
import { describe } from "vitest";
|
||||
import { it } from "../helpers";
|
||||
|
||||
describe("Setup wizard", () => {
|
||||
it("completes successfully with create-next-app", async ({ expect }) => {
|
||||
const [error, stdout, stderr] = await new Promise<[Error | null, string, string]>((resolve) => {
|
||||
exec("pnpm -C packages/init-stack run test-run-auto", (error, stdout, stderr) => {
|
||||
resolve([error, stdout, stderr]);
|
||||
});
|
||||
});
|
||||
expect(error, `Expected no error to be thrown!\n\n\n\nstdout: ${stdout}\n\n\n\nstderr: ${stderr}`).toBeNull();
|
||||
}, 120_000);
|
||||
});
|
||||
@ -8,7 +8,7 @@
|
||||
--foreground: black;
|
||||
}
|
||||
|
||||
[data-stack-theme='dark'] {
|
||||
html:has(head > [data-stack-theme="dark"]) {
|
||||
--background: black;
|
||||
--foreground: white;
|
||||
}
|
||||
@ -16,4 +16,4 @@
|
||||
body {
|
||||
background-color: var(--background);
|
||||
color: var(--foreground);
|
||||
}
|
||||
}
|
||||
|
||||
@ -19,7 +19,7 @@ export default function RootLayout({
|
||||
return (
|
||||
<html lang="en" suppressHydrationWarning>
|
||||
<head />
|
||||
<body suppressHydrationWarning>
|
||||
<body>
|
||||
<StackProvider app={stackServerApp}>
|
||||
<StackTheme>
|
||||
<Provider>
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
/** @type {import('tailwindcss').Config} */
|
||||
module.exports = {
|
||||
darkMode: ["selector", '[data-stack-theme="dark"]'],
|
||||
darkMode: ["selector", 'html:has(head > [data-stack-theme="dark"])'],
|
||||
content: [
|
||||
"./src/**/*.{js,ts,jsx,tsx,mdx}",
|
||||
"./node_modules/@stackframe/stack-ui/src/**/*.{ts,tsx}",
|
||||
|
||||
@ -8,7 +8,7 @@
|
||||
--foreground: black;
|
||||
}
|
||||
|
||||
[data-stack-theme='dark'] {
|
||||
html:has(head > [data-stack-theme="dark"]) {
|
||||
--background: black;
|
||||
--foreground: white;
|
||||
}
|
||||
@ -16,4 +16,4 @@
|
||||
body {
|
||||
background-color: var(--background);
|
||||
color: var(--foreground);
|
||||
} */
|
||||
} */
|
||||
|
||||
@ -20,7 +20,7 @@ export default function RootLayout({
|
||||
return (
|
||||
<html lang="en" suppressHydrationWarning className={inter.className}>
|
||||
<head />
|
||||
<body suppressHydrationWarning>
|
||||
<body>
|
||||
<StackProvider
|
||||
app={stackServerApp}
|
||||
>
|
||||
|
||||
@ -3,7 +3,7 @@ import { stackServerApp } from "../stack";
|
||||
|
||||
export default function RootLayout({ children }: { children: React.ReactNode }) {
|
||||
return (
|
||||
<html lang="en" suppressHydrationWarning>
|
||||
<html lang="en">
|
||||
<body className="bg-background text-foreground">
|
||||
<StackProvider app={stackServerApp}>
|
||||
<StackTheme>
|
||||
|
||||
1
packages/init-stack/.gitignore
vendored
Normal file
1
packages/init-stack/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
||||
test-run-output
|
||||
@ -75,7 +75,7 @@ async function main() {
|
||||
);
|
||||
}
|
||||
const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, "utf-8"));
|
||||
const nextVersionInPackageJson = packageJson?.dependencies["next"] ?? packageJson?.devDependencies["next"];
|
||||
const nextVersionInPackageJson = packageJson?.dependencies?.["next"] ?? packageJson?.devDependencies?.["next"];
|
||||
if (!nextVersionInPackageJson) {
|
||||
throw new UserError(
|
||||
`The project at ${projectPath} does not appear to be a Next.js project, or does not have 'next' installed as a dependency. Only Next.js projects are currently supported.`
|
||||
@ -195,6 +195,8 @@ async function main() {
|
||||
);
|
||||
}
|
||||
|
||||
const stackPackageName = process.env.STACK_PACKAGE_NAME_OVERRIDE || "@stackframe/stack";
|
||||
|
||||
const isReady = await inquirer.prompt([
|
||||
{
|
||||
type: "confirm",
|
||||
@ -209,7 +211,7 @@ async function main() {
|
||||
|
||||
console.log();
|
||||
console.log(`${ansis.bold}Installing dependencies...${ansis.clear}`);
|
||||
await shellNicelyFormatted(`${installCommand} @stackframe/stack`, {
|
||||
await shellNicelyFormatted(`${installCommand} ${stackPackageName}`, {
|
||||
shell: true,
|
||||
cwd: projectPath,
|
||||
});
|
||||
@ -294,7 +296,9 @@ main()
|
||||
"For more information, please visit https://docs.stack-auth.com/getting-started/setup"
|
||||
);
|
||||
console.log();
|
||||
await open("https://app.stack-auth.com/wizard-congrats");
|
||||
if (!process.env.STACK_DISABLE_INTERACTIVE) {
|
||||
await open("https://app.stack-auth.com/wizard-congrats");
|
||||
}
|
||||
})
|
||||
.catch((err) => {
|
||||
if (!(err instanceof UserError)) {
|
||||
|
||||
@ -5,7 +5,11 @@
|
||||
"main": "index.mjs",
|
||||
"bin": "./index.mjs",
|
||||
"scripts": {
|
||||
"init-stack": "node index.mjs"
|
||||
"clean": "rimraf test-run-output && rimraf node_modules",
|
||||
"init-stack": "node index.mjs",
|
||||
"init-stack:local": "STACK_PACKAGE_NAME_OVERRIDE=../../stack node index.mjs",
|
||||
"test-run": "rimraf test-run-output && npx -y create-next-app@latest test-run-output && pnpm run init-stack:local test-run-output",
|
||||
"test-run-auto": "rimraf test-run-output && npx -y create-next-app@latest test-run-output --app --ts --no-src-dir --tailwind --use-npm --eslint --import-alias '##@#/*' --turbopack && STACK_DISABLE_INTERACTIVE=true pnpm run init-stack:local test-run-output"
|
||||
},
|
||||
"files": [
|
||||
"README.md",
|
||||
|
||||
@ -28,12 +28,12 @@
|
||||
}
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": ">=18.2",
|
||||
"react-dom": ">=18.2",
|
||||
"react": ">=18.2 || >=19.0.0-rc.0",
|
||||
"react-dom": ">=18.2 || >=19.0.0-rc.0",
|
||||
"yup": "^1.4.0",
|
||||
"@types/react": ">=18.2.66",
|
||||
"@types/react-dom": ">=18.2.66",
|
||||
"next": ">=14.1.0"
|
||||
"@types/react": ">=18.2.66 || >=19.0.0-rc.0",
|
||||
"@types/react-dom": ">=18.2.66 || >=19.0.0-rc.0",
|
||||
"next": ">=14.1.0 || >=15.0.0-rc.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@types/react": {
|
||||
|
||||
@ -30,11 +30,11 @@
|
||||
"LICENSE"
|
||||
],
|
||||
"peerDependencies": {
|
||||
"next": ">=14.1",
|
||||
"react": ">=18.2",
|
||||
"react-dom": ">=18.2",
|
||||
"@types/react": ">=18.3.12",
|
||||
"@types/react-dom": ">=18.3.1"
|
||||
"next": ">=14.1 || >=15.0.0-rc.0",
|
||||
"react": ">=18.2 || >=19.0.0-rc.0",
|
||||
"react-dom": ">=18.2 || >=19.0.0-rc.0",
|
||||
"@types/react": ">=18.3.12 || >=19.0.0-rc.0",
|
||||
"@types/react-dom": ">=18.3.1 || >=19.0.0-rc.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@types/react": {
|
||||
|
||||
@ -27,11 +27,11 @@
|
||||
}
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": ">=18.2",
|
||||
"react-dom": ">=18.2",
|
||||
"@types/react": ">=18.2",
|
||||
"@types/react-dom": ">=18.2",
|
||||
"next": ">=14.1.0",
|
||||
"react": ">=18.2 || >=19.0.0-rc.0",
|
||||
"react-dom": ">=18.2 || >=19.0.0-rc.0",
|
||||
"@types/react": ">=18.2 || >=19.0.0-rc.0",
|
||||
"@types/react-dom": ">=18.2 || >=19.0.0-rc.0",
|
||||
"next": ">=14.1.0 || >=15.0.0-rc.0",
|
||||
"yup": "^1.4.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
|
||||
@ -1,10 +1,14 @@
|
||||
import { useParams } from "next/navigation";
|
||||
import { useEffect, useState } from "react";
|
||||
import { useSyncExternalStore } from "react";
|
||||
import { suspendIfSsr } from "../utils/react";
|
||||
|
||||
const getHash = () => typeof window === "undefined" ? undefined : window.location.hash.substring(1);
|
||||
export const useHash = () => {
|
||||
const params = useParams();
|
||||
const [hash, setHash] = useState(getHash());
|
||||
useEffect(() => setHash(getHash()), [params]);
|
||||
return hash;
|
||||
suspendIfSsr("useHash");
|
||||
return useSyncExternalStore(
|
||||
(onChange) => {
|
||||
const interval = setInterval(() => onChange(), 10);
|
||||
return () => clearInterval(interval);
|
||||
},
|
||||
() => window.location.hash.substring(1)
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@ -23,11 +23,11 @@
|
||||
}
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": ">=18.2",
|
||||
"react-dom": ">=18.2",
|
||||
"@types/react": ">=18.2.12",
|
||||
"@types/react-dom": ">=18.2.12",
|
||||
"next": ">=14.1.0",
|
||||
"react": ">=18.2 || >=19.0.0-rc.0",
|
||||
"react-dom": ">=18.2 || >=19.0.0-rc.0",
|
||||
"@types/react": ">=18.2.12 || >=19.0.0-rc.0",
|
||||
"@types/react-dom": ">=18.2.12 || >=19.0.0-rc.0",
|
||||
"next": ">=14.1.0 || >=15.0.0-rc.0",
|
||||
"yup": "^1.4.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
|
||||
@ -66,11 +66,11 @@
|
||||
"yup": "^1.4.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"next": ">=14.1",
|
||||
"react": ">=18.2",
|
||||
"react-dom": ">=18.2",
|
||||
"@types/react": ">=18.2",
|
||||
"@types/react-dom": ">=18.2"
|
||||
"next": ">=14.1 || >=15.0.0-rc.0",
|
||||
"react": ">=18.2 || >=19.0.0-rc.0",
|
||||
"react-dom": ">=18.2 || >=19.0.0-rc.0",
|
||||
"@types/react": ">=18.2 || >=19.0.0-rc.0",
|
||||
"@types/react-dom": ">=18.2 || >=19.0.0-rc.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@types/react": {
|
||||
|
||||
@ -30,7 +30,6 @@ export function MaybeFullPage({
|
||||
<>
|
||||
<div
|
||||
id={id}
|
||||
suppressHydrationWarning
|
||||
style={{
|
||||
minHeight: '100vh',
|
||||
alignSelf: 'stretch',
|
||||
|
||||
@ -11,7 +11,6 @@ export function SsrScript(props: { script: string, nonce?: string }) {
|
||||
|
||||
return (
|
||||
<script
|
||||
suppressHydrationWarning
|
||||
nonce={props.nonce}
|
||||
dangerouslySetInnerHTML={{ __html: props.script }}
|
||||
/>
|
||||
|
||||
@ -69,7 +69,7 @@ function convertColorsToCSS(theme: Theme) {
|
||||
.stack-scope {
|
||||
${colorsToCSSVars(colors.light)}
|
||||
}
|
||||
[data-stack-theme="dark"] .stack-scope {
|
||||
html:has(head > [data-stack-theme="dark"]) .stack-scope {
|
||||
${colorsToCSSVars(colors.dark)}
|
||||
}`;
|
||||
}
|
||||
@ -95,7 +95,6 @@ export function StackTheme({
|
||||
<>
|
||||
<BrowserScript nonce={nonce} />
|
||||
<style
|
||||
suppressHydrationWarning
|
||||
nonce={nonce}
|
||||
dangerouslySetInnerHTML={{
|
||||
__html: globalCSS + "\n" + convertColorsToCSS(themeValue),
|
||||
|
||||
@ -17,7 +17,14 @@ const script = () => {
|
||||
};
|
||||
|
||||
const setTheme = (mode: 'dark' | 'light') => {
|
||||
document.documentElement.setAttribute('data-stack-theme', mode);
|
||||
let el = document.getElementById(`--stack-theme-mode`);
|
||||
if (!el) {
|
||||
el = document.createElement("style");
|
||||
el.id = `--stack-theme-mode`;
|
||||
el.innerHTML = `/* This tag is used by Stack Auth to set the theme in the browser without causing a hydration error (since React ignores additional tags in the <head>). We later use the \`html:has(head > [data-stack-theme=XYZ])\` selector to apply styles based on the theme. */`;
|
||||
document.head.appendChild(el);
|
||||
}
|
||||
el.setAttribute("data-stack-theme", mode);
|
||||
};
|
||||
|
||||
const colorToRGB = (color: string): [number, number, number] | null => {
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
/** @type {import('tailwindcss').Config} */
|
||||
module.exports = {
|
||||
darkMode: ["selector", '[data-stack-theme="dark"]'],
|
||||
darkMode: ["selector", 'html:has(head > [data-stack-theme="dark"])'],
|
||||
content: [
|
||||
"./src/**/*.{ts,tsx}",
|
||||
"./node_modules/@stackframe/stack-ui/src/**/*.{ts,tsx}",
|
||||
|
||||
@ -752,10 +752,10 @@ importers:
|
||||
specifier: workspace:*
|
||||
version: link:../stack-ui
|
||||
'@types/react':
|
||||
specifier: '>=18.2'
|
||||
specifier: '>=18.2 || >=19.0.0-rc.0'
|
||||
version: 18.3.12
|
||||
'@types/react-dom':
|
||||
specifier: '>=18.2'
|
||||
specifier: '>=18.2 || >=19.0.0-rc.0'
|
||||
version: 18.2.18
|
||||
browser-image-compression:
|
||||
specifier: ^2.0.2
|
||||
@ -882,10 +882,10 @@ importers:
|
||||
specifier: workspace:*
|
||||
version: link:../stack-ui
|
||||
'@types/react':
|
||||
specifier: '>=18.2.66'
|
||||
specifier: '>=18.2.66 || >=19.0.0-rc.0'
|
||||
version: 18.3.12
|
||||
'@types/react-dom':
|
||||
specifier: '>=18.2.66'
|
||||
specifier: '>=18.2.66 || >=19.0.0-rc.0'
|
||||
version: 18.3.1
|
||||
clsx:
|
||||
specifier: ^2.1.1
|
||||
@ -937,10 +937,10 @@ importers:
|
||||
packages/stack-sc:
|
||||
dependencies:
|
||||
'@types/react':
|
||||
specifier: '>=18.3.12'
|
||||
specifier: '>=18.3.12 || >=19.0.0-rc.0'
|
||||
version: 18.3.12
|
||||
'@types/react-dom':
|
||||
specifier: '>=18.3.1'
|
||||
specifier: '>=18.3.1 || >=19.0.0-rc.0'
|
||||
version: 18.3.1
|
||||
devDependencies:
|
||||
next:
|
||||
@ -965,10 +965,10 @@ importers:
|
||||
specifier: workspace:*
|
||||
version: link:../stack-sc
|
||||
'@types/react':
|
||||
specifier: '>=18.2'
|
||||
specifier: '>=18.2 || >=19.0.0-rc.0'
|
||||
version: 18.3.12
|
||||
'@types/react-dom':
|
||||
specifier: '>=18.2'
|
||||
specifier: '>=18.2 || >=19.0.0-rc.0'
|
||||
version: 18.2.18
|
||||
bcrypt:
|
||||
specifier: ^5.1.1
|
||||
@ -1116,10 +1116,10 @@ importers:
|
||||
specifier: ^8.20.5
|
||||
version: 8.20.5(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
|
||||
'@types/react':
|
||||
specifier: '>=18.2.12'
|
||||
specifier: '>=18.2.12 || >=19.0.0-rc.0'
|
||||
version: 18.3.12
|
||||
'@types/react-dom':
|
||||
specifier: '>=18.2.12'
|
||||
specifier: '>=18.2.12 || >=19.0.0-rc.0'
|
||||
version: 18.2.18
|
||||
class-variance-authority:
|
||||
specifier: ^0.7.0
|
||||
|
||||
Loading…
Reference in New Issue
Block a user