šŸš€ Big News: Socket Acquires Coana to Bring Reachability Analysis to Every Appsec Team.Learn more →
Socket
Sign inDemoInstall
Socket

frontend-hamroun

Package Overview
Dependencies
Maintainers
1
Versions
153
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

frontend-hamroun

A lightweight full-stack JavaScript framework

1.2.67
latest
npm
Version published
Weekly downloads
1.3K
35.88%
Maintainers
1
Weekly downloads
Ā 
Created
Source

Frontend Hamroun

Frontend Hamroun Logo

A lightweight full-stack JavaScript framework with Virtual DOM and hooks implementation

npm npm bundle size npm GitHub license

šŸ“‹ Table of Contents

šŸš€ Introduction

Frontend Hamroun is a lightweight (~5KB gzipped) JavaScript framework designed for building modern web applications. It combines React-like frontend development with powerful backend capabilities in a single, unified package.

Key Features

  • Efficient Virtual DOM: Minimizes DOM operations with intelligent diffing
  • Complete Hooks API: useState, useEffect, useRef, useMemo, and more
  • Full-Stack Solution: Unified frontend and backend development
  • Server-Side Rendering: Optimized SSR with hydration
  • File-Based Routing: Intuitive API endpoint creation
  • Database Integration: Built-in support for MongoDB, MySQL, PostgreSQL
  • TypeScript Support: Full type definitions and excellent DX
  • Automatic Batch Updates: Efficient state management
  • CLI Tooling: Scaffolding for components, pages, and API routes

šŸ“¦ Installation

# Using npm
npm install frontend-hamroun

# Using yarn
yarn add frontend-hamroun

# Using pnpm
pnpm add frontend-hamroun

šŸ Quick Start

Method 1: Create a new project with CLI
# Using npx
npx create-frontend-app my-app

# Or with the frontend-hamroun CLI
npx frontend-hamroun create my-app

Then:

cd my-app
npm install
npm run dev

This will scaffold a new project with all the necessary configuration.

Method 2: Add to an existing project
# Install the package
npm install frontend-hamroun

# Import and use in your code
import { render, useState } from 'frontend-hamroun';
// Create a simple app
import { render, useState } from 'frontend-hamroun';

function Counter() {
  const [count, setCount] = useState(0);
  
  return (
    <div>
      <h1>Count: {count}</h1>
      <button onClick={() => setCount(count + 1)}>
        Increment
      </button>
    </div>
  );
}

render(<Counter />, document.getElementById('root'));

🧠 Core Concepts

Virtual DOM

Frontend Hamroun uses a lightweight Virtual DOM implementation to efficiently update the real DOM. It only applies the minimal necessary changes by:

// Virtual DOM diffing occurs automatically
function App() {
  const [count, setCount] = useState(0);
  return (
    <div>
      <h1>Counter</h1>
      <p>Count: {count}</p> {/* Only this text node updates */}
      <button onClick={() => setCount(count + 1)}>Increment</button>
    </div>
  );
}

Component Model

Components are the building blocks of your UI. Each component encapsulates its own logic and rendering:

// Function components with hooks
function Greeting({ name }) {
  // State management
  const [clicked, setClicked] = useState(false);
  
  // Side effects
  useEffect(() => {
    document.title = `Hello, ${name}`;
    return () => { document.title = 'App'; };
  }, [name]);
  
  return (
    <div>
      <h1>{clicked ? `Thanks, ${name}!` : `Hello, ${name}!`}</h1>
      <button onClick={() => setClicked(true)}>
        {clicked ? 'Clicked!' : 'Click me'}
      </button>
    </div>
  );
}

šŸŽØ Frontend Features

Hooks System

State Management with useState
import { useState } from 'frontend-hamroun';

function Counter() {
  const [count, setCount] = useState(0);
  
  function increment() {
    setCount(count + 1);
  }
  
  function decrement() {
    setCount(count - 1);
  }
  
  // Functional updates for derived state
  function double() {
    setCount(prevCount => prevCount * 2);
  }
  
  return (
    <div>
      <h2>Count: {count}</h2>
      <button onClick={increment}>+</button>
      <button onClick={decrement}>-</button>
      <button onClick={double}>Ɨ2</button>
    </div>
  );
}
Side Effects with useEffect
import { useState, useEffect } from 'frontend-hamroun';

function UserProfile({ userId }) {
  const [user, setUser] = useState(null);
  const [loading, setLoading] = useState(true);
  
  useEffect(() => {
    // Reset state when userId changes
    setLoading(true);
    
    // Fetch user data
    fetch(`/api/users/${userId}`)
      .then(res => res.json())
      .then(data => {
        setUser(data);
        setLoading(false);
      })
      .catch(err => {
        console.error(err);
        setLoading(false);
      });
    
    // Cleanup function runs on component unmount or before effect re-runs
    return () => {
      // Cancel any pending requests or subscriptions
      console.log('Cleaning up effect for userId:', userId);
    };
  }, [userId]); // Only re-run when userId changes
  
  if (loading) return <div>Loading...</div>;
  if (!user) return <div>User not found</div>;
  
  return (
    <div>
      <h1>{user.name}</h1>
      <p>Email: {user.email}</p>
    </div>
  );
}
Performance Optimization with useMemo and useRef
import { useState, useMemo, useRef } from 'frontend-hamroun';

function ExpensiveCalculation({ items, filter }) {
  const [selectedId, setSelectedId] = useState(null);
  
  // Cache expensive calculation results, only recalculate when dependencies change
  const filteredItems = useMemo(() => {
    console.log('Filtering items...');
    return items.filter(item => item.name.includes(filter));
  }, [items, filter]);
  
  // Create a persistent reference that doesn't trigger re-renders
  const lastRenderTime = useRef(Date.now());
  
  console.log(`Time since last render: ${Date.now() - lastRenderTime.current}ms`);
  lastRenderTime.current = Date.now();
  
  // DOM element references
  const listRef = useRef(null);
  
  function scrollToTop() {
    listRef.current.scrollTop = 0;
  }
  
  return (
    <div>
      <button onClick={scrollToTop}>Scroll to top</button>
      <div ref={listRef} style={{ height: '200px', overflow: 'auto' }}>
        {filteredItems.map(item => (
          <div 
            key={item.id}
            onClick={() => setSelectedId(item.id)}
            style={{ 
              background: item.id === selectedId ? 'lightblue' : 'white'
            }}
          >
            {item.name}
          </div>
        ))}
      </div>
    </div>
  );
}
Context API for State Management
import { createContext, useContext, useState } from 'frontend-hamroun';

// Create a context with default value
const ThemeContext = createContext('light');

// Provider component to supply context value
function ThemeProvider({ children }) {
  const [theme, setTheme] = useState('light');
  
  const toggleTheme = () => {
    setTheme(theme === 'light' ? 'dark' : 'light');
  };
  
  return (
    <ThemeContext.Provider value={{ theme, toggleTheme }}>
      {children}
    </ThemeContext.Provider>
  );
}

// Consumer component using the context value
function ThemedButton() {
  const { theme, toggleTheme } = useContext(ThemeContext);
  
  return (
    <button 
      onClick={toggleTheme}
      style={{ 
        background: theme === 'light' ? '#fff' : '#333',
        color: theme === 'light' ? '#333' : '#fff',
        border: '1px solid #ccc',
        padding: '8px 16px',
      }}
    >
      Switch to {theme === 'light' ? 'dark' : 'light'} mode
    </button>
  );
}

// Usage in application
function App() {
  return (
    <ThemeProvider>
      <div>
        <h1>Themed Application</h1>
        <ThemedButton />
      </div>
    </ThemeProvider>
  );
}
Error Boundaries with useErrorBoundary
import { useErrorBoundary } from 'frontend-hamroun';

function ErrorBoundary({ children }) {
  const [error, resetError] = useErrorBoundary();
  
  if (error) {
    return (
      <div className="error-boundary">
        <h2>Something went wrong</h2>
        <p>{error.message}</p>
        <button onClick={resetError}>Try again</button>
      </div>
    );
  }
  
  return children;
}

// Usage
function App() {
  return (
    <ErrorBoundary>
      <UserProfile userId="123" />
    </ErrorBoundary>
  );
}

Batch Updates for Efficiency

Frontend Hamroun automatically batches state updates within event handlers and can manually batch other updates with batchUpdates:

import { useState, batchUpdates } from 'frontend-hamroun';

function Form() {
  const [name, setName] = useState('');
  const [email, setEmail] = useState('');
  const [isSubmitting, setSubmitting] = useState(false);
  const [errors, setErrors] = useState({});
  
  async function handleSubmit(e) {
    e.preventDefault();
    
    // Group multiple state updates into a single render
    batchUpdates(() => {
      setSubmitting(true);
      setErrors({});
    });
    
    try {
      const response = await fetch('/api/users', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ name, email })
      });
      
      const result = await response.json();
      
      batchUpdates(() => {
        setSubmitting(false);
        setName('');
        setEmail('');
      });
    } catch (error) {
      batchUpdates(() => {
        setSubmitting(false);
        setErrors({ submit: error.message });
      });
    }
  }
  
  return (
    <form onSubmit={handleSubmit}>
      {/* Form fields */}
      <button type="submit" disabled={isSubmitting}>
        {isSubmitting ? 'Submitting...' : 'Submit'}
      </button>
    </form>
  );
}

šŸ–„ļø Backend Features

Express Server Integration

Server Setup
import { server } from 'frontend-hamroun/server';

const app = await server.createServer({
  port: 3000,
  apiDir: './api',        // Directory for API routes
  pagesDir: './pages',    // Directory for page components
  staticDir: './public',  // Directory for static files
  
  // Database configuration
  db: {
    url: process.env.DATABASE_URL,
    type: 'mongodb'       // mongodb, mysql, or postgres
  },
  
  // Authentication configuration
  auth: {
    secret: process.env.JWT_SECRET,
    expiresIn: '7d'       // Token expiration time
  }
});

await app.start();
console.log('Server running at http://localhost:3000');

File-Based API Routing

API Routes
// api/users.js (automatically maps to /api/users)
export async function get(req, res) {
  // GET /api/users - List all users
  const users = await req.db.collection('users').find().toArray();
  res.json(users);
}

export async function post(req, res) {
  // POST /api/users - Create a new user
  const { name, email } = req.body;
  
  if (!name || !email) {
    return res.status(400).json({ error: 'Name and email are required' });
  }
  
  const result = await req.db.collection('users').insertOne({
    name,
    email,
    createdAt: new Date()
  });
  
  res.status(201).json({ id: result.insertedId });
}
// api/users/[id].js (automatically maps to /api/users/:id)
export async function get(req, res) {
  // GET /api/users/:id - Get user by ID
  const { id } = req.params;
  
  try {
    const user = await req.db.collection('users').findOne({
      _id: new ObjectId(id)
    });
    
    if (!user) {
      return res.status(404).json({ error: 'User not found' });
    }
    
    res.json(user);
  } catch (error) {
    res.status(500).json({ error: 'Server error' });
  }
}

export async function put(req, res) {
  // PUT /api/users/:id - Update user
  const { id } = req.params;
  const { name, email } = req.body;
  
  await req.db.collection('users').updateOne(
    { _id: new ObjectId(id) },
    { $set: { name, email, updatedAt: new Date() } }
  );
  
  res.json({ success: true });
}

export async function del(req, res) {
  // DELETE /api/users/:id - Delete user
  // Note: 'delete' is a reserved word, so we use 'del'
  const { id } = req.params;
  
  await req.db.collection('users').deleteOne({
    _id: new ObjectId(id)
  });
  
  res.status(204).end();
}

Database Integration

MongoDB Example
// api/posts.js
export async function get(req, res) {
  // Complex MongoDB aggregation
  const posts = await req.db.collection('posts')
    .aggregate([
      { $match: { published: true } },
      { $sort: { createdAt: -1 } },
      { $limit: 10 },
      { $lookup: {
        from: 'users',
        localField: 'authorId',
        foreignField: '_id',
        as: 'author'
      }},
      { $unwind: '$author' },
      { $project: {
        title: 1,
        content: 1,
        createdAt: 1,
        'author.name': 1,
        'author.email': 1
      }}
    ])
    .toArray();
  
  res.json(posts);
}
MySQL Example
// api/products.js
export async function get(req, res) {
  // Complex SQL query with joins
  const [products] = await req.db.execute(`
    SELECT 
      p.id, 
      p.name, 
      p.price, 
      c.name as categoryName
    FROM 
      products p
    JOIN 
      categories c ON p.category_id = c.id
    WHERE 
      p.active = ?
    ORDER BY 
      p.created_at DESC
    LIMIT 20
  `, [true]);
  
  res.json(products);
}
PostgreSQL Example
// api/analytics.js
export async function get(req, res) {
  // Advanced PostgreSQL features
  const result = await req.db.query(`
    WITH monthly_sales AS (
      SELECT
        date_trunc('month', order_date) as month,
        SUM(total_amount) as revenue
      FROM
        orders
      WHERE
        order_date > NOW() - INTERVAL '1 year'
      GROUP BY
        date_trunc('month', order_date)
    )
    SELECT 
      month,
      revenue,
      lag(revenue) OVER (ORDER BY month) as prev_month_revenue,
      round((revenue - lag(revenue) OVER (ORDER BY month)) / 
        lag(revenue) OVER (ORDER BY month) * 100, 2) as growth_percent
    FROM
      monthly_sales
    ORDER BY
      month
  `);
  
  res.json(result.rows);
}

Authentication System

JWT Authentication
// api/auth/login.js
export async function post(req, res) {
  const { email, password } = req.body;
  
  // Validate input
  if (!email || !password) {
    return res.status(400).json({ error: 'Email and password are required' });
  }
  
  try {
    // Find user by email
    const user = await req.db.collection('users').findOne({ email });
    
    // Check if user exists and password is correct
    if (!user || !await req.auth.comparePasswords(password, user.password)) {
      return res.status(401).json({ error: 'Invalid credentials' });
    }
    
    // Generate JWT token
    const token = req.auth.generateToken({
      id: user._id,
      name: user.name,
      email: user.email,
      roles: user.roles || ['user']
    });
    
    // Return token and user info (excluding sensitive data)
    res.json({
      token,
      user: {
        id: user._id,
        name: user.name,
        email: user.email,
        roles: user.roles || ['user']
      }
    });
  } catch (error) {
    res.status(500).json({ error: 'Authentication failed' });
  }
}
// api/auth/register.js
export async function post(req, res) {
  const { name, email, password } = req.body;
  
  // Validate input
  if (!name || !email || !password) {
    return res.status(400).json({ 
      error: 'Name, email, and password are required' 
    });
  }
  
  try {
    // Check if user already exists
    const existingUser = await req.db.collection('users').findOne({ email });
    if (existingUser) {
      return res.status(409).json({ error: 'Email already in use' });
    }
    
    // Hash password
    const hashedPassword = await req.auth.hashPassword(password);
    
    // Create user
    const result = await req.db.collection('users').insertOne({
      name,
      email,
      password: hashedPassword,
      roles: ['user'],
      createdAt: new Date()
    });
    
    res.status(201).json({ 
      id: result.insertedId,
      name,
      email,
      roles: ['user']
    });
  } catch (error) {
    res.status(500).json({ error: 'Registration failed' });
  }
}
// middleware/requireAuth.js - Protected route middleware
export default function requireAuth(req, res, next) {
  const token = req.headers.authorization?.split(' ')[1];
  
  if (!token) {
    return res.status(401).json({ error: 'Authentication required' });
  }
  
  try {
    // Verify token
    const decoded = req.auth.verifyToken(token);
    req.user = decoded; // Attach user to request
    next();
  } catch (error) {
    return res.status(401).json({ error: 'Invalid or expired token' });
  }
}

// api/profile.js - Protected route example
import requireAuth from '../middleware/requireAuth.js';

export const middleware = [requireAuth];

export async function get(req, res) {
  // req.user is available from requireAuth middleware
  const { id } = req.user;
  
  const profile = await req.db.collection('users').findOne(
    { _id: new ObjectId(id) },
    { projection: { password: 0 } } // Exclude password
  );
  
  res.json(profile);
}

šŸ”„ Server-Side Rendering

Frontend Hamroun provides built-in server-side rendering capabilities to improve performance and SEO:

Server-Side Rendering Setup
// server.js
import express from 'express';
import { renderToString } from 'frontend-hamroun/ssr';
import App from './App';

const app = express();
app.use(express.static('public'));

app.get('*', async (req, res) => {
  // Render app to string
  const html = await renderToString(<App url={req.url} />);
  
  // Send complete HTML document
  res.send(`
    <!DOCTYPE html>
    <html>
      <head>
        <title>My SSR App</title>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <link rel="stylesheet" href="/styles.css">
      </head>
      <body>
        <div id="root">${html}</div>
        <script src="/bundle.js"></script>
      </body>
    </html>
  `);
});

app.listen(3000, () => {
  console.log('Server running at http://localhost:3000');
});

// client.js (for hydration)
import { hydrate } from 'frontend-hamroun';
import App from './App';

// Hydrate the app in the browser
hydrate(<App url={window.location.pathname} />, document.getElementById('root'));

šŸ› ļø CLI Tools

Frontend Hamroun includes a powerful CLI for scaffolding projects, components, and API routes:

Project Creation
# Create a new project with interactive prompts
npx frontend-hamroun create my-app

# Create with specific template
npx frontend-hamroun create my-app --template fullstack-app

Available templates:

  • basic-app: Minimal client-side setup
  • ssr-template: Server-side rendering with hydration
  • fullstack-app: Complete solution with frontend, backend, auth, and DB
Component Generation
# Generate a new component
npx frontend-hamroun add:component Button

# Generate a TypeScript component
npx frontend-hamroun add:component UserProfile --typescript

# Specify path and hooks
npx frontend-hamroun add:component Sidebar --path=src/layout --hooks=useState,useEffect
API Route Generation
# Generate API route
npx frontend-hamroun add:api products

# Specify HTTP methods and auth requirement
npx frontend-hamroun add:api orders --methods=get,post --auth

🧩 Advanced Usage

Custom Hooks
import { useState, useEffect } from 'frontend-hamroun';

// Custom hook for fetching data
function useFetch(url, options = {}) {
  const [data, setData] = useState(null);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState(null);
  
  useEffect(() => {
    setLoading(true);
    setError(null);
    
    fetch(url, options)
      .then(response => {
        if (!response.ok) {
          throw new Error(`HTTP error ${response.status}`);
        }
        return response.json();
      })
      .then(json => {
        setData(json);
        setLoading(false);
      })
      .catch(err => {
        setError(err.message);
        setLoading(false);
      });
  }, [url]);
  
  return { data, loading, error };
}

// Usage
function UserList() {
  const { data, loading, error } = useFetch('/api/users');
  
  if (loading) return <div>Loading...</div>;
  if (error) return <div>Error: {error}</div>;
  
  return (
    <ul>
      {data.map(user => (
        <li key={user.id}>{user.name}</li>
      ))}
    </ul>
  );
}
Performance Optimization Techniques
import { useMemo, useState, useRef, batchUpdates } from 'frontend-hamroun';

function OptimizedList({ items }) {
  const [filter, setFilter] = useState('');
  const [sortOrder, setSortOrder] = useState('asc');
  const prevItems = useRef(items);
  
  // Memoize expensive calculations
  const processedItems = useMemo(() => {
    console.log('Processing items...');
    let result = [...items];
    
    // Apply filter
    if (filter) {
      result = result.filter(item => 
        item.name.toLowerCase().includes(filter.toLowerCase())
      );
    }
    
    // Apply sorting
    result.sort((a, b) => {
      const comparison = a.name.localeCompare(b.name);
      return sortOrder === 'asc' ? comparison : -comparison;
    });
    
    return result;
  }, [items, filter, sortOrder]);
  
  // Check for changed items with more control than dependency arrays
  if (items !== prevItems.current) {
    console.log('Items array reference changed');
    prevItems.current = items;
  }
  
  // Batch multiple state updates together
  const toggleSortAndClear = () => {
    batchUpdates(() => {
      setSortOrder(sortOrder === 'asc' ? 'desc' : 'asc');
      setFilter('');
    });
  };
  
  return (
    <div>
      <div>
        <input 
          type="text"
          value={filter}
          onChange={e => setFilter(e.target.value)}
          placeholder="Filter items..."
        />
        <button onClick={toggleSortAndClear}>
          Toggle Sort ({sortOrder})
        </button>
      </div>
      
      {/* Using key for efficient list rendering */}
      <ul>
        {processedItems.map(item => (
          <li key={item.id}>{item.name}</li>
        ))}
      </ul>
    </div>
  );
}

šŸ“ TypeScript Support

Frontend Hamroun is built with TypeScript and comes with complete type definitions:

Type-Safe Component Example
import { useState, useEffect } from 'frontend-hamroun';

// Define props interface
interface UserProfileProps {
  id: number;
  name: string;
  email: string;
  role: 'admin' | 'user' | 'guest';
  onStatusChange?: (id: number, active: boolean) => void;
}

// Define state interface
interface UserProfileState {
  isActive: boolean;
  isEditing: boolean;
  formData: {
    name: string;
    email: string;
  };
}

function UserProfile({ 
  id, 
  name, 
  email, 
  role, 
  onStatusChange 
}: UserProfileProps) {
  // Type-safe state
  const [state, setState] = useState<UserProfileState>({
    isActive: true,
    isEditing: false,
    formData: {
      name,
      email
    }
  });
  
  // Type-safe event handlers
  const toggleStatus = (): void => {
    const newStatus = !state.isActive;
    setState(prev => ({
      ...prev,
      isActive: newStatus
    }));
    
    if (onStatusChange) {
      onStatusChange(id, newStatus);
    }
  };
  
  // Type-safe refs
  const formRef = useRef<HTMLFormElement>(null);
  
  return (
    <div className="user-profile">
      <h2>{name}</h2>
      <p>Email: {email}</p>
      <p>Role: {role}</p>
      <p>Status: {state.isActive ? 'Active' : 'Inactive'}</p>
      
      <button onClick={toggleStatus}>
        {state.isActive ? 'Deactivate' : 'Activate'}
      </button>
      
      {state.isEditing ? (
        <form ref={formRef}>
          {/* Form fields */}
        </form>
      ) : (
        <button onClick={() => setState(prev => ({ 
          ...prev, 
          isEditing: true 
        }))}>
          Edit
        </button>
      )}
    </div>
  );
}

// Usage with type checking
const App = () => (
  <div>
    <UserProfile
      id={1}
      name="John Doe"
      email="john@example.com"
      role="admin"
      onStatusChange={(id, active) => {
        console.log(`User ${id} status changed to ${active}`);
      }}
    />
    
    {/* This would cause TypeScript errors */}
    {/* 
    <UserProfile 
      id="1"          // Error: string is not assignable to number
      name="Jane Doe" 
      role="manager"  // Error: 'manager' is not assignable
    /> 
    */}
  </div>
);
Type-Safe API Routes
// types.ts
export interface User {
  id?: string;
  name: string;
  email: string;
  password?: string;
  role: 'admin' | 'user';
  createdAt?: Date;
  updatedAt?: Date;
}

// api/users/[id].ts
import type { User } from '../../types';

export async function get(req, res) {
  const { id } = req.params;
  
  try {
    const user = await req.db.collection('users').findOne({ 
      _id: new ObjectId(id) 
    }) as User;
    
    if (!user) {
      return res.status(404).json({ error: 'User not found' });
    }
    
    // Omit sensitive data
    const { password, ...safeUser } = user;
    
    res.json(safeUser);
  } catch (error) {
    res.status(500).json({ error: 'Server error' });
  }
}

export async function put(req, res) {
  const { id } = req.params;
  const { name, email, role } = req.body as Partial<User>;
  
  // Validate that role is a valid enum value
  if (role && !['admin', 'user'].includes(role)) {
    return res.status(400).json({ error: 'Invalid role' });
  }
  
  try {
    await req.db.collection('users').updateOne(
      { _id: new ObjectId(id) },
      { 
        $set: { 
          ...(name && { name }),
          ...(email && { email }),
          ...(role && { role }),
          updatedAt: new Date()
        } 
      }
    );
    
    res.json({ success: true });
  } catch (error) {
    res.status(500).json({ error: 'Server error' });
  }
}

🌐 Browser Compatibility

Frontend Hamroun supports all modern browsers out of the box:

  • Chrome (latest 2 versions)
  • Firefox (latest 2 versions)
  • Safari (latest 2 versions)
  • Edge (latest 2 versions)

For older browsers like IE11, you'll need:

  • Appropriate polyfills
  • Transpilation to ES5
  • CSS compatibility work

ā“ Frequently Asked Questions

How does Frontend Hamroun compare to React?

Frontend Hamroun offers a React-like API but with additional built-in features:

  • Smaller bundle size (~5KB vs. 42KB+)
  • Integrated backend capabilities
  • Built-in server-side rendering
  • Database integrations
  • Authentication system

For React developers, the learning curve is minimal.

Can I use it with existing React components?

While Frontend Hamroun's API is similar to React's, they have different internal implementations. You can:

  • Port React components to Frontend Hamroun with minimal changes
  • Use React components in dedicated sections with a compatibility layer
  • Share non-UI code and logic between both frameworks
Does it support static site generation (SSG)?

Yes, Frontend Hamroun provides tools for static site generation. Use the renderToString API to pre-render pages at build time.

šŸ“„ License

MIT Ā© Hamroun

ā¬†ļø Back to top

Keywords

frontend

FAQs

Package last updated on 10 May 2025

Did you know?

Socket

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Install

Related posts