Skip to content
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

feat: Next.js@13 support #3140

Merged
merged 17 commits into from
Dec 7, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
80 changes: 80 additions & 0 deletions .changeset/khaki-timers-travel.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
---
"@pankod/refine-nextjs-router": major
---

- Bumped Next.js to 13
- Added support for experimental `appDir` option in `next.config.js` to allow for the latest Next.js features.


## `pages` directory

Current support for `pages` directory has not changed and will continue to work as before. It will be supported as long as `Next.js` continues to support and prompts it as the stable way of working with `Next.js`.

## `appDir` option

`appDir` option is a new experimental feature in `Next.js` that introduces a bunch of new features. It is currently in beta and is not stable. It is not recommended to use it in production. But can be used alongside the current `pages` directory support.

To use `appDir` option, you need to add it to your `next.config.js` file.

```js
// next.config.js
module.exports = {
/* ... */
experimental: {
appDir: true,
},
};
```

## Using `appDir` with **refine**

We've needed to make some changes to the `@pankod/refine-nextjs-router` to make it work with the current structure of the `app` directory feature. To make sure these do not break the current support for `pages` directory, we've added a new exports at the sub path `@pankod/refine-nextjs-router/app` that can be used with the `appDir` option.

**Note**

To make optional catch-all routes to work with the `app` directory, you need to define them as directories unlike the option of defining them as files with `pages` directory.

You need to use `NextRouteComponent` from `@pankod/refine-nextjs-router/app` instead of `NextRouteComponent` from `@pankod/refine-nextjs-router` when using `appDir` option.

Inside your `layout` file, you need to bind `params` to `routerProvider` to make sure `@pankod/refine-nextjs-router` can work properly with the new structure.

```tsx
// app/[[...refine]]/layout.tsx
"use client";

import routerProvider from "@pankod/refine-nextjs-router/app";

const Layout = ({ children, params }) => {
return (
<Refine
routerProvider={routerProvider.apply({ params })}
/* ... */
>
{children}
</Refine>
);
};
```

**Warning**

Please note that, unlike the `routerProvider` from the `@pankod/refine-nextjs-router`, `routerProvider` from `@pankod/refine-nextjs-router/app` is a function and you need to bind `params` to make it work properly.

```tsx
// app/[[...refine]]/page.tsx

"use client";

import { NextRouteComponent } from "@pankod/refine-nextjs-router/app";

export default NextRouteComponent;

```

**Warning**

You need to add `"use client";` directive to both `layout.tsx` and `page.tsx` inside `app/[[...refine]]` directory.

**Warning**

`checkAuthentication` does not work with `appDir`. We're aiming to release a substitute for it using middleware but for now its not included in this release.
79 changes: 78 additions & 1 deletion documentation/docs/advanced-tutorials/ssr/nextjs.md
Original file line number Diff line number Diff line change
Expand Up @@ -396,9 +396,86 @@ export const getServerSideProps: GetServerSideProps = async (context) => {

`parseTableParams` parses the query string and returns query parameters([refer here for their interfaces][interfaces]). They can be directly used for `dataProvider` methods that accepts them.

## `appDir` Support

Next.js introduced a new way of defining pages within the `app/` directory. _This new directory has support for layouts, nested routes, and uses Server Components by default._ To learn more about the feature check out [Next.js Beta docs](https://beta.nextjs.org/docs/upgrade-guide)

**refine** also follows this feature and provides a way to use `appDir` with your **refine** apps.

:::caution

`app/` is currently in beta and is **not recommended** for production use in Next.js. In **refine**, we're providing the `app/` support as experimental and not recommended for production use.

:::

To start using `app/` with **refine**, you need to set create the **refine** routes in your `/app` directory with the following convention:

```bash

your-project
└── app
└── [[...refine]]
├── layout.tsx
└── page.tsx

```

**Initializing `<Refine/>` in `layout.tsx`**

```tsx title="app/[[...refine]]/layout.tsx"
"use client";

import routerProvider from "@pankod/refine-nextjs-router/app";

export default function RefineLayout({
children,
params,
}: {
children: React.ReactNode;
params: Record<"refine", string[]>;
}) {
return (
<Refine
routerProvider={routerProvider.call({ params })}
/* ... */
>
{children}
</Refine>
);
}
```

We need to bind the `params` to the `routerProvider` and call it to initialize the `routerProvider`. This is because the `params` are not available via hooks for **refine** to use.

**Creating `page.tsx`**

```tsx title="app/[[...refine]]/page.tsx"
"use client";

import { NextRouteComponent } from "@pankod/refine-nextjs-router/app";

export default NextRouteComponent;
```

Note that we're importing `NextRouteComponent` from `@pankod/refine-nextjs-router/app` instead of `@pankod/refine-nextjs-router`. This is because we're using the `app/` directory and we need to import the `app` version of the `NextRouteComponent`.

:::note
`"use client";` is a directive that instructs Next.js to opt-out from Server Components. This is because **refine** and dependencies are not yet compatible with Server Components. Thats why we're using it in both `layout.tsx` and `page.tsx` files.
:::

:::note
`checkAuthentication` does not work with `app/` directory. You need to handle the authentication your views while using `app/` directory.

**refine** aims to provide a middleware for `app/` directory to substitue `checkAuthentication` but it's not available yet.
:::

:::info
You can find the `app/` directory example with **refine** in [examples/nextjs/appdir](https://github.com/refinedev/refine/tree/next/examples/remix/antd)
:::

## Live StackBlitz Example

<iframe loading="lazy" src="https://stackblitz.com/github/refinedev/refine/tree/master/examples/refine-next/?embed=1&view=preview&theme=dark&preset=node&ctl=1"
<iframe loading="lazy" src="https://stackblitz.com/github/refinedev/refine/tree/master/examples/nextjs/base/?embed=1&view=preview&theme=dark&preset=node&ctl=1"
style={{width: "100%", height:"80vh", border: "0px", borderRadius: "8px", overflow:"hidden"}}
title="refine-next"
></iframe>
Expand Down
16 changes: 16 additions & 0 deletions documentation/docs/examples/next-js/appdir.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
---
id: nextjs-appdir
title: With `app/` Directory
example-tags: [next.js,router-provider,antd,experimental]
---

**refine** allows you to use the `app/` structure in your Next.js apps. To learn more about the `app/` directory, check out [Next.js beta docs](https://beta.nextjs.org/docs/upgrade-guide). In this example you will find how to use the `app/` directory with refine.

[Refer to the refine Next.js documentation for more information. →](/docs/advanced-tutorials/ssr/nextjs.md)

[View Next.js with `app/` Example Source](https://github.com/refinedev/refine/tree/master/examples/nextjs/appdir)

<iframe loading="lazy" src="https://stackblitz.com/github/refinedev/refine/tree/master/examples/nextjs/appdir/?embed=1&view=preview&theme=dark&preset=node&ctl=1"
style={{width: "100%", height:"80vh", border: "0px", borderRadius: "8px", overflow:"hidden"}}
title="refine-nextjs-appdir-example"
></iframe>
4 changes: 2 additions & 2 deletions documentation/docs/examples/next-js/next-js.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,9 @@ example-tags: [next.js,router-provider,antd]

[Refer to the refine Next.js documentation for more information. →](/docs/advanced-tutorials/ssr/nextjs.md)

[View Next.js Example Source](https://github.com/refinedev/refine/tree/master/examples/refine-next)
[View Next.js Example Source](https://github.com/refinedev/refine/tree/master/examples/nextjs/base)

<iframe loading="lazy" src="https://stackblitz.com/github/refinedev/refine/tree/master/examples/i18n/nextjs/?embed=1&view=preview&theme=dark&preset=node&ctl=1"
<iframe loading="lazy" src="https://stackblitz.com/github/refinedev/refine/tree/master/examples/nextjs/base/?embed=1&view=preview&theme=dark&preset=node&ctl=1"
style={{width: "100%", height:"80vh", border: "0px", borderRadius: "8px", overflow:"hidden"}}
title="refine-nextjs-example"
></iframe>
5 changes: 4 additions & 1 deletion documentation/sidebars.js
Original file line number Diff line number Diff line change
Expand Up @@ -825,7 +825,10 @@ module.exports = {
{
type: "category",
label: "Next.js",
items: ["examples/next-js/nextjs"],
items: [
"examples/next-js/nextjs",
"examples/next-js/nextjs-appdir",
],
},
{
type: "category",
Expand Down
2 changes: 1 addition & 1 deletion examples/blog/ecommerce/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
"@pankod/refine-strapi-v4": "^3.39.0",
"axios": "^0.26.1",
"framer-motion": "^7.5.3",
"next": "^12.1.6",
"next": "^13.0.6",
"next-compose-plugins": "^2.2.1",
"nookies": "^2.5.2",
"react": "^18.0.0",
Expand Down
2 changes: 1 addition & 1 deletion examples/blog/next-refine-pwa/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
"@pankod/refine-core": "^3.90.4",
"@pankod/refine-nextjs-router": "^3.38.0",
"@pankod/refine-simple-rest": "^3.37.4",
"next": "^12.1.6",
"next": "^13.0.6",
"next-compose-plugins": "^2.2.1",
"react": "^18.0.0",
"react-dom": "^18.0.0"
Expand Down
2 changes: 1 addition & 1 deletion examples/fineFoods/client/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
"@pankod/refine-simple-rest": "^3.37.4",
"gsap": "^3.8.0",
"js-confetti": "^0.9.0",
"next": "^12.1.6",
"next": "^13.0.6",
"react": "^18.0.0",
"react-dom": "^18.0.0"
},
Expand Down
2 changes: 1 addition & 1 deletion examples/i18n/nextjs/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
"@pankod/refine-core": "^3.90.4",
"@pankod/refine-nextjs-router": "^3.38.0",
"@pankod/refine-simple-rest": "^3.37.4",
"next": "^12.1.6",
"next": "^13.0.6",
"next-compose-plugins": "^2.2.1",
"next-i18next": "^8.9.0",
"nookies": "^2.5.2",
Expand Down
File renamed without changes.
File renamed without changes.
File renamed without changes.
64 changes: 64 additions & 0 deletions examples/nextjs/appdir/app/[[...refine]]/layout.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
"use client";

import React from "react";

import { Refine } from "@pankod/refine-core";
import {
notificationProvider,
Layout,
ErrorComponent,
AuthPage,
} from "@pankod/refine-antd";
import dataProvider from "@pankod/refine-simple-rest";
import routerProvider from "@pankod/refine-nextjs-router/app";
import "@pankod/refine-antd/dist/styles.min.css";

import "@styles/global.css";

import { authProvider } from "src/authProvider";
import { API_URL } from "../../src/constants";

import { PostList, PostCreate, PostEdit, PostShow } from "@components";

export default function RefineLayout({
children,
params,
}: {
children: React.ReactNode;
params: Record<"refine", string[]>;
}) {
return (
<Refine
routerProvider={routerProvider.call({ params })}
authProvider={authProvider}
dataProvider={dataProvider(API_URL)}
resources={[
{
name: "posts",
list: PostList,
create: PostCreate,
edit: PostEdit,
show: PostShow,
canDelete: true,
},
{ name: "users" },
]}
options={{ syncWithLocation: true }}
notificationProvider={notificationProvider}
LoginPage={() => (
<AuthPage
formProps={{
initialValues: {
email: "admin@refine.dev",
password: "password",
},
}}
/>
)}
Layout={Layout}
catchAll={<ErrorComponent />}
>
{children}
</Refine>
);
}
5 changes: 5 additions & 0 deletions examples/nextjs/appdir/app/[[...refine]]/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
"use client";

import { NextRouteComponent } from "@pankod/refine-nextjs-router/app";

export default NextRouteComponent;
11 changes: 11 additions & 0 deletions examples/nextjs/appdir/app/layout.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
export default function RootLayout({
children,
}: {
children: React.ReactNode;
}) {
return (
<html lang="en">
<body>{children}</body>
</html>
);
}
10 changes: 10 additions & 0 deletions examples/nextjs/appdir/next.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
/** @type {import('next').NextConfig} */
const nextConfig = {
reactStrictMode: true,
swcMinify: true,
experimental: {
appDir: true,
},
};

module.exports = nextConfig;
28 changes: 28 additions & 0 deletions examples/nextjs/appdir/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
{
"name": "refine-nextjs-appdir",
"version": "3.25.0",
"private": true,
"scripts": {
"start": "NODE_OPTIONS=--max_old_space_size=4096 PORT=3002 next dev",
"build": "next build",
"start:prod": "next start",
"lint": "eslint '**/*.{js,jsx,ts,tsx}'"
},
"dependencies": {
"@pankod/refine-antd": "^3.64.2",
"@pankod/refine-core": "^3.90.4",
"@pankod/refine-nextjs-router": "^3.38.0",
"@pankod/refine-simple-rest": "^3.37.4",
"next": "^13.0.6",
"nookies": "^2.5.2",
"react": "^18.0.0",
"react-dom": "^18.0.0"
},
"devDependencies": {
"@types/node": "^12.20.11",
"@types/react": "^18.0.0",
"@types/react-dom": "^18.0.0",
"@typescript-eslint/parser": "^5.38.1",
"typescript": "^4.7.4"
}
}
Loading