refinedev / refine

A React Framework for building internal tools, admin panels, dashboards & B2B apps with unmatched flexibility.
https://refine.dev
MIT License
27.75k stars 2.15k forks source link

[FEAT] To simplify adding a page after adding resources using CLI with Next.js. #6091

Closed noritsune closed 1 month ago

noritsune commented 3 months ago

Is your feature request related to a problem? Please describe.

I usually use Refine with Next.js (App Router). The CLI command for adding resources is very convenient.

However, the files generated by the CLI are all components. Each time, I go through the following cumbersome process to convert them into pages:

  1. Execute the npx refine add resource command.
    • This generates CRUD operation components under /src/components/{resource name}.
    • image
  2. Move each .tsx file from /src/components/{resource name} to /src/app/{resource name}.
  3. Modify the directory structure in /src/app/{resource name} according to the specifications in _refine_context.tsx. Rename each .tsx file moved in the previous step to page.tsx.
    • image
  4. Replace each export const in the CRUD pages with export default function;
    • before: export const UsersShow = () => {
    • after: export default function UsersShow() {
    • If I use export const, the following error will be displayed in the browser when I open the page.
      • Error: The default export is not a React Component in page: "/users/show/[id]"

Describe alternatives you've considered

No response

Additional context

No response

Describe the thing to improve

Below is my request

  1. When using Refine with Next.js, adding resources via CLI should generate appropriate page.tsx files under /src/app/.
  2. Each generated page.tsx file should export the page component with export default function.
noritsune commented 3 months ago

If you assign me this issue, I'm ready to take on the challenge of fixing it.

alicanerdurmaz commented 3 months ago

Hello @noritsune, thank you for the issue. I agree that we can improve the developer experience.

After discussing with the core team, we thought it would be good to keep the current system as it is and add new features for Next.js (App Router).

Here are the steps:

  1. Run npx refine add resource
  2. Create /src/components/{resource name} and, if using Next.js (App Router), add the “use client” directive to this file.
  3. If using Next.js (App Router), create the routes for this resource component and return the created resource component.

We believe this approach is simpler to implement and improves the developer experience. What are your thoughts?

And of course, I can assign this issue to you. We would be very happy 🙌

noritsune commented 3 months ago

Hello, @alicanerdurmaz!

Thank you for your response and for assigning me to this issue.

Am I correct in understanding that according to the proposed modification, both the component and page files will be created under /src/components/{resource name} and /src/app/{resource name} respectively?

I don't quite understand why we need the component file in addition to the page file. Could you please explain why a component file is necessary for CRUD operations on the resource? I've gone through the CLI documentation but couldn't find any information regarding this, hence the confusion.

alicanerdurmaz commented 3 months ago

Refine is independent of the route package and can be used with Remix, React Router, Next.js App Router, or Next.js Pages Router. While there may not be an issue currently, we believe that separating the JSX code of resources into components is the correct approach.

For example, when using React Router, we write:

<Route path="/" element={<PostListPage />} />

However, with Next.js, we use a file-based system to achieve the same result. Fundamentally, we believe that the rendered output in this route should be a separate component.

Additionally, the Next.js App Router defaults to server components, but components generated by the Refine CLI cannot run on the server. Therefore, we need to add the "use-client" directive at the top of the file we create. If we create the resource component in /src/app/{resource name}, unfortunately, we take away the user's ability to use this route on the server.

noritsune commented 3 months ago

Thank you for the detailed explanation.

I now understand why the npx refine add resource command creates a component file instead of a page, and I agree that maintaining this feature makes sense.

Now, regarding your idea of adding an option to the npx refine add resource command—specifically --for-next-app:

With this option, when executing npx refine add resource, instead of creating a component file, a page.tsx file would be generated under /src/app/{resource name} following the routing structure. The contents of the file would be almost identical to the current setup, but would use export default function instead of export const.

Additionally, it might be beneficial to add a --for-next-page option for those using the Next.js page router.

Having these options would allow developers using Next.js with Refine to effortlessly generate CRUD pages for their resources without any further modifications, simply by running a command.

alicanerdurmaz commented 3 months ago

The current components need the "use client" directive to be compatible with RSC, but adding this to all files would restrict users. We agree to update the command to include page.tsx files that correctly import and return these components, but filling page.tsx with them could limit users.

For example, if we keep resource components in the components folder, we can:

Generating the resource component directly in page.tsx with the "use client" directive would be like doing this:

<Route
  path="posts/list"
  Component={() => {
    return <div>{/** Generated resource component code */}</div>;
  }}
/>

Also, we don't need to add an option to Refine CLI. We can detect the type of application (Next.js, Vite, Remix, etc.) and make the necessary adjustments. The Refine CLI can already do this, but we need extra control for Next.js appdir and pages.

noritsune commented 3 months ago

Refine CLI can automatically switch its behavior based on the framework you are using—that's correct, and I didn't know that. Thank you for informing me.

I agree that keeping Refine CLI simple without adding options would be beneficial.

From your explanations so far, I now fully understand what you're trying to convey. So, regarding the new feature you proposed for Next.js (App Router), is it intended to work like this?

  1. Execute npx refine add resource.
  2. Create CRUD component files under /src/components/{resource name}:
    • These files have the use client directive added at the top.
  3. Create corresponding CRUD page.tsx files under /src/app/{resource name} in the appropriate directory structure:
    • Each page.tsx file returns the corresponding CRUD component generated in step 2.
    • page.tsx files should not include the use client directive as they should run on the server.

Here is an example of the files that would be generated.

/src/components/users/list.tsx

"use client";

import { MuiInferencer } from "@refinedev/inferencer/mui";

export const UserList = () => {
    return <MuiInferencer />;
};

/src/app/page.tsx

import { UserList } from "@components/users";

export default function UserListPage() {
    return (<UserList/>)
}
alicanerdurmaz commented 3 months ago

Refine CLI can automatically switch its behavior based on the framework you are using—that's correct, and I didn't know that. Thank you for informing me.

I agree that keeping Refine CLI simple without adding options would be beneficial.

From your explanations so far, I now fully understand what you're trying to convey. So, regarding the new feature you proposed for Next.js (App Router), is it intended to work like this?

  1. Execute npx refine add resource.
  2. Create CRUD component files under /src/components/{resource name}:

    • These files have the use client directive added at the top.
  3. Create corresponding CRUD page.tsx files under /src/app/{resource name} in the appropriate directory structure:

    • Each page.tsx file returns the corresponding CRUD component generated in step 2.
    • page.tsx files should not include the use client directive as they should run on the server.

Here is an example of the files that would be generated.

/src/components/users/list.tsx

"use client";

import { MuiInferencer } from "@refinedev/inferencer/mui";

export const UserList = () => {
    return <MuiInferencer />;
};

/src/app/page.tsx

import { UserList } from "@components/users";

export default function UserListPage() {
    return (<UserList/>)
}

Yes, I think this is good.

noritsune commented 3 months ago

Thank you. I will now start working on this task.

aliemir commented 1 month ago

With thanks to the @noritsune's contribution, we've published this feature with our latest release of @refinedev/cli 🙏