RedwoodJS

中国镜像

The JS App Framework for Startups

Ship today with architecture for tomorrow. Redwood includes deploy support for Netlify, Vercel, Render.com, AWS and more. Deploy serverless or serverfull and scale from zero servers to a thousand. Built on React, GraphQL, and Prisma, with full TypeScript support, and Webpack/Babel ready to go with zero config. Redwood gives you the workflow you love, but with simple conventions and helpers to make your experience even better.

Get the Newsletter

Keep up on what's happening with RedwoodJS!

Get Some Swag

The Redwood logo on shirts, hats,
and more!

The Redwood Shop →

Get Free Stickers

Enter your address for a chance to get some, free!

Edge-ready

Redwood is designed to be deployable completely to the Edge—CDNs and serverless functions distributed everywhere. (Databases coming soon!)

Code Organization

Redwood has a pre-defined place for all your code— front-end and back-end. Components, layouts, pages, GraphQL, and services: they all have a home.

Developer Experience

Redwood apps are as declarative as possible; we eliminate most boilerplate; zero-config code splitting...everything Just Works™.

How it's Organized

Redwood places both the frontend and backend code in a single monorepo.

/web contains the frontend and is served as static files through a CDN (and automatically code-split for you).

/api contains the backend serverless functions (a GraphQL API by default) that your frontend will call when it needs some dynamic data.

Structure of a Redwood app

Routing

Redwood features its own router that brings some awesome innovation to this often overlooked (but important) part of your app. Named routes let you reference a route by a name you define, route param types take care of coercing values based on data type or custom functions, and more.

// web/src/Routes.js
import { Router, Route } from '@redwoodjs/router'
const Routes = () => {
  return (
    <Router>
      <Route path="/" page={HomePage} name="home" />
      <Route path="/users/{type}" page={UsersPage} name="users" />
    </Router>
  )
}

// web/src/components/Admin/Admin.js
import { Link, routes } from '@redwoodjs/router'
const Admin = () => {
  return (
    <h1><Link to={routes.home()}>My CRM</Link></h1>
    <Link to={routes.users({type: "admin"})}>View Admins</Link>
  )
}

Cells

The sequence of retrieving data from an API, showing a loading placeholder, and then displaying the result is so common that Redwood codifies it into a declarative code pattern, resulting in simple and readable code!

We call them cells and they contain the GraphQL query, loading, empty, error, and success states, each one rendering itself automatically depending on what state your cell is in.

// web/src/components/UsersCell/UsersCell.js
export const QUERY = gql`
  query USERS {
    users {
      id
      name
    }
  }
`
export const Loading = () => <div>Loading users...</div>
export const Empty = () => <div>No users yet!</div>
export const Failure = ({ message }) => <div>Error: {message}</div>
export const Success = ({ users }) => {
  return (
    <ul>
      { users.map(user => (
        <li>{user.id} | {user.name}</li>
      ))}
    </ul>
  )
}

Services

Redwood puts all your business logic in one place—Services. These can be used by your GraphQL API or any other place in your backend code. Redwood does all of the annoying stuff for you.

Check out how easy it is to create and consume a GraphQL endpoint (we didn't even omit any other import statements or cheat to get the code smaller, honest!):

// api/src/graphql/users.sdl.js
export const schema = gql`
  type User {
    id: Int!
    name: String!
  }
  type Query {
    users: [User]
  }
`

// api/src/services/users/users.js
import { db } from 'src/lib/db'

export const users = () => {
  return db.user.findMany()
}

// web/src/components/UsersCell/UsersCell.js
export const QUERY = gql`
  query USERS {
    users {
      id
      name
    }
  }
`
export const Success = ({ users }) => {
  return JSON.stringify(users)
}

Generators

Even with a relentless elimination of boilerplate, Redwood files still need a bit of code to get you started, and need to be created in the right directories. No problem, let a computer do that for you!

Redwood contains several generators which create the shell of cells, pages, layouts, services, and more. We even have a scaffold generator which will create all the pages necessary to run end-to-end CRUD operations on a database table.

# Create a cell for Users
$ yarn rw generate cell Users

# Create a layout named Admin
$ yarn rw generate layout Admin

# Create an About page and set the URL to /about
$ yarn rw generate page About /about

# Read the DB schema and create the SDL file for the User table
$ yarn rw generate sdl User

# Create api/src/services/email/email.js and include CRUD functions
$ yarn rw generate service Email --crud

# Create the SDL, service, cells, pages and components to CRUD a User
$ yarn rw generate scaffold User

Forms

Working with forms is notoriously annoying in React apps. Redwood removes the complexity and gives you the freedom to work with regular HTML inputs, but sprinkled with a bit of validation and error handling. Show client and server-side errors automatically and style them like any other React component.

// web/src/components/Comment/Comment.js
import { Form, Label, TextAreaField, FieldError, Submit } from "@redwoodjs/web"

export const Comment = () => {
  const onSubmit = (data) => {
    console.info(`Submitted: ${data}`)
  }
  return (
    <Form onSubmit={onSubmit}>
      <Label name="comment" errorStyle={{ color: "red" }} />
      <TextAreaField
        name="comment"
        errorStyle={{ borderColor: "red" }}
        validation={{ required: true }}
      />
      <FieldError name="comment" errorStyle={{ color: "red" }} />
      <Submit>Send</Submit>
    </Form>
  )
}
      

Ready for Redwood?