A RetroSearch Logo

Home - News ( United States | United Kingdom | Italy | Germany ) - Football scores

Search Query:

Showing content from https://github.com/web-widget/web-widget below:

GitHub - web-widget/web-widget: Web Widget

🌟 A revolutionary meta-framework that seamlessly integrates multiple frontend technologies with unprecedented simplicity.

Break free from technology stack lock-in while maintaining elegant simplicity. Experience the power of running React, Vue, and other frameworks together with ease.

⚠️ Preview Release: This project is currently in preview stage with API subject to changes. Some features mentioned may be under development.

💫 Design Philosophy: Simplicity Meets Power

Our framework is built on the core principle that powerful technology should be intuitive to use:

"The best technology is the one you don't have to think about" - This is our guiding principle.

The Challenge: Modern web development often forces teams into framework silos, making technology evolution difficult and risky. Monolithic frontend architectures become increasingly hard to maintain and upgrade.

The Web Widget Approach: A meta-framework that embraces framework diversity while maintaining simplicity.

Applications like insmind.com and gaoding.com demonstrate these benefits in practice:

Application Architecture Use Case insmind.com React pages + Vue 3 + Vue 2 components "Seamlessly integrated legacy Vue 2 components with modern Vue 3 features" gaoding.com React pages + Vue 2 + Lit components "Migrated incrementally from Vue 2 to React without downtime"

💡 These examples showcase the framework's ability to handle complex multi-technology scenarios in real applications.

The approach works: Web Widget provides a practical path to multi-framework architecture without the usual complexity overhead.

Get started with Web Widget (preview release):

# Clone or download the example
git clone https://github.com/web-widget/web-widget.git
cd web-widget/examples/react  # or examples/vue

# Install dependencies
npm install

# Start development
npm run dev
🎯 Current Framework Support Framework Status Version React ✅ Supported 19.x Vue ✅ Supported 3.x, 2.x Svelte 🚧 Coming Soon - Solid 🚧 Coming Soon - Angular 🚧 Planned -

💡 Preview Status: Web Widget is currently in preview. A dedicated CLI tool (create-web-widget-app) is planned for future releases.

Try online examples:

🏗️ Core Architecture: Simplicity in Action

Web Widget's power comes from just two concepts - keeping it beautifully simple:

📄 Route Modules (*@route.*)

Server-side modules for rendering pages and handling HTTP requests.

// routes/index@route.tsx - Simple, yet it can do everything
import { defineRouteComponent } from '@web-widget/helpers';
import Counter from './components/Counter@widget.tsx';

export default defineRouteComponent(function HomePage() {
  return (
    <html>
      <body>
        <h1>Welcome to Web Widget</h1>
        <Counter count={0} />
      </body>
    </html>
  );
});
🧩 Widget Modules (*@widget.*)

Isomorphic components that work on both server and client - the secret to our power.

// components/Counter@widget.tsx (React)
import { useState } from 'react';

export default function Counter({ count }: { count: number }) {
  const [value, setValue] = useState(count);

  return (
    <div>
      <button onClick={() => setValue((v) => v - 1)}>-</button>
      <span>{value}</span>
      <button onClick={() => setValue((v) => v + 1)}>+</button>
    </div>
  );
}
<!-- components/Counter@widget.vue (Vue) -->
<script setup lang="ts">
import { ref } from 'vue';

const props = defineProps<{ count: number }>();
const value = ref(props.count);
</script>

<template>
  <div>
    <button @click="value--">-</button>
    <span>{{ value }}</span>
    <button @click="value++">+</button>
  </div>
</template>
🔀 Cross-Framework Magic: Power Unleashed

The real power emerges when you effortlessly combine different frameworks:

// Mix React and Vue in the same page
import ReactCounter from './Counter@widget.tsx';
import VueCounter from './Counter@widget.vue';
import { toReact } from '@web-widget/vue';

const RVueCounter = toReact(VueCounter);

export default defineRouteComponent(function MixedPage() {
  return (
    <div>
      <h2>React Component:</h2>
      <ReactCounter count={0} />

      <h2>Vue Component (as React):</h2>
      <RVueCounter count={0} />
    </div>
  );
});
Lightning Fast Performance 🔄 Technology Flexibility Without Complexity 🌐 Web Standards First - Built to Last 🔧 Production Ready, Developer Friendly 🚀 End-to-End State Caching: Zero Hydration Errors

Web Widget solves SSR's biggest challenge: hydration mismatches. Our cache providers ensure server and client always render identical content.

// ❌ Traditional SSR: Hydration mismatches
function UserProfile({ userId }) {
  const [user, setUser] = useState(null); // Server: null, Client: fetched data

  useEffect(() => {
    fetchUser(userId).then(setUser); // Only runs on client
  }, []);

  return <div>{user?.name || 'Loading...'}</div>; // Different on server vs client
}

// ✅ Web Widget: Perfect hydration
function UserProfile({ userId }) {
  const user = syncCacheProvider(`user-${userId}`, () => fetchUser(userId));

  return <div>{user.name}</div>; // Identical on server and client
}
  1. Server: Execute data fetching, cache results
  2. Transfer: Automatically embed cached data in HTML
  3. Client: Read cached data, skip re-fetching
// Vue 3: Use asyncCacheProvider for top-level await
const userData = await asyncCacheProvider('user-profile', async () => {
  return fetch('/api/user').then((r) => r.json());
});

// React: Use syncCacheProvider for hook-like behavior
const userData = syncCacheProvider('user-profile', async () => {
  return fetch('/api/user').then((r) => r.json());
});
📁 Project Structure: Elegant Organization
my-web-widget-app/
├── routes/
│   ├── (components)/
│   │   ├── BaseLayout.tsx
│   │   ├── Counter@widget.tsx
│   │   └── Counter@widget.vue
│   ├── index@route.tsx
│   ├── about@route.tsx
│   ├── action/
│   │   ├── index@route.tsx
│   │   └── functions@action.ts
│   └── api/
│       └── hello@route.ts
├── public/
├── entry.client.ts
├── entry.server.ts
├── routemap.server.json
├── importmap.client.json
├── package.json
├── tsconfig.json
└── vite.config.ts

Organized structure with clear separation of concerns.

File-System Routing

Web Widget supports file-system based routing conventions, automatically generating routemap.server.json during development.

File Name Route Pattern Matching Paths index@route.ts / / about@route.ts /about /about blog/[slug]@route.ts /blog/:slug /blog/foo, /blog/bar blog/[slug]/comments@route.ts /blog/:slug/comments /blog/foo/comments old/[...path]@route.ts /old/:path* /old/foo, /old/bar/baz [[lang]]/index@route.ts /{/:lang}? /, /en, /zh-cn

Create route groups using parentheses-wrapped folder names:

└── routes
    ├── (middlewares)
    │   └── [...all]@middleware.ts # -> /:all*
    ├── (vue2)
    │   ├── package.json
    │   └── marketing@route.vue    # -> /marketing
    └── (vue3)
        ├── package.json
        └── info@route.vue         # -> /info
Route Module Examples
// ./routes/index@route.tsx
import { defineRouteComponent, defineMeta } from '@web-widget/helpers';
import BaseLayout from './components/BaseLayout';

export const meta = defineMeta({
  title: 'Home - Web Widget',
});

export default defineRouteComponent(function Page() {
  return (
    <BaseLayout>
      <h1>Welcome to Web Widget</h1>
      <p>This is a basic route module example</p>
    </BaseLayout>
  );
});
Data Fetching and Processing
// ./routes/fetch@route.tsx
import {
  defineRouteComponent,
  defineRouteHandler,
  defineMeta,
} from '@web-widget/helpers';
import BaseLayout from './components/BaseLayout';

interface PageData {
  items: Array<{ title: string; url: string }>;
}

async function fetchData(url: URL): Promise<PageData> {
  const response = await fetch(`${url.origin}/api/data`);
  return response.json();
}

export const meta = defineMeta({
  title: 'Data Fetching Example',
});

export const handler = defineRouteHandler<PageData>({
  async GET(ctx) {
    const data = await fetchData(new URL(ctx.request.url));

    const response = ctx.html(data);
    response.headers.set('X-Custom-Header', 'Hello');

    return response;
  },
});

export default defineRouteComponent<PageData>(function Page({ data }) {
  return (
    <BaseLayout>
      <h1>Data Fetching</h1>
      <ul>
        {data.items.map((item, index) => (
          <li key={index}>
            <a href={item.url}>{item.title}</a>
          </li>
        ))}
      </ul>
    </BaseLayout>
  );
});

Routes are automatically configured based on your file structure. Web Widget generates the routing configuration during development, so you don't need to manually manage route mappings.

Advanced Routing Features
// routes/users/[id]@route.tsx
export default defineRouteComponent(function UserPage(props) {
  const { id } = props.params;
  return <div>User ID: {id}</div>;
});
// Simple redirects in route handlers
export const handler = defineRouteHandler({
  async GET(ctx) {
    if (shouldRedirect) {
      return redirect('/new-path', 301);
    }
    return ctx.html();
  },
});
// Route-level error handling
export const handler = defineRouteHandler({
  async GET(ctx) {
    if (!data) {
      throw createHttpError(404, 'Not Found');
    }
    return ctx.html(data);
  },
});
export const meta = defineMeta({
  title: 'My Page',
  description: 'Page description',
});

// Dynamic metadata in handlers
export const handler = defineRouteHandler({
  async GET(ctx) {
    const newMeta = mergeMeta(ctx.meta, {
      title: `User: ${user.name}`,
    });
    return ctx.html(null, { meta: newMeta });
  },
});
Widget Module Examples
// ./components/Counter@widget.tsx
import { useState } from 'react';
import styles from './Counter.module.css';

interface CounterProps {
  count: number;
}

export default function Counter(props: CounterProps) {
  const [count, setCount] = useState(props.count);

  return (
    <div className={styles.counter}>
      <button onClick={() => setCount(count - 1)}></button>
      <span className={styles.count}>{count}</span>
      <button onClick={() => setCount(count + 1)}>+</button>
    </div>
  );
}
Vue Widget with Scoped Styles
<!-- ./components/Counter@widget.vue -->
<script setup lang="ts">
import { ref } from 'vue';

interface CounterProps {
  count: number;
}

const props = defineProps<CounterProps>();
const count = ref(props.count);
</script>

<template>
  <div class="counter">
    <button @click="count--">−</button>
    <span class="count">{{ count }}</span>
    <button @click="count++">+</button>
  </div>
</template>

<style scoped>
/*...*/
</style>
// ./routes/index@route.tsx
import { defineRouteComponent } from '@web-widget/helpers';
import BaseLayout from './components/BaseLayout';
import ReactCounter from './components/Counter@widget.tsx';
import VueCounter from './components/Counter@widget.vue';
import { toReact } from '@web-widget/vue';

const RVueCounter = toReact(VueCounter);

export default defineRouteComponent(function Page() {
  return (
    <BaseLayout>
      <h1>Mixed Technology Stack Example</h1>

      <h2>React Component:</h2>
      <ReactCounter count={0} />

      <h2>Vue Component:</h2>
      <RVueCounter count={0} />
    </BaseLayout>
  );
});
Advanced Widget Features
// Server-only rendering
<StaticChart renderStage="server" data={chartData} />

// Client-only rendering
<InteractiveMap renderStage="client" location={coords} />

Access request data, parameters, and state in your components:

import { context } from '@web-widget/helpers/context';

export default function MyComponent() {
  const { request, params, state } = context();
  return <div>Current URL: {request.url}</div>;
}
Web Standards APIs

Full Web Standards support in all environments:

Advanced Import Maps Configuration Production-Ready Import Maps
{
  "imports": {
    "react": "https://esm.sh/react@18.2.0",
    "react-dom": "https://esm.sh/react-dom@18.2.0",
    "react-dom/client": "https://esm.sh/react-dom@18.2.0/client",
    "vue": "https://esm.sh/vue@3.4.8",
    "lodash": "https://esm.sh/lodash@4.17.21",
    "date-fns": "https://esm.sh/date-fns@2.30.0",
    "@company/ui-kit": "https://cdn.company.com/ui-kit@1.2.0/index.js",
    "@company/analytics": "https://cdn.company.com/analytics@2.1.0/index.js"
  },
  "scopes": {
    "/legacy/": {
      "react": "https://esm.sh/react@17.0.2",
      "react-dom": "https://esm.sh/react-dom@17.0.2"
    }
  }
}

Benefits in action:

// In your components - just import naturally
import React from 'react'; // Shared via importmap
import { createApp } from 'vue'; // Shared via importmap
import MyComponent from '@components/MyComponent'; // Path mapping

// No build-time complexity, maximum runtime efficiency

The Web Platform Way: Instead of reinventing module sharing, we embrace the native solution that browsers are optimizing for.

Server Actions: Seamless Client-Server Integration

Web Widget's Server Actions feature allows you to call server-side functions directly from client components with unprecedented simplicity - no API endpoints, no fetch calls, just direct function invocation.

// Traditional approach: Complex API setup
// ❌ Create API endpoint
export async function POST(request: Request) {
  const data = await request.json();
  return Response.json({ message: data.content, date: new Date() });
}

// ❌ Client-side fetch calls
const handleClick = async () => {
  const response = await fetch('/api/echo', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ content: inputValue }),
  });
  const result = await response.json();
  setLog(JSON.stringify(result));
};

// ✅ Web Widget Server Actions: Pure simplicity
// Server function (functions@action.ts)
export const echo = async (content: string) => {
  return {
    message: content,
    date: new Date().toISOString(),
    respondent: 'server',
  };
};

// Client component - call server function like any local function
const handleClick = async () => {
  const result = await echo(inputValue); // Direct server call!
  setLog(JSON.stringify(result));
};
routes/action/
├── index@route.tsx        # Route page
├── Echo@widget.tsx        # Interactive client component
├── functions@action.ts    # Server-only functions
└── styles.css            # Styling
// functions@action.ts - Server functions
export const echo = async (content: string) => {
  // This code ONLY runs on the server
  return {
    message: content,
    date: new Date().toISOString(),
    respondent: typeof document === 'undefined' ? 'server' : 'client',
  };
};

// Echo@widget.tsx - Client component
import { useState } from 'react';
import { echo } from './functions@action';

export default function EchoWidget() {
  const [inputValue, setInputValue] = useState('');
  const [result, setResult] = useState('');

  const handleSubmit = async () => {
    // Direct server function call - no fetch, no API endpoints!
    const response = await echo(inputValue);
    setResult(JSON.stringify(response, null, 2));
  };

  return (
    <>
      <input
        value={inputValue}
        onChange={(e) => setInputValue(e.target.value)}
      />
      <button onClick={handleSubmit}>Send to Server</button>
      {result && <pre>{result}</pre>}
    </>
  );
}
🌟 Why Server Actions Matter
  1. 🎯 Simplicity: Write server logic as simple functions, not API endpoints
  2. ⚡ Performance: Automatic request optimization and batching
  3. 🔒 Security: Server functions never expose internals to client
  4. 📱 Developer Experience: Unified development model across client/server
  5. 🚀 Productivity: Focus on business logic, not infrastructure code

The Future of Full-Stack Development: Server Actions represent a paradigm shift from thinking in terms of "API endpoints" to thinking in terms of "server functions" - making full-stack development as natural as writing single-tier applications.

HTTP Caching & Performance

Web Widget provides enterprise-grade HTTP caching using standard Cache Control headers:

// index@route.tsx

export const config = {
  cache: {
    // Cache rendered pages using HTTP cache control directives
    cacheControl: {
      // Cache for 60 seconds in shared caches
      sharedMaxAge: 60,
      // Serve stale content for 7 days on errors
      staleIfError: 604800,
      // Background revalidation for 7 days
      staleWhileRevalidate: 604800,
    },
  },
};

// ...

This mode requires integrating the @web-widget/middlewares/cache middleware

Project Setup & Configuration Complete Project Structure
my-web-widget-app/
├── routes/
│   ├── (components)/
│   │   ├── BaseLayout.tsx
│   │   ├── Counter@widget.tsx
│   │   └── Counter@widget.vue
│   ├── index@route.tsx
│   ├── about@route.tsx
│   ├── action/
│   │   ├── index@route.tsx
│   │   └── functions@action.ts
│   └── api/
│       └── hello@route.ts
├── public/
├── entry.client.ts
├── entry.server.ts
├── routemap.server.json
├── importmap.client.json
├── package.json
├── tsconfig.json
└── vite.config.ts
{
  "dependencies": {
    "@web-widget/helpers": "^1.59.0",
    "@web-widget/html": "^1.59.0",
    "@web-widget/node": "^1.59.0",
    "@web-widget/react": "^1.59.0",
    "@web-widget/vue": "^1.59.0",
    "@web-widget/web-router": "^1.59.0",
    "@web-widget/web-widget": "^1.59.0",
    "react": "^19.0.0",
    "react-dom": "^19.0.0",
    "vue": "^3.4.8"
  },
  "devDependencies": {
    "@vitejs/plugin-react": "^4.1.1",
    "@vitejs/plugin-vue": "^5.0.0",
    "@web-widget/vite-plugin": "^1.59.0",
    "vite": "^5.4.19"
  }
}
Best Practices & Tips Development Best Practices
  1. Technology Stack Isolation: Use widget modules to achieve isolation of different technology stack components
  2. Progressive Enhancement: Prioritize server-side rendering, add client-side interaction as needed
  3. Caching Strategy: Use lifecycle caching wisely to improve performance
  4. Error Handling: Implement comprehensive error boundaries and fallback solutions
  5. Type Safety: Make full use of TypeScript's type system

Join developers exploring the future of multi-framework architecture.

🌟 The Future of Framework Freedom

Web Widget represents a new approach to frontend architecture - one that embraces technology diversity rather than fighting it. By building on Web Standards and providing elegant abstractions, we're creating a path forward that doesn't require abandoning existing investments or limiting future choices.

Ready to explore framework freedom?

Experience the elegant simplicity of multi-framework architecture. Build your future with Web Widget.

"Simplicity is the ultimate sophistication" - Leonardo da Vinci


RetroSearch is an open source project built by @garambo | Open a GitHub Issue

Search and Browse the WWW like it's 1997 | Search results from DuckDuckGo

HTML: 3.2 | Encoding: UTF-8 | Version: 0.7.4