UIFork

repository·main·Indexed 42 days ago

https://github.com/sambernhardt/uifork

A CLI tool and React component library for managing UI component versions. UIFork enables file-based versioning and runtime switching of components, allowing developers to iterate on UI variations using a wrapper-based rendering approach and a dedicated watch server for synchronization.

Tokens
9.2K
Snippets
38
Records
45
Agent score
53%

What's inside UIFork

  1. How UIFFork works: File-based versioning and runtime switching

    main

    UIFork enables structured UI iteration using three core mechanisms:

    1. File-based versions

    Each variation is a real file on disk (e.g., Button.v1.tsx, Button.v2.tsx). This allows for source control history, AI generation, and file-level diffing.

    2. Wrapper-based rendering

    When you initialize a component, UIFFork replaces it with a wrapper. This wrapper:

    • Reads the active version from localStorage.
    • Dynamically imports the correct version file.
    • Re-renders instantly when the version is switched.

    3. Runtime switching

    The UIFFork widget allows you to switch versions instantly. It persists your selection in localStorage. You can also use keyboard shortcuts to cycle through versions:

    • Mac: Cmd + Arrow Up/Down
    • Windows/Linux: Ctrl + Arrow Up/Down
  2. Understand the UIFork file structure

    main

    After initializing a component (e.g., src/components/Button.tsx), UIFork manages the following file structure:

    • Button.tsx: The wrapper component. This is the file you should import in your application code. It reads the active version from localStorage and renders the corresponding version.
    • Button.versions.ts: The configuration file that tracks all available versions.
    • Button.v1.tsx: The original component (Version 1).
    • Button.v2.tsx: An additional version.
    • Button.v1_1.tsx: A sub-version (displayed as V1.1 in the UI).

    Version Naming Convention:

    • v1, v2: Major versions.
    • v1_1, v1_2: Sub-versions (displayed as V1.1, V1.2 in the UI).
  3. How UIFork works internally

    main

    UIFork enables real-time UI experimentation through a coordinated system of components and a local server:

    1. The Wrapper (ForkedComponent): When you import your component, you are actually importing a wrapper. This wrapper reads the currently active version ID from localStorage and renders the matching version file.
    2. The Widget (UIFork): The floating widget connects to the local watch server to discover all available versions defined in your project.
    3. State Synchronization: When a user selects a new version in the widget, the widget updates localStorage. This triggers the wrapper component to re-render with the new version.
    4. The Watch Server: The server monitors your file system. When new version files are detected (or created via CLI), it automatically updates the versions.ts file so the widget stays in sync.
  4. Setup UIFFork using AI Agents & Skills

    main

    For an optimized AI-driven experience, you can add the UIFork skill to your agent. This allows you to prompt the agent to add UIFFork to your project or fork components directly.

    1. Add the skill:

    npx skills add sambernhardt/uifork

    2. Add UIFFork to your project: Use a prompt like Add uifork to this application. If the skill isn't automatically recognized, use the command: /uifork add to this application

    3. Fork a component: Prompt the agent: Fork a version of {some component} and make the following changes

  5. Add the UIFork component to your React app

    main

    To enable the versioning UI widget, add the <UIFork /> component to your application root. It is recommended to gate this component so it only appears in development or staging environments, not in production.

    Vite

    import { UIFFork } from "uifork";
    
    const showUIFork = import.meta.env.MODE !== "production";
    
    function App() {
      return (
        <>
          <YourApp />
          {showUIFork && <UIFork />}
        </>
      );
    }

    Next.js (App Router)

    Create a client component provider to wrap your layout:

    // components/UIForkProvider.tsx
    "use client";
    import { UIFork } from "uifork";
    
    export function UIForkProvider() {
      if (process.env.NODE_ENV === "production") return null;
      return <UIFork />;
    }
    
    // app/layout.tsx
    import { UIFForkProvider } from "@/components/UIForkProvider";
    
    export default function RootLayout({ children }) {
      return (
        <html lang="en">
          <body>
            {children}
            <UIForkProvider />
          </body>
        </html>
      );
    }

    Next.js (Pages Router)

    // pages/_app.tsx
    import { UIFork } from "uifork";
    
    export default function App({ Component, pageProps }) {
      return (
        <>
          <Component {...pageProps} />
          {process.env.NODE_ENV !== "production" && <UIFork />}
        </>
      );
    }

    Note: No separate CSS import is required; styles are automatically included.

    import { UIFork } from "uifork";
    
    // Example usage in a component
    <UIFork />
  6. Setup the UIFork Marketing environment

    main

    To set up the local development environment for the marketing app, install the dependencies using npm. You can do this from within the apps/marketing directory or from the repository root.

    From the root directory:

    cd apps/marketing && npm install

    Or directly from the marketing directory:

    cd apps/marketing
    npm install
  7. Test the Built Package (`dev`)

    main

    To simulate how consumers will use the package, test against the built workspace version instead of the raw source. You must build the uifork package before running the marketing app.

    1. Build the uifork package:
      cd ../../packages/uifork && npm run build
    2. Run the marketing app:
      cd ../../apps/marketing && npm run dev
    # Build the uifork package first
    cd ../../packages/uifork && npm run build
    
    # Then run marketing
    cd ../../apps/marketing && npm run dev
  8. Use Local Development with HMR (`dev:local`)

    main

    Use this mode when actively developing the uifork package. It uses a Vite alias to point directly to packages/uifork/src, which enables Hot Module Replacement (HMR). Changes made to the package source will be reflected immediately in the marketing app without a full rebuild.

    npm run dev:local