Bulletproof React

repository·master·Indexed 12 days ago

https://github.com/alan2207/bulletproof-react

An opinionated, scalable, and production-ready architecture for building React applications. It provides a collection of best practices, architectural patterns, and structured project layouts to ensure maintainability and consistency across codebases. The repository includes sample implementations using Next.js (App and Pages routers) and React Vite, demonstrating core principles of scalability, reliability, and clean boundaries.

Tokens
29.3K
Snippets
100
Records
138
Agent score
97%

What's inside Bulletproof React

  1. Overview of Bulletproof React architecture

    master

    Bulletproof React is an opinionated architecture designed for building simple, scalable, and production-ready React applications. It is not a template or a boilerplate, but rather a collection of resources, best practices, and architectural patterns intended to solve real-world problems in a practical way.

    The architecture focuses on several core principles:

    • Scalability: Designed to scale in terms of both codebase size and team size.
    • Maintainability: Emphasizes simple, understandable code with clean boundaries between application parts.
    • Consistency: Provides a standard way of doing things so team members stay aligned.
    • Reliability: Focuses on security, performance, and early issue detection.

    While the repository showcases specific tools and libraries, users are encouraged to focus on the underlying principles and concepts rather than being strictly limited to the specific technology stack used in the sample applications.

  2. Implement API mocking with MSW

    master

    Use MSW to create a mocked server that intercepts HTTP requests. This is useful for:

    1. Prototyping: Building frontend features before the backend is ready.
    2. API Design: Defining endpoints and business logic within MSW handlers.
    3. Integration Testing: Making actual HTTP calls that are intercepted by the service worker, providing a more realistic test environment than manual fetch mocks.
  3. Implement Permission-Based Access Control (PBAC)

    master

    For granular control where roles are insufficient (e.g., allowing only the owner of a resource to edit it), use Permission-Based Access Control (PBAC).

    Instead of passing roles to the RBAC component, you pass a policy check. This allows you to evaluate dynamic conditions (like comment.authorId === currentUser.id) to determine access.

    <RBAC policy={(user) => user.id === comment.authorId}>
      <DeleteCommentButton />
    </RBAC>
  4. Manage In-App Errors with React Error Boundaries

    master

    Use React Error Boundaries to prevent application crashes when a component fails. Instead of using a single global error boundary, place multiple error boundaries at different levels of your component tree. This containment strategy ensures that an error in one specific feature (e.g., a discussion thread) does not disrupt the entire application's functionality.

    For a practical example of localized error handling, see the implementation in discussion.tsx.

    /* See implementation in: ../apps/react-vite/src/app/routes/app/discussions/discussion.tsx */
  5. Manage URL State via routing

    master
    URL state is data stored in the browser's address bar, such as dynamic path parameters (e.g., /app/${dynamicParam}) or query parameters (e.g., /app?dynamicParam=1). Use routing solutions like react-router-dom to access and control this state, allowing users to manipulate application parameters directly via the URL.
  6. Implement Role-Based Access Control (RBAC)

    master

    RBAC determines access by assigning specific roles (e.g., USER, ADMIN) to users. To protect UI elements or routes using RBAC, use the RBAC component and pass the allowedRoles prop.

    Example usage for restricting a component to specific roles:

    <RBAC allowedRoles={['ADMIN']}>
      <DeleteDiscussionButton />
    </RBAC>
  7. Manage Application State with global stores

    master

    Application state manages global concerns like notifications, global modals, or color modes. To maintain performance, localize this state as closely as possible to the components that need it rather than making everything global by default.

    Recommended solutions for Application State:

    • React Context + Hooks
    • Redux + Redux Toolkit
    • MobX
    • Zustand
    • Jotai
    • XState
  8. Select a Styling Solution

    master

    There are several ways to style a React application. Note that if you are using React Server Components (RSC), you must use a zero-runtime styling solution.

    Common Styling Options

    • Tailwind CSS: Utility-first CSS framework.
    • Vanilla-extract: Type-safe, zero-runtime CSS-in-JS.
    • Panda CSS: Type-safe, build-time CSS-in-JS.
    • CSS Modules: Scoped CSS using standard CSS files.
    • Styled-components / Emotion: Runtime CSS-in-JS solutions.

    Component-as-Code (Hybrid)

    These provide predefined components that are provided as code rather than as an installed package, allowing for deep customization:

    • ShadCN UI
    • Park UI
  9. Understand the application data model

    master

    The application is built around a hierarchical structure of Users, Teams, Discussions, and Comments. Understanding these relationships is key to navigating the application logic:

    • User: Has one of two roles:
      • ADMIN: Can create/edit/delete discussions, create/delete all comments, delete users, and edit their own profile.
      • USER: Can edit their own profile and create/delete their own comments.
    • Team: A group consisting of one admin and multiple users who participate in discussions.
    • Discussion: A topic created by members of a team.
    • Comment: Individual messages within a discussion.
  10. Maintain code quality with ESLint, Prettier, and TypeScript

    master

    The project relies on a combination of three tools to ensure code quality and consistency:

    1. ESLint: Used for linting JavaScript/TypeScript to identify errors and enforce coding standards via .eslintrc.js.
    2. Prettier: Used for consistent code formatting. It is recommended to enable "format on save" in your IDE. Prettier can be integrated with ESLint to handle both formatting and linting.
    3. TypeScript: Used to catch type-related bugs and assist during large refactoring processes. When refactoring, prioritize updating type declarations first, then resolving the resulting TypeScript errors.
  11. Manage Server Cache State with caching libraries

    master

    Server Cache State refers to remote data stored locally on the client for future use. While you can use a general state manager like Redux, it is more efficient to use specialized caching libraries designed for server state.

    Recommended libraries for Server Cache State:

    • TanStack Query (react-query): For REST and GraphQL.
    • SWR: For REST and GraphQL.
    • Apollo Client: For GraphQL.
    • urql: For GraphQL.
    • RTK Query: Part of Redux Toolkit.
  12. Securely store authentication tokens

    master

    When implementing authentication in a Single Page Application (SPA), you must decide where to store the JSON Web Token (JWT).

    • Application State: Most secure, but the token is lost on page refresh.
    • localStorage/sessionStorage: Common, but vulnerable to Cross-Site Scripting (XSS) attacks which can lead to token theft.
    • Cookies (Recommended): Storing tokens in cookies configured with the HttpOnly attribute is the most secure method because they are inaccessible to client-side JavaScript, mitigating XSS risks.

    In this project, js-cookie is used for cookie management, assuming the backend enforces the HttpOnly attribute.