Skip to content

Work with Vite

This guide covers setting up React Signify with Vite from scratch, including project creation, React configuration, and React Signify integration.

Prerequisites

  • Node.js >= 16.0.0
  • NPM, Yarn, pnpm, or Bun package manager

Project Setup

1. Create New Vite + React Project

Using NPM

bash
# JavaScript
npm create vite@latest my-signify-app -- --template react

# TypeScript (Recommended)
npm create vite@latest my-signify-app -- --template react-ts

cd my-signify-app
npm install

Using Yarn

bash
# JavaScript
yarn create vite my-signify-app --template react

# TypeScript (Recommended)
yarn create vite my-signify-app --template react-ts

cd my-signify-app
yarn install

Using pnpm

bash
# JavaScript
pnpm create vite my-signify-app --template react

# TypeScript (Recommended)
pnpm create vite my-signify-app --template react-ts

cd my-signify-app
pnpm install

Using Bun

bash
# JavaScript
bun create vite my-signify-app --template react

# TypeScript (Recommended)
bun create vite my-signify-app --template react-ts

cd my-signify-app
bun install

2. Install React Signify

bash
# NPM
npm install react-signify

# Yarn
yarn add react-signify

# pnpm
pnpm add react-signify

# Bun
bun add react-signify

Vite Configuration

Basic Configuration

Update your vite.config.ts for optimal React Signify performance:

typescript
import { defineConfig } from "vite";
import react from "@vitejs/plugin-react";

export default defineConfig({
  plugins: [react()],
  optimizeDeps: {
    include: ["react-signify"],
  },
  build: {
    rollupOptions: {
      output: {
        manualChunks: {
          "react-signify": ["react-signify"],
        },
      },
    },
  },
});

Advanced Configuration

For larger applications with optimization:

typescript
import { defineConfig } from "vite";
import react from "@vitejs/plugin-react";

export default defineConfig({
  plugins: [react()],
  optimizeDeps: {
    include: ["react-signify"],
  },
  build: {
    rollupOptions: {
      output: {
        manualChunks: (id) => {
          if (id.includes("react-signify")) {
            return "react-signify";
          }
          if (id.includes("node_modules")) {
            return "vendor";
          }
        },
      },
    },
    chunkSizeWarningLimit: 1000,
  },
  server: {
    port: 3000,
    open: true,
  },
});

TypeScript Configuration

tsconfig.json Setup

If using TypeScript, ensure your tsconfig.json is optimized:

json
{
  "compilerOptions": {
    "target": "ES2020",
    "useDefineForClassFields": true,
    "lib": ["ES2020", "DOM", "DOM.Iterable"],
    "module": "ESNext",
    "skipLibCheck": true,

    /* Bundler mode */
    "moduleResolution": "bundler",
    "allowImportingTsExtensions": true,
    "resolveJsonModule": true,
    "isolatedModules": true,
    "noEmit": true,
    "jsx": "react-jsx",

    /* Linting */
    "strict": true,
    "noUnusedLocals": true,
    "noUnusedParameters": true,
    "noFallthroughCasesInSwitch": true
  },
  "include": ["src"],
  "references": [{ "path": "./tsconfig.node.json" }]
}

Project Structure

Files You'll Create

src/
├── components/
│   ├── Counter.tsx
│   └── CounterButton.tsx
├── store/
│   └── counter.ts
├── App.tsx
├── main.tsx
└── index.css

React Signify Integration

1. Create Store File

Create a store file to manage your counter state:

tsx
// src/store/counter.ts
import { signify } from "react-signify";

export const sCounter = signify(0);

2. Create Main Component (Display with use)

Create the main component that displays the counter value:

tsx
// src/components/Counter.tsx
import React from "react";
import { sCounter } from "../store/counter";
import CounterButton from "./CounterButton";

export default function Counter() {
  const count = sCounter.use(); // Use to display value

  return (
    <div>
      <h2>Counter: {count}</h2>
      <CounterButton />
    </div>
  );
}

3. Create Child Component (Update with set)

Create a child component that updates the counter:

tsx
// src/components/CounterButton.tsx
import React from "react";
import { sCounter } from "../store/counter";

export default function CounterButton() {
  const handleIncrement = () => {
    sCounter.set(prev => {
      prev.value += 1; // Set to update value directly
    });
  };

  return <button onClick={handleIncrement}>+1</button>;
}

4. Update Main App

tsx
// src/App.tsx
import React from "react";
import Counter from "./components/Counter";
import "./App.css";

function App() {
  return (
    <div className="App">
      <h1>Vite + React + React Signify</h1>
      <Counter />
    </div>
  );
}

export default App;

5. Update Main Entry

tsx
// src/main.tsx
import React from "react";
import ReactDOM from "react-dom/client";
import App from "./App.tsx";
import "./index.css";

ReactDOM.createRoot(document.getElementById("root")!).render(
  <React.StrictMode>
    <App />
  </React.StrictMode>
);

Development Tools

ESLint Configuration

Add to your .eslintrc.cjs:

javascript
module.exports = {
  root: true,
  env: { browser: true, es2020: true },
  extends: [
    "eslint:recommended",
    "@typescript-eslint/recommended",
    "plugin:react-hooks/recommended",
  ],
  ignorePatterns: ["dist", ".eslintrc.cjs"],
  parser: "@typescript-eslint/parser",
  plugins: ["react-refresh"],
  rules: {
    "react-refresh/only-export-components": [
      "warn",
      { allowConstantExport: true },
    ],
    "react-hooks/exhaustive-deps": "warn",
    "react-hooks/rules-of-hooks": "error",
    "@typescript-eslint/no-unused-vars": "error",
  },
};

Build and Deployment

Build for Production

bash
# NPM
npm run build

# Yarn
yarn build

# pnpm
pnpm build

# Bun
bun run build

Preview Production Build

bash
# NPM
npm run preview

# Yarn
yarn preview

# pnpm
pnpm preview

# Bun
bun run preview

Deploy to Vercel

bash
# Install Vercel CLI
npm i -g vercel

# Deploy
vercel

Deploy to Netlify

bash
# Build first
npm run build

# Deploy dist folder to Netlify
# Or connect your Git repository to Netlify

Performance Optimization

Bundle Analysis

bash
# Install bundle analyzer
npm install --save-dev rollup-plugin-visualizer

# Add to vite.config.ts
import { visualizer } from 'rollup-plugin-visualizer';

export default defineConfig({
  plugins: [
    react(),
    visualizer({
      filename: 'dist/stats.html',
      open: true,
    }),
  ],
});

Tree Shaking

React Signify supports tree shaking out of the box:

tsx
// ✅ Good - Tree shakable
import { signify } from "react-signify";

// ❌ Avoid - Imports everything
import * as ReactSignify from "react-signify";

Troubleshooting

Common Issues

1. "Cannot resolve module 'react-signify'"

bash
# Clear cache and reinstall
rm -rf node_modules
rm package-lock.json  # or yarn.lock, pnpm-lock.yaml
npm install

2. TypeScript errors

bash
# Ensure React types are installed
npm install --save-dev @types/react @types/react-dom

3. Vite hot reload issues

tsx
// Add to vite.config.ts
export default defineConfig({
  server: {
    hmr: {
      overlay: false,
    },
  },
});

4. Build errors

bash
# Check for TypeScript errors
npx tsc --noEmit

# Clear Vite cache
rm -rf node_modules/.vite

Testing Setup

Vitest Configuration

bash
npm install --save-dev vitest @testing-library/react @testing-library/jest-dom
typescript
// vite.config.ts
import { defineConfig } from "vite";
import react from "@vitejs/plugin-react";

export default defineConfig({
  plugins: [react()],
  test: {
    globals: true,
    environment: "jsdom",
    setupFiles: ["./src/test/setup.ts"],
  },
});
typescript
// src/test/setup.ts
import "@testing-library/jest-dom";

Example Test

tsx
// src/components/__tests__/Counter.test.tsx
import { render, screen, fireEvent } from "@testing-library/react";
import { describe, it, expect, beforeEach } from "vitest";
import Counter from "../Counter";
import { sCounter } from "../../store/counter";

describe("Counter", () => {
  beforeEach(() => {
    sCounter.reset();
  });

  it("renders counter with initial value", () => {
    render(<Counter />);
    expect(screen.getByText("Counter: 0")).toBeInTheDocument();
  });

  it("increments counter when + button is clicked", () => {
    render(<Counter />);
    const incrementButton = screen.getByText("+");
    fireEvent.click(incrementButton);
    expect(screen.getByText("Counter: 1")).toBeInTheDocument();
  });
});

Next Steps

After successful setup:

  1. 📖 Understanding Signify - Learn core concepts
  2. 🚀 Quick Start Guide - Build more examples
  3. 🏗️ Project Structure - Advanced organization
  4. 🎯 TypeScript Guide - Advanced TypeScript usage
  5. 📚 API Reference - Complete API guide

Having issues with Vite + React Signify? Create an issue on GitHub or check our discussions.

Released under the MIT License.