0.1.163 • Published 3 months ago

react-edge v0.1.163

Weekly downloads
-
License
MIT
Repository
github
Last release
3 months ago

React Edge Framework 🚀

A revolutionary React framework for building blazing-fast applications on the edge, powered by Cloudflare Workers

TypeScript Vitest MIT License

🚀 Motivation

Read the full story on DEV.to

🌟 Features

  • Powerful Data Fetching & RPC: Write server-side methods and use them with an incredibly flexible fetching system:
// Define your types
type User = {
  id: string;
  name: string;
  preferences: {
    theme: 'light' | 'dark';
    notifications: boolean;
  };
};

type Product = {
  id: string;
  name: string;
  price: number;
  category: string;
};

// Server: Your API methods
class API extends Rpc {
  async getUser(id: string): Promise<User> {
    return this.db.users.findById(id);
  }

  async getProducts(category: string): Promise<Product[]> {
    return this.db.products.findByCategory(category);
  }

  async searchProducts(query: string): Promise<Product[]> {
    return this.db.products.search(query);
  }
}

// Client: Unleash the power of useFetch!
const Dashboard = () => {
  const { rpc } = app.useContext<App.Context>();
  const [searchQuery, setSearchQuery] = useState('');
  const [selectedCategory, setSelectedCategory] = useState('all');

  // 🚀 Basic fetch with automatic SSR and hydration
  const { data: user } = app.useFetch(async (ctx, id) => {
	return ctx.rpc.getUser(id ?? '123');
  });

  // 🚀 Reactive fetch with dependencies
  const { data: products, loading, error, fetch: refreshProducts } = app.useFetch(
    async ctx => ctx.rpc.getProducts(selectedCategory),
    {
      // Refetch when category changes
      deps: [selectedCategory]
    }
  );

  // 🚀 Debounced search with automatic error handling
  const { data: searchResults } = app.useFetch(
    async ctx => ctx.rpc.searchProducts(searchQuery),
    {
      // Only fetch if we have a query
      shouldFetch: () => searchQuery.length > 2,
	  deps: [searchQuery],
      // Debounce the API calls
      depsDebounce: 300
    }
  );

  // 🚀 Parallel fetching with batch
  const { data: dashboardData } = app.useFetch(
    async ctx => {
      const [
        userProfile,
        recentProducts,
        recommendations
      ] = await ctx.rpc.batch([
        ctx.rpc.getUser('123'),
        ctx.rpc.getProducts('recent'),
        ctx.rpc.searchProducts('recommended')
      ]);

      return {
        profile: userProfile,
        recent: recentProducts,
        recommended: recommendations
      };
    },
    {
      // Automatic polling every 30 seconds
      interval: 30000
    }
  );

  return (
    <div>
      {/* All your data is fully typed! */}
      <UserProfile user={user} />

      <ProductGrid
        products={products}
        loading={loading}
        onRefresh={refreshProducts}
      />

      <SearchResults results={searchResults} />

      <DashboardWidgets data={dashboardData} />
    </div>
  );
};

🎯 useFetch Features:

  • Seamless SSR & Hydration: Data is preloaded during SSR and hydrated on the client automatically
  • Dependency-based Refetching: Reactive updates when dependencies change
  • Smart Debouncing: Control the frequency of API calls with depsDebounce
  • Intelligent Batching: Multiple RPC calls are automatically combined into a single request
  • Simple Polling: Easy periodic data updates with interval
  • Type Safety: Full TypeScript support with zero manual type declarations
  • Conditional Fetching: Control when fetching should occur with shouldFetch
  • Manual Controls: Programmatic refresh capabilities with fetch function
  • Performance Optimized: Automatic request deduplication and caching

📦 Installation

npm install react-edge

🚀 Quick Start

1. Set up your Worker

// worker.ts
const handler = {
	fetch: async (req: Request, env: types.Worker.Env, context: ExecutionContext) => {
		const workerApp = new AppWorkerEntry({
			i18n: {
				en: await import('./translations/en'),
				es: await import('./translations/es')
			}
		});

		return await workerApp.fetch();
	}
};

2. Create your first RPC endpoint

class UserAPI extends Rpc {
	async getProfile(id: string) {
		const user = await this.db.users.findById(id);

		return this.createResponse(user, {
			cache: {
				tags: [`user:${id}`],
				ttlSeconds: 300 // Cache for 5 minutes
			}
		});
	}
}

3. Use it in your components

const UserProfile = () => {
  const { rpc } = app.useContext<App.Context>();

  const { data: profile, loading } = app.useFetch(
    async ctx => ctx.rpc.getProfile('123')
  );

  if (loading) return <Loading />;

  return <div>Welcome, {profile.name}!</div>;
};

🛠 Core Features

Typed RPC System

The RPC system enables seamless client-server communication with full TypeScript support:

class ProductsAPI extends Rpc {
	// Private methods (not exposed to client)
	private async _validateProduct(data: ProductData) {
		// or $validateProduct , or #validateProduct
		return productSchema.parse(data);
	}

	// Public methods (accessible via RPC)
	async createProduct(data: ProductData) {
		const validated = await this._validateProduct(data);
		return this.db.products.create(validated);
	}
}

Smart Caching

Built-in caching system with tag-based invalidation:

class CacheExample extends Rpc {
	async getProducts(category: string) {
		const products = await this.db.products.findByCategory(category);

		return this.createResponse(products, {
			cache: {
				tags: [`category:${category}`, 'products'],
				ttlSeconds: 3600 // 1 hour
			}
		});
	}

	async updateProduct(id: string, data: ProductData) {
		await this.db.products.update(id, data);

		// Invalidate specific caches
		await this.cache.deleteBy({
			tags: [`product:${id}`, `category:${data.category}`]
		});
	}
}

Authentication

Simple JWT authentication with secure cookie management:

class AuthAPI extends Rpc {
	private auth = new AuthJwt({
		cookie: 'token',
		encrypt: true,
		expires: { days: 1 },
		secret: process.env.JWT_SECRET
	});

	async login(credentials: LoginData) {
		const { headers } = await this.auth.sign(credentials);
		return this.createResponse({ success: true }, { headers });
	}
}

State Management

URL-Synced State

const FiltersComponent = () => {
  const [filters, setFilters] = app.useUrlState({
    category: 'all',
    minPrice: 0,
    maxPrice: 1000
  }, {
    debounce: 500,
    kebabCase: true
  });

  return <FilterPanel value={filters} onChange={setFilters} />;
};

Persistent State

const UserPreferences = () => {
  const [prefs, setPrefs] = app.useStorageState('user-prefs', {
    theme: 'light',
    fontSize: 16
  }, {
    storage: 'local',
    debounce: 300
  });

  return <PreferencesPanel value={prefs} onChange={setPrefs} />;
};

🛠 CLI Commands

React Edge comes with a powerful CLI for development and deployment:

Development

# Start development server
yarn edge dev

# Start development server for app only
yarn edge dev --app

# Start development server for worker only
yarn edge dev --worker

Build

# Build entire project
yarn edge build

# Build for specific environment
yarn edge build --env production

# Build app or worker separately
yarn edge build --app
yarn edge build --worker

Other Commands

# Deploy to Cloudflare Workers
yarn edge deploy

# View worker logs
yarn edge logs

# Run linting
yarn edge lint

# Run tests
yarn edge test

# Type checking
yarn edge type-check

🌍 Internationalization

Easy i18n support with variable interpolation:

// translations/fr.ts
export default {
  'Welcome, {name}!': 'Bienvenue, {name}!'
};

// Component
const Welcome = () => (
  <h1>{__('Welcome, {name}!', { name: 'John' })}</h1>
);

📚 Best Practices

  1. RPC Organization

    • Keep related functionality in dedicated RPC classes
    • Use private methods for internal logic
    • Leverage caching for frequently accessed data
  2. State Management

    • Use useUrlState for shareable state
    • Use useStorageState for persistent preferences
    • Use useDistinct to optimize updates
  3. Performance

    • Implement appropriate cache strategies
    • Use Link component for preloading
    • Leverage edge caching when possible

📝 License

MIT © Felipe Rohde

👨‍💻 Author

Felipe Rohde

0.1.52

7 months ago

0.1.53

7 months ago

0.1.54

7 months ago

0.1.55

7 months ago

0.1.56

7 months ago

0.1.57

7 months ago

0.1.58

7 months ago

0.1.59

7 months ago

0.1.50

7 months ago

0.1.51

7 months ago

0.1.118

4 months ago

0.1.117

4 months ago

0.1.119

4 months ago

0.1.114

4 months ago

0.1.113

4 months ago

0.1.116

4 months ago

0.1.115

4 months ago

0.1.110

4 months ago

0.1.49

7 months ago

0.1.112

4 months ago

0.1.111

4 months ago

0.1.41

7 months ago

0.1.42

7 months ago

0.1.43

7 months ago

0.1.44

7 months ago

0.1.45

7 months ago

0.1.46

7 months ago

0.1.47

7 months ago

0.1.48

7 months ago

0.1.40

7 months ago

0.1.129

4 months ago

0.1.128

4 months ago

0.1.125

4 months ago

0.1.124

4 months ago

0.1.127

4 months ago

0.1.126

4 months ago

0.1.121

4 months ago

0.1.38

8 months ago

0.1.120

4 months ago

0.1.39

8 months ago

0.1.123

4 months ago

0.1.122

4 months ago

0.1.30

8 months ago

0.1.31

8 months ago

0.1.32

8 months ago

0.1.33

8 months ago

0.1.34

8 months ago

0.1.35

8 months ago

0.1.36

8 months ago

0.1.37

8 months ago

0.1.139

4 months ago

0.1.136

4 months ago

0.1.135

4 months ago

0.1.138

4 months ago

0.1.137

4 months ago

0.1.132

4 months ago

0.1.27

8 months ago

0.1.131

4 months ago

0.1.28

8 months ago

0.1.134

4 months ago

0.1.29

8 months ago

0.1.133

4 months ago

0.1.130

4 months ago

0.1.20

8 months ago

0.1.21

8 months ago

0.1.22

8 months ago

0.1.23

8 months ago

0.1.24

8 months ago

0.1.25

8 months ago

0.1.26

8 months ago

0.1.147

3 months ago

0.1.146

4 months ago

0.1.149

3 months ago

0.1.148

3 months ago

0.1.143

4 months ago

0.1.142

4 months ago

0.1.145

4 months ago

0.1.144

4 months ago

0.1.141

4 months ago

0.1.140

4 months ago

0.1.99

4 months ago

0.1.90

4 months ago

0.1.91

4 months ago

0.1.92

4 months ago

0.1.93

4 months ago

0.1.94

4 months ago

0.1.95

4 months ago

0.1.158

3 months ago

0.1.157

3 months ago

0.1.159

3 months ago

0.1.154

3 months ago

0.1.153

3 months ago

0.1.156

3 months ago

0.1.155

3 months ago

0.1.150

3 months ago

0.1.152

3 months ago

0.1.151

3 months ago

0.1.85

5 months ago

0.1.86

5 months ago

0.1.87

4 months ago

0.1.88

4 months ago

0.1.89

4 months ago

0.1.80

5 months ago

0.1.81

5 months ago

0.1.82

5 months ago

0.1.83

5 months ago

0.1.84

5 months ago

0.1.161

3 months ago

0.1.160

3 months ago

0.1.163

3 months ago

0.1.162

3 months ago

0.1.74

5 months ago

0.1.75

5 months ago

0.1.76

5 months ago

0.1.77

5 months ago

0.1.78

5 months ago

0.1.79

5 months ago

0.1.70

6 months ago

0.1.71

6 months ago

0.1.72

6 months ago

0.1.73

5 months ago

0.1.63

7 months ago

0.1.64

7 months ago

0.1.65

7 months ago

0.1.66

7 months ago

0.1.67

7 months ago

0.1.68

7 months ago

0.1.69

6 months ago

0.1.60

7 months ago

0.1.61

7 months ago

0.1.62

7 months ago

0.1.107

4 months ago

0.1.106

4 months ago

0.1.109

4 months ago

0.1.108

4 months ago

0.1.103

4 months ago

0.1.102

4 months ago

0.1.105

4 months ago

0.1.104

4 months ago

0.1.101

4 months ago

0.1.100

4 months ago

0.1.19

8 months ago

0.1.18

8 months ago

0.1.17

9 months ago

0.1.16

9 months ago

0.1.15

9 months ago

0.1.14

9 months ago

0.1.13

9 months ago

0.1.12

9 months ago

0.1.11

9 months ago

0.1.10

9 months ago

0.1.9

9 months ago

0.1.7

9 months ago

0.1.6

9 months ago

0.1.5

9 months ago

0.1.4

9 months ago

0.1.3

9 months ago

0.1.2

9 months ago

0.1.1

9 months ago

0.1.0

3 years ago

0.0.5

3 years ago

0.0.4

3 years ago

0.0.3

3 years ago

0.0.2

3 years ago

0.0.1

3 years ago

0.0.0

3 years ago