iTranslated by AI

The content below is an AI-generated translation. This is an experimental feature, and may contain errors. View original article
🥑

Introduction to RedwoodJS (Part 5: Final Thoughts and Impressions)

に公開

About this article

This is the fifth part of a five-part series.
Getting Started with RedwoodJS (Part 1: App Creation to Model Creation)
Getting Started with RedwoodJS (Part 2: CRUD Creation API Edition)
Getting Started with RedwoodJS (Part 3: CRUD Creation WEB Edition)
Getting Started with RedwoodJS (Part 4: Authentication with dbAuth)
Getting Started with RedwoodJS (Part 5: Impressions after actually using it)

In this article, I will summarize my impressions of using Redwood so far.

What I liked about RedwoodJS

Can be written almost entirely in TypeScript

The fact that you can reap the benefits of TypeScript on both the frontend and backend is huge.

When developing with a stack like Rails, GraphQL (GraphQL Ruby), and React + TypeScript, context switching used to occur even for a single variable name—such as using snake_case because the backend is Ruby and camelCase because the frontend is TypeScript. Although it's a small detail, I thought it was great that this is no longer necessary.

GraphQL is available

This is simply because I like this architecture, but I felt again that GraphQL is excellent.

You get the benefits of types on the frontend and can define queries across resources. As I experienced with Rails + GraphQL development, the developer experience (DX) is fantastic.

You have to be careful about N+1 problems, but since Prisma has DataLoader built-in, that drawback is mitigated (though N+1 can still occur depending on how queries are defined).

Test files are also generated by Generator commands

Redwood's Generators basically ensure that test files are generated at the same time as any given file.

For example, running yarn rw g cell foo generates FooCell.mock.ts, FooCell.stories.tsx, and FooCell.test.tsx in addition to FooCell.tsx.

I appreciate that the barrier to writing test code is lowered even by a little.

The built-in Router is great

While it's entirely a matter of personal preference, Redwood's Router has just the right balance between handling things for you and requiring manual configuration. Although I have some opinions about the page imports (mentioned later), I felt that it is functionally more than sufficient, offering good visibility for component definitions using Set and Private, rendering during loading, and path definition methods.

A few things that concerned me about RedwoodJS

Regarding the frequency of version updates

This is a point that can be both good and bad, but although version 1.0 was released in April of this year (less than a year ago), version 3.6 has already been released.

I read in an article somewhere that they aim to add features without fear of major updates. While I have high expectations that it will continue to improve, I also worry that keeping up with versions might be difficult if there are many breaking changes.

Cell Specifications

I can't quite get used to the specification where you define named exports for things like { data, loading, error } (similar to what Apollo Client's useQuery returns) using specific component names within a single file and then import that file.

Since you have to import the entire file, named imports are not possible, and editor autocompletion often fails when calling a Cell (it works occasionally for some reason, but most of the time it doesn't).

Since importing Cells happens quite frequently, I wish there were a way to improve this... (or perhaps it can be resolved through some configuration?).

Similar to React Suspense, I'm happy that the loading state doesn't leak into the component displaying the data, but it's a specification that personally leaves me feeling a bit uneasy.

Importing Pages in Routes.tsx

In Routes.tsx, Redwood handles things behind the scenes to prevent the list of import statements from growing, allowing you to call Pages without importing them. It also makes them global variables so that no editor errors occur.

While it seems convenient, it can lead to confusing names depending on how the Page components are organized. (For example, a component at web/src/pages/Post/PostPage/PostPage.tsx becomes PostPostPage).

I felt that if it has to go that far, it might be better to just have the import statements.

Of course, typing PostPage will automatically add the import statement via autocompletion, but once you type "Post," the suggestions get crowded with many PostXxx items, which is a bit confusing.

It might be something I'll stop noticing once I'm used to it, but it's a point that caught my attention.

Query types are sometimes not automatically generated

When the server is running and you edit a QUERY within a Cell file, graphql.d.ts is supposed to be automatically regenerated with the new content. However, I frequently experienced cases where it wouldn't update unless I manually ran yarn rw g types. I might have some misunderstanding, but having to define a QUERY or mutation -> manually run yarn rw g types -> return to the file to import the generated type while working on the same file felt a bit cumbersome.

Type definition loading sometimes fails

After creating a Foo model and running yarn rw prisma migrate dev, importing db from src/lib/db and accessing db.foo sometimes results in an error like Property 'foo' does not exist on type 'PrismaClient<{ log: LogDefinition[]; }, never, false>'. ts(2339). Even though it's added to the Prisma type definitions, the editor seems to be using a cache. Opening node_modules/.prisma/client/index.d.ts usually makes the editor recognize the type, perhaps by forcing a reload. It might be due to my specific environment, but it's a bit annoying.

rw setup i18n does not support TypeScript

This is a minor point and might be addressed in the future...

There is a command called yarn rw setup i18n that automates i18n setup, including installing react-i18next and its related packages and generating initial configuration files. However, even in a TypeScript project, these configuration files are generated as .js files. Since other auto-generated files also require several manual updates, the utility of the command feels somewhat limited.

How does it compare to Rails?

To begin with, although I can see some shared philosophies, plain Rails and Redwood felt like quite different things.

Backend type checking is possible

It might be possible with Rails + RBS, but Rails doesn't fully support it yet. In some cases, you have to manually create type definition files for checking. In that regard, Redwood generates most type definitions from the DB Schema. Since editor autocompletion also works, having types makes the developer experience feel very good.

Prisma and ActiveRecord

I felt that this isn't simply a case of DB operations being replaced, but rather that the concepts themselves are different. Therefore, I can't say definitively which is better, but it made me realize once again how convenient ActiveRecord was. The fact that classes are generated according to the DB tables is great.

In contrast, Redwood also has a concept called RedwoodRecord.

RedwoodRecord is, as the name suggests, the Redwood version of ActiveRecord. It allows you to define validations in classes and perform record operations in a way similar to ActiveRecord. Furthermore, it seems that callbacks like afterCreate are planned to be added in the future.

However, personally, I believe that DB-related operations should be centralized in the Service layer, so I wonder if RedwoodRecord is actually suitable for Redwood's framework design in the first place...

https://redwoodjs.com/docs/redwoodrecord

Conclusion

I've written about Redwood across five parts, and I felt that it's something that can reasonably be considered for production use.

I appreciated that it minimizes the need for Redwood-specific syntax by relying on existing ecosystems like npm packages—for instance, the i18n generate command sets up react-i18next, and although not covered in this article, the built-in Redwood Form is a thin wrapper around react-hook-form. I felt it's a framework with plenty of room for future growth.

GitHubで編集を提案

Discussion