npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

chen-the-dawnstreak

v4.2.2

Published

赤刃明霄陈-轻量级React元框架:文件路由·数据钩子·SSR·PWA·多平台CLI脚手架

Readme

Chen-the-Dawnstreak

npm version React 19 License: MIT

赤刃明霄陈 — 轻量级 React 元框架:文件路由 · 数据钩子 · SSR · PWA · 多平台脚手架。

Star过200就在README里放赤刃明霄陈立绘

Quick Start — CLI

npx chen-the-dawnstreak my-app
# or
npx chen my-app

交互式选择项目类型:

| 类型 | 说明 | |------|------| | Web | Vite + React | | Web + PWA | 额外生成 manifest.json、Service Worker | | Desktop (Electron) | 额外生成 Electron 主进程/预加载脚本 | | Desktop (Tauri) | 额外生成 src-tauri/ Rust 项目 |

CLI 不会自动安装依赖,创建完成后按提示手动执行 npm install

Installation

npm install chen-the-dawnstreak

Peer requirement: React 19+.

Quick Start

import { ChenRouter, Routes, Route, Link, useFetch } from 'chen-the-dawnstreak';

function App() {
  return (
    <ChenRouter>
      <nav>
        <Link to="/">Home</Link>
        <Link to="/about">About</Link>
      </nav>
      <Routes>
        <Route path="/" element={<Home />} />
        <Route path="/about" element={<About />} />
      </Routes>
    </ChenRouter>
  );
}

Router

Thin wrapper around react-router v7.

import { ChenRouter, Route, Routes, Link, useNavigate } from 'chen-the-dawnstreak';

Re-exports: ChenRouter, Route, Routes, Link, NavLink, Navigate, Outlet, useNavigate, useParams, useSearchParams, useLocation, useMatch.

Data Fetching

useFetch

import { useFetch } from 'chen-the-dawnstreak';

function UserList() {
  const { data, loading, error, refetch } = useFetch<User[]>('/api/users');

  if (loading) return <p>Loading...</p>;
  if (error) return <p>Error: {error.message}</p>;

  return (
    <ul>
      {data?.map((u) => <li key={u.id}>{u.name}</li>)}
    </ul>
  );
}

useMutation

import { useMutation } from 'chen-the-dawnstreak';

function CreateUser() {
  const { mutate, loading } = useMutation<User, { name: string }>('/api/users');

  return (
    <button disabled={loading} onClick={() => mutate({ name: 'Chen' })}>
      Create
    </button>
  );
}

Forms

useForm

Lightweight form management hook with validation, similar to React Hook Form.

import { useForm } from 'chen-the-dawnstreak';

function LoginForm() {
  const { register, handleSubmit, errors, isSubmitting } = useForm({
    defaultValues: { email: '', password: '' },
    validationRules: {
      email: { required: 'Email is required', pattern: { value: /^\S+@\S+$/, message: 'Invalid email' } },
      password: { required: true, minLength: { value: 8, message: 'Min 8 characters' } },
    },
    onSubmit: async (values) => {
      await fetch('/api/login', { method: 'POST', body: JSON.stringify(values) });
    },
  });

  return (
    <form onSubmit={handleSubmit}>
      <input {...register('email')} placeholder="Email" />
      {errors.email && <p>{errors.email}</p>}
      <input {...register('password')} type="password" placeholder="Password" />
      {errors.password && <p>{errors.password}</p>}
      <button type="submit" disabled={isSubmitting}>Login</button>
    </form>
  );
}

Returns: { values, errors, touched, isValid, isSubmitting, register, handleSubmit, setValue, setValues, reset, validate, validateField }.

Validation rules: required, min, max, minLength, maxLength, pattern, validate (async), custom.

useController

For controlled components that don't use standard onChange:

import { useForm, useController } from 'chen-the-dawnstreak';

function MyForm() {
  const form = useForm({ defaultValues: { role: 'user' } });
  const { field, fieldState } = useController(form, { name: 'role' });

  return <select value={field.value} onChange={field.onChange}>...</select>;
}

State Management

createStore (Context-based)

Creates a scoped store with React Context. Each StoreProvider holds its own state.

import { createStore } from 'chen-the-dawnstreak';

const { StoreProvider, useStore, useStoreDispatch, useStoreSelector } = createStore({
  name: 'counter',
  initialState: { count: 0, label: 'Counter' },
});

function Counter() {
  const count = useStoreSelector((s) => s.count);
  const dispatch = useStoreDispatch();
  return <button onClick={() => dispatch((s) => ({ count: s.count + 1 }))}>Count: {count}</button>;
}

function App() {
  return (
    <StoreProvider>
      <Counter />
    </StoreProvider>
  );
}

createSimpleStore (Global singleton)

Module-level store, no Provider needed. Good for app-wide state like themes or auth.

import { createSimpleStore } from 'chen-the-dawnstreak';

const themeStore = createSimpleStore({ dark: false });

function ThemeToggle() {
  const { dark } = themeStore.useStore();
  const dispatch = themeStore.useDispatch();
  return <button onClick={() => dispatch({ dark: !dark })}>{dark ? 'Light' : 'Dark'}</button>;
}

Server Actions / RSC

useServerAction

Wraps React 19's useActionState for server actions:

import { useServerAction } from 'chen-the-dawnstreak';

// Server action (in a "use server" file)
async function createUser(prev: { error?: string }, formData: FormData) {
  "use server";
  const name = formData.get('name') as string;
  // ... create user
  return { error: undefined };
}

// Client component
function CreateUserForm() {
  const { state, execute, isPending } = useServerAction(createUser, { error: undefined });

  return (
    <form action={execute}>
      <input name="name" placeholder="Name" />
      <button type="submit" disabled={isPending}>Create</button>
      {state.error && <p>{state.error}</p>}
    </form>
  );
}

Re-exports: useFormStatus (from react-dom), useOptimistic (from react).

SSR

Chen supports server-side rendering with streaming and string-based APIs.

Setup

// vite.config.ts
import { chen } from 'chen-the-dawnstreak/vite-plugin';

export default defineConfig({
  plugins: [react(), chen({ ssr: true })],
});

The ssr: true option stubs CSS imports during SSR builds and configures ssr.noExternal.

Server-side rendering

import { renderToStream, renderToHTML, createHTMLShell, ChenSSRRouter } from 'chen-the-dawnstreak/ssr';
import express from 'express';

const app = express();
app.use(express.static('dist/client'));

app.get('*', (req, res) => {
  const element = (
    <ChenSSRRouter location={req.url}>
      <App />
    </ChenSSRRouter>
  );

  // Option 1: Streaming (recommended)
  renderToStream(element, res, {
    clientEntry: '/assets/main.js',
    title: 'My App',
    cssHref: '/assets/style.css',
  });

  // Option 2: String rendering
  // const html = renderToHTML(element, { clientEntry: '/assets/main.js', title: 'My App' });
  // res.send(html);
});

API

  • renderToStream(element, writable, options) — streams HTML with React's renderToPipeableStream
  • renderToHTML(element, options) — returns complete HTML string
  • createHTMLShell(options) — returns { beforeContent, afterContent } for custom streaming
  • ChenSSRRouter — re-export of StaticRouter from react-router
  • isBrowser / isServer — environment detection constants

Vite Plugin

// vite.config.ts
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
import { chen } from 'chen-the-dawnstreak/vite-plugin';

export default defineConfig({
  plugins: [react(), chen()],
});

File Routing

Place page files under src/pages/ according to convention. The plugin automatically generates routes, eliminating the need to manually write <Routes>/<Route>.

chen({ routes: true })
// Or custom directory
chen({ routes: { dir: 'src/pages' } })

Add type references in vite-env.d.ts:

/// <reference types="chen-the-dawnstreak/vite-plugin/client" />

Use in the application entry point:

import { ChenRouter } from 'chen-the-dawnstreak';
import { ChenRoutes } from 'virtual:chen-routes';

ReactDOM.createRoot(document.getElementById('root')!).render(
  <ChenRouter>
    <ChenRoutes />
  </ChenRouter>
);

File Conventions:

| File | Route | Description | |------|------|------| | pages/index.tsx | / | Homepage | | pages/about.tsx | /about | Static Routing | | pages/blog/index.tsx | /blog | Index | | pages/blog/[id].tsx | /blog/:id | Dynamic Parameters | | pages/[...slug].tsx | * | Wildcard catch-all | | pages/_layout.tsx | — | Root Layout, must contain <Outlet /> | | pages/blog/_layout.tsx | — | /blog Nested Layout | | pages/_404.tsx | * | Custom 404 Page |

_layout.tsx Example:

import { Outlet } from 'chen-the-dawnstreak';

export default function Layout() {
  return (
    <>
      <nav>...</nav>
      <Outlet />
    </>
  );
}

Page files are automatically split using React.lazy. Adding/deleting files during development triggers an automatic refresh.

PWA Support

chen({ pwa: true })
// Or custom configuration
chen({
  pwa: {
    name: 'My App',
    shortName: 'App',
    themeColor: '#6750a4',
    backgroundColor: '#ffffff',
    display: 'standalone',
    icons: [
      { src: '/icons/icon-192x192.png', sizes: '192x192', type: 'image/png' },
      { src: '/icons/icon-512x512.png', sizes: '512x512', type: 'image/png' },
    ],
  },
})

After enabling PWA, manifest.json and sw.js are automatically generated during the build process, and the manifest link, theme-color meta, and Service Worker registration scripts are injected into the HTML.

Roadmap

  • [x] Router (react-router v7 wrapper)
  • [x] File-based routing
  • [x] Data fetching hooks (useFetch, useMutation)
  • [x] Form management (useForm, useController)
  • [x] State management (createStore, createSimpleStore)
  • [x] Server actions (RSC)
  • [x] SSR support (streaming + string)
  • [x] Build tooling (Vite plugin)
  • [x] CLI scaffolding tool (Web / PWA / Electron / Tauri)

License

MIT