Skip to content

feat: SSR/Next Server Actions Support #528

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

Merged
merged 31 commits into from
Dec 31, 2023
Merged
Show file tree
Hide file tree
Changes from 27 commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
23bd4d5
docs: add initial NextJS RSC code sample
crutchcorn Nov 5, 2023
5eab53a
chore: replace react imports with rehackt imports
crutchcorn Dec 13, 2023
1a9b91c
chore: initial work to add server action support to React Form
crutchcorn Dec 13, 2023
f41ad62
feat: got initial demo of NextJS server action error to work
crutchcorn Dec 13, 2023
08b8331
feat: add useTransform and mergeForm APIs
crutchcorn Dec 13, 2023
6520695
chore: WIP
crutchcorn Dec 13, 2023
e22cbed
feat: add transform array checking
crutchcorn Dec 13, 2023
2c42134
fix: issues with canSubmit state issues when using server validation
crutchcorn Dec 13, 2023
7f4bba9
fix: remove error when Field component is first ran
crutchcorn Dec 13, 2023
275c983
fix: correct failing tests
crutchcorn Dec 13, 2023
076bff5
chore: fix ci/cd
crutchcorn Dec 13, 2023
871f7f3
chore: fix next server action typings
crutchcorn Dec 13, 2023
acb8e6d
chore: fix various issues with templates and CI/CD
crutchcorn Dec 13, 2023
6a9147a
chore: upgrade node version
crutchcorn Dec 28, 2023
994c85c
chore: change from tsup to manual rollup
crutchcorn Dec 28, 2023
8f056b3
Revert "chore: change from tsup to manual rollup"
crutchcorn Dec 28, 2023
b9b1f07
chore: attempt to fix tsup issues
crutchcorn Dec 28, 2023
84b3aa0
Revert "chore: attempt to fix tsup issues"
crutchcorn Dec 28, 2023
b291b7b
Merge branch 'main' into nextjs-server-actions
crutchcorn Dec 29, 2023
ddea1ee
chore: migrate form-core to use Vite
crutchcorn Dec 29, 2023
a44c97d
chore: migrate Vue package to Vite
crutchcorn Dec 29, 2023
169950b
docs: migrate form adapters to vite
crutchcorn Dec 29, 2023
cfe9e3b
chore: migrate solid and react packages to use vite
crutchcorn Dec 29, 2023
4adba66
chore: refactor to single config generator
crutchcorn Dec 29, 2023
58d0378
chore: remove typescript 4.8
crutchcorn Dec 29, 2023
d1772f7
chore: fix issues with test ci
crutchcorn Dec 29, 2023
fd11504
chore: fix PR CI
crutchcorn Dec 29, 2023
db6ca34
chore: fix clean script
crutchcorn Dec 29, 2023
f2fa22b
Merge main into nextjs-server-actions (#545)
lachlancollins Dec 31, 2023
a56e6bf
Merge branch 'main' into nextjs-server-actions
lachlancollins Dec 31, 2023
cce56b1
Fix lockfile
lachlancollins Dec 31, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ jobs:
version: 8
- uses: actions/setup-node@v3
with:
node-version: 18.15.0
node-version: 18.19.0
registry-url: https://registry.npmjs.org/
cache: 'pnpm'
- name: Install dependencies
Expand Down
10 changes: 5 additions & 5 deletions .github/workflows/pr.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ jobs:
version: 8
- uses: actions/setup-node@v3
with:
node-version: 18.15.0
node-version: 18.19.0
cache: 'pnpm'
- name: Install dependencies
run: pnpm --prefer-offline install --no-frozen-lockfile
Expand All @@ -45,7 +45,7 @@ jobs:
version: 7
- uses: actions/setup-node@v3
with:
node-version: 16.14.2
node-version: 18.19.0
cache: 'pnpm'
- name: Install dependencies
run: pnpm --prefer-offline install --no-frozen-lockfile
Expand All @@ -64,7 +64,7 @@ jobs:
version: 7
- uses: actions/setup-node@v3
with:
node-version: 16.14.2
node-version: 18.19.0
cache: 'pnpm'
- name: Install dependencies
run: pnpm --prefer-offline install --no-frozen-lockfile
Expand All @@ -83,7 +83,7 @@ jobs:
version: 7
- uses: actions/setup-node@v3
with:
node-version: 16.14.2
node-version: 18.19.0
cache: 'pnpm'
- name: Install dependencies
run: pnpm --prefer-offline install --no-frozen-lockfile
Expand All @@ -102,7 +102,7 @@ jobs:
version: 7
- uses: actions/setup-node@v3
with:
node-version: 16.14.2
node-version: 18.19.0
cache: 'pnpm'
- name: Install dependencies
run: pnpm --prefer-offline install --no-frozen-lockfile
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -45,3 +45,4 @@ dist
.idea

nx-cloud.env
.nx
7 changes: 7 additions & 0 deletions examples/react/next-server-actions/.eslintrc.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
module.exports = {
extends: 'next/core-web-vitals',
parserOptions: {
tsconfigRootDir: __dirname,
project: ['./tsconfig.json'],
},
}
36 changes: 36 additions & 0 deletions examples/react/next-server-actions/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.

# dependencies
/node_modules
/.pnp
.pnp.js
.yarn/install-state.gz

# testing
/coverage

# next.js
/.next/
/out/

# production
/build

# misc
.DS_Store
*.pem

# debug
npm-debug.log*
yarn-debug.log*
yarn-error.log*

# local env files
.env*.local

# vercel
.vercel

# typescript
*.tsbuildinfo
next-env.d.ts
36 changes: 36 additions & 0 deletions examples/react/next-server-actions/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
This is a [Next.js](https://nextjs.org/) project bootstrapped with [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app).

## Getting Started

First, run the development server:

```bash
npm run dev
# or
yarn dev
# or
pnpm dev
# or
bun dev
```

Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.

You can start editing the page by modifying `app/page.tsx`. The page auto-updates as you edit the file.

This project uses [`next/font`](https://nextjs.org/docs/basic-features/font-optimization) to automatically optimize and load Inter, a custom Google Font.

## Learn More

To learn more about Next.js, take a look at the following resources:

- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API.
- [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial.

You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js/) - your feedback and contributions are welcome!

## Deploy on Vercel

The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js.

Check out our [Next.js deployment documentation](https://nextjs.org/docs/deployment) for more details.
4 changes: 4 additions & 0 deletions examples/react/next-server-actions/next.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
/** @type {import('next').NextConfig} */
const nextConfig = {}

module.exports = nextConfig
25 changes: 25 additions & 0 deletions examples/react/next-server-actions/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
{
"name": "@tanstack/form-example-react-next-server-actions",
"version": "0.1.0",
"private": true,
"scripts": {
"dev": "next dev",
"build": "next build",
"test:types": "tsc --noEmit",
"test:eslint": "next lint"
},
"dependencies": {
"react": "^18",
"react-dom": "^18",
"next": "14.0.4",
"@tanstack/react-form": "^0.11.0"
},
"devDependencies": {
"typescript": "^5",
"@types/node": "^20",
"@types/react": "18.2.35",
"@types/react-dom": "^18.2.14",
"eslint": "^8",
"eslint-config-next": "14.0.4"
}
}
7 changes: 7 additions & 0 deletions examples/react/next-server-actions/src/app/action.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
'use server'

import { formFactory } from './shared-code'

export default async function someAction(prev: unknown, formData: FormData) {
return await formFactory.validateFormData(formData)
}
68 changes: 68 additions & 0 deletions examples/react/next-server-actions/src/app/client-component.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
/// <reference types="../../node_modules/@types/react-dom/experimental" />
'use client'

import { useFormState } from 'react-dom'
import someAction from './action'
import { formFactory } from './shared-code'
import { useTransform, mergeForm, type FormApi } from '@tanstack/react-form'

export const ClientComp = () => {
const [state, action] = useFormState(someAction, formFactory.initialFormState)

const form = formFactory.useForm({
transform: useTransform(
(baseForm: FormApi<any, any>) => mergeForm(baseForm, state),
[state],
),
})

const formErrors = form.useStore((formState) => formState.errors)

return (
<form.Provider>
<form action={action as never} onSubmit={() => form.handleSubmit()}>
{formErrors.map((error) => (
<p key={error as string}>{error}</p>
))}

<form.Field
name="age"
validators={{
onChange: ({ value }) =>
value < 8
? 'Client validation: You must be at least 8'
: undefined,
}}
>
{(field) => {
return (
<div>
<input
name="age"
type="number"
value={field.state.value}
onChange={(e) => field.handleChange(e.target.valueAsNumber)}
/>
{field.state.meta.errors.map((error) => (
<p key={error as string}>{error}</p>
))}
</div>
)
}}
</form.Field>
<form.Subscribe
selector={(formState) => [
formState.canSubmit,
formState.isSubmitting,
]}
>
{([canSubmit, isSubmitting]) => (
<button type="submit" disabled={!canSubmit}>
{isSubmitting ? '...' : 'Submit'}
</button>
)}
</form.Subscribe>
</form>
</form.Provider>
)
}
18 changes: 18 additions & 0 deletions examples/react/next-server-actions/src/app/layout.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import type { Metadata } from 'next'

export const metadata: Metadata = {
title: 'Create Next App',
description: 'Generated by create next app',
}

export default function RootLayout({
children,
}: {
children: React.ReactNode
}) {
return (
<html lang="en">
<body>{children}</body>
</html>
)
}
9 changes: 9 additions & 0 deletions examples/react/next-server-actions/src/app/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { ClientComp } from './client-component'

export default function Home() {
return (
<>
<ClientComp />
</>
)
}
13 changes: 13 additions & 0 deletions examples/react/next-server-actions/src/app/shared-code.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { createFormFactory } from '@tanstack/react-form'

export const formFactory = createFormFactory({
defaultValues: {
firstName: '',
age: 0,
},
onServerValidate({ value }) {
if (value.age < 12) {
return 'Server validation: You must be at least 12 to sign up'
}
},
})
24 changes: 24 additions & 0 deletions examples/react/next-server-actions/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
{
"compilerOptions": {
"target": "es5",
"lib": ["dom", "dom.iterable", "esnext"],
"allowJs": true,
"skipLibCheck": true,
"strict": true,
"noEmit": true,
"esModuleInterop": true,
"module": "esnext",
"moduleResolution": "bundler",
"resolveJsonModule": true,
"isolatedModules": true,
"jsx": "preserve",
"incremental": true,
"plugins": [
{
"name": "next"
}
]
},
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
"exclude": ["node_modules"]
}
1 change: 1 addition & 0 deletions examples/react/simple/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
"jsx": "react",
"noEmit": true,
"strict": true,
"esModuleInterop": true,
"lib": ["DOM", "DOM.Iterable", "ES2020"]
}
}
1 change: 1 addition & 0 deletions examples/react/valibot/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
"jsx": "react",
"noEmit": true,
"strict": true,
"esModuleInterop": true,
"lib": ["DOM", "DOM.Iterable", "ES2020"]
}
}
1 change: 1 addition & 0 deletions examples/react/yup/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
"jsx": "react",
"noEmit": true,
"strict": true,
"esModuleInterop": true,
"lib": ["DOM", "DOM.Iterable", "ES2020"]
}
}
1 change: 1 addition & 0 deletions examples/react/zod/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
"jsx": "react",
"noEmit": true,
"strict": true,
"esModuleInterop": true,
"lib": ["DOM", "DOM.Iterable", "ES2020"]
}
}
39 changes: 0 additions & 39 deletions getTsupConfig.js

This file was deleted.

Loading