Skip to content

Commit

Permalink
feat: Next.js@13 support (#3140)
Browse files Browse the repository at this point in the history
* refactor(nextjs): move current setup to `src/pages` for convenience

* feat(nextjs): `appDir` compatible nextjs router instance

* feat(nextjs): separate export at `/app` for `appDir` feature

* feat(nextjs): add nextjs example with `appDir`

* chore(live-previews): bump to `nextjs` 13

* chore(examples): bump to next 13

* refactor(examples): update component name

* feat(nextjs): add `routercomponent` to `/app` router provider

* chore: add changeset

* chore: update check auth

* chore: update changeset

* chore: fix store incompatible prop type

* docs: update live example link

* chore: move nextjs examples to `examples/nextjs`

* docs: add `app/` example to examples list

* docs(nextjs): add `app` support section
  • Loading branch information
aliemir authored Dec 7, 2022
1 parent f06e017 commit 102bfbf
Show file tree
Hide file tree
Showing 90 changed files with 1,281 additions and 133 deletions.
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.
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>
);
}
File renamed without changes.
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"
}
}
File renamed without changes.
Loading

0 comments on commit 102bfbf

Please sign in to comment.