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

@webtypen/webframez-react

v0.0.31

Published

TypeScript React RSC addition for @webtypen/webframez-core

Readme

@webtypen/webframez-react

React Server Components (RSC) extension for @webtypen/webframez-core.

@webtypen/webframez-react provides:

  • seamless webframez-core integration via initWebframezReact(Route)
  • file-based routing for pages/**/index.tsx
  • layout/error handling with RouteChildren
  • client-side navigation (Link, Redirect, useRouter) and cookies (useCookie)
  • server-rendered initial HTML plus RSC streaming
  • a small CLI for the standard server/client build pipeline

Requirements

  • Node.js >= 20
  • @webtypen/webframez-core
  • React 19.x with matching react-dom and react-server-dom-webpack

Installation

npm i @webtypen/webframez-react @webtypen/webframez-core react react-dom react-server-dom-webpack
npm i -D typescript webpack webpack-cli ts-loader

Quick Start with webframez-core

// src/server.ts
import path from "node:path";
import { BaseKernelWeb, Route, WebApplication } from "@webtypen/webframez-core";
import { initWebframezReact } from "@webtypen/webframez-react";

class Kernel extends BaseKernelWeb {
  static controller = {};
  static middleware = {};
}

const ReactRoute = initWebframezReact(Route);

const app = new WebApplication();
app.boot({
  kernel: Kernel,
  routesFunction: () => {
    ReactRoute.renderReact("/react", {
      distRootDir: path.resolve(process.cwd(), "dist"),
    });
  },
});

Notes:

  • "/react" is automatically registered as a catch-all route (/react/*).
  • basePath, assetsPrefix, rscPath, and clientScriptUrl are derived automatically from the mount path unless you override them.
  • initWebframezReact(Route) returns the extended route facade, which gives you reliable editor autocompletion for renderReact(...) even in monorepos or symlinked development setups.
  • The package also ships module augmentation for Route.renderReact(...), but using the returned ReactRoute variable is the most robust TypeScript setup.

Route.renderReact()

Signature:

Route.renderReact(path, options)

Example:

Route.renderReact("/app", {
  distRootDir: path.resolve(process.cwd(), "dist"),
  method: "GET",
  routeOptions: {
    middleware: ["auth"],
  },
});

Options

distRootDir

  • Required.
  • Directory containing the built client assets and generated manifests.

pagesDir

  • Optional.
  • Directory containing the compiled pages/** output.
  • Default: ${distRootDir}/pages

manifestPath

  • Optional.
  • Path to the React client manifest.
  • Default: ${distRootDir}/react-client-manifest.json

assetsPrefix

  • Optional.
  • Public URL prefix used to serve built client assets.
  • Auto-derived from path.
  • Example for "/react": /react/assets/

rscPath

  • Optional.
  • Public URL for the RSC endpoint.
  • Auto-derived from path.
  • Example for "/react": /react/rsc

clientScriptUrl

  • Optional.
  • Public URL of the browser client entry bundle.
  • Auto-derived from path.
  • Example for "/react": /react/assets/client.js

basePath

  • Optional.
  • Basename mounted in front of all file-router paths.
  • Auto-derived from path when path !== "/".

liveReloadPath

  • Optional.
  • Enables dev live reload on a custom path or disables it explicitly with false.
  • Automatically disabled in production mode.

method

  • Optional.
  • HTTP method or methods used to register the route.
  • Supported values: "GET" | "POST" | "PUT" | "DELETE"
  • Default: "GET"

routeOptions

  • Optional.
  • Additional route options forwarded to webframez-core.
  • Typical use case: middleware.

Head() Assets

Inside a page, layout, or error Head() method you can set basename. That basename is applied to favicon and links[].href, and also updates the router basename used by Link, Redirect, and client-side navigation.

export function Head() {
  return {
    title: "Dashboard",
    basename: "/app",
    favicon: "/favicon.ico",
    links: [{ rel: "stylesheet", href: "/styles/dashboard.css" }],
  };
}

Absolute URLs like https://... or //... stay unchanged.

Recommended Project Structure

pages/
  layout.tsx
  errors.tsx
  index.tsx
  about/index.tsx
src/
  server.ts
  client.tsx
  components/
dist/

tsconfig.server.json

Compared to a standard @webtypen/webframez-core project, the server TypeScript config usually needs a few changes:

  • enable JSX via "jsx": "react-jsx"
  • include pages/**/*.tsx
  • include src/components/**/*.tsx
  • include your server entry (src/server.ts or src/server.tsx)
  • exclude the browser client entry (src/client.tsx by default)
  • add paths mappings for the @webtypen/webframez-react package and its subpaths

When you use the CLI (webframez-react build:server / watch:server), it generates a temporary .webframez-react.tsconfig.server.json that extends your project tsconfig.server.json. That means:

  • your own tsconfig.server.json stays the source of truth
  • the CLI only injects the resolved server entry and the standard RSC include/exclude rules
  • you only need to customize the base config when your project structure differs from the defaults

A good starting point is the shipped default config:

  • @webtypen/webframez-react/defaults/tsconfig.server
  • @webtypen/webframez-react/defaults/tsconfig.server.example

Example:

{
  "compilerOptions": {
    "target": "ES2020",
    "module": "CommonJS",
    "moduleResolution": "Node",
    "baseUrl": ".",
    "paths": {
      "@webtypen/webframez-react": [
        "./node_modules/@webtypen/webframez-react/dist/index.d.ts"
      ],
      "@webtypen/webframez-react/types": [
        "./node_modules/@webtypen/webframez-react/dist/types.d.ts"
      ],
      "@webtypen/webframez-react/router": [
        "./node_modules/@webtypen/webframez-react/dist/router.d.ts"
      ],
      "@webtypen/webframez-react/client": [
        "./node_modules/@webtypen/webframez-react/dist/client.d.ts"
      ],
      "@webtypen/webframez-react/navigation": [
        "./node_modules/@webtypen/webframez-react/dist/navigation.d.ts"
      ],
      "@webtypen/webframez-react/webframez-core": [
        "./node_modules/@webtypen/webframez-react/dist/webframez-core.d.ts"
      ]
    },
    "jsx": "react-jsx",
    "strict": true,
    "esModuleInterop": true,
    "skipLibCheck": true,
    "outDir": "dist",
    "rootDir": "."
  },
  "include": [
    "src/server.ts",
    "src/server.tsx",
    "src/components/**/*.tsx",
    "pages/**/*.tsx",
    "src/types.d.ts"
  ],
  "exclude": [
    "src/client.tsx",
    "dist",
    "node_modules"
  ]
}

package.json Scripts

Recommended scripts:

{
  "scripts": {
    "build:server": "webframez-react build:server",
    "build:client": "webframez-react build:client",
    "build": "npm run build:server && npm run build:client",
    "start": "NODE_OPTIONS='--conditions react-server -r @webtypen/webframez-react/register' node start-server.cjs",
    "watch:server": "webframez-react watch:server",
    "watch:client": "webframez-react watch:client",
    "serve:watch": "NODE_OPTIONS='--conditions react-server -r @webtypen/webframez-react/register' node --watch start-server.cjs",
    "watch": "sh -c 'npm run watch:server & npm run watch:client & npm run serve:watch & wait'",
    "dev": "sh -c 'npm run watch:server & npm run watch:client & npm run serve:watch & wait'"
  }
}

Notes:

  • build compiles the server output (pages, server.ts) and the browser client bundle (client.tsx + RSC manifests).
  • start runs the built app in React Server mode.
  • watch / dev keep TypeScript and webpack in watch mode and restart Node automatically when server output changes.
  • @webtypen/webframez-react/register activates the React Server module register, so "use client" modules are treated correctly in Node and in the package's SSR worker.

If you run an existing webframez-core app directly with ts-node or node, use the same preload:

{
  "scripts": {
    "start": "NODE_OPTIONS='--conditions react-server -r @webtypen/webframez-react/register' ts-node ./app.ts",
    "watch:app": "nodemon --exec \"NODE_OPTIONS='--conditions react-server -r @webtypen/webframez-react/register' ts-node ./app.ts\""
  }
}

Or via the shipped wrapper command:

{
  "scripts": {
    "start": "TS_NODE_FILES=true webframez-react exec -- ts-node ./app.ts",
    "watch:app": "nodemon --exec \"TS_NODE_FILES=true webframez-react exec -- ts-node ./app.ts\""
  }
}

CLI Config and Custom Entry Paths

The CLI first checks project override files and then falls back to the package defaults:

  • tsconfig.server.json
  • webpack.client.cjs
  • webpack.server.cjs

If you do not want to create your own webpack config just to move client.tsx or server.ts, you can use a small project config file:

// webframez-react.config.mjs
export default {
  clientEntryPath: "src/app/client.tsx",
  serverEntryPath: "src/app/server.tsx",
};

Supported file names:

  • webframez-react.config.mjs
  • webframez-react.config.cjs
  • webframez-react.config.js
  • webframez-react.config.json

You can also override the entry paths per command:

webframez-react build:client --client-entry=src/app/client.tsx
webframez-react build:server --server-entry=src/app/server.tsx
webframez-react watch:client --client-entry=src/app/client.tsx
webframez-react watch:server --server-entry=src/app/server.tsx

Notes:

  • The default client entry is src/client.tsx.
  • The default server entry is src/server.ts, with automatic fallback to src/server.tsx if present.
  • build:server:webpack and watch:server:webpack also respect serverEntryPath.
  • build:server and watch:server generate a temporary .webframez-react.tsconfig.server.json so custom server entry paths also work with the TypeScript compiler.

File-Based Routing

Example:

pages/
  layout.tsx
  errors.tsx
  index.tsx
  about/index.tsx
  accounts/[username]/index.tsx

pages/layout.tsx:

"use server";

import React from "react";
import { RouteChildren } from "@webtypen/webframez-react/router";

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

RouteChildren marks where the currently resolved page should be rendered.

Error Handling with abort()

Every server page gets abort() via RouteContext.

"use server";

import type { PageProps } from "@webtypen/webframez-react/types";

export default function AccountPage({ params, abort }: PageProps) {
  if (params.username !== "jane") {
    abort({
      status: 404,
      message: `Account \"${params.username}\" not found`,
      payload: { attemptedUsername: params.username },
    });
  }

  return <section>...</section>;
}

Behavior:

  • default without options: 404 + "Page not found"
  • rendered through pages/errors.tsx
  • pathname is provided automatically by context
  • optional payload is forwarded to errors.tsx

Client Entry

// src/client.tsx
import { mountWebframezClient } from "@webtypen/webframez-react/client";

mountWebframezClient();

Optional:

mountWebframezClient({
  rootId: "root",
  rscEndpoint: "/react/rsc",
});

Navigation

"use client";

import React from "react";
import { Link, Redirect } from "@webtypen/webframez-react/navigation";

export function Nav() {
  return (
    <>
      <Link to="/">Home</Link>
      <Link to="/about">About</Link>
    </>
  );
}

export function Guard({ loggedIn }: { loggedIn: boolean }) {
  if (!loggedIn) {
    return <Redirect to="/login" replace />;
  }

  return null;
}

Notes:

  • Link and Redirect automatically use the basename from Route.renderReact().
  • You can override it per usage via basename.

Router and Cookies in Client Components

"use client";

import React from "react";
import { useCookie, useRouter } from "@webtypen/webframez-react/client";

export default function LoginAction() {
  const cookie = useCookie();
  const router = useRouter();

  return (
    <button
      onClick={() => {
        cookie.set("logged_in", "1", { path: "/react", sameSite: "Lax" });
        router.refresh();
      }}
    >
      Login
    </button>
  );
}

Public Entrypoints

  • @webtypen/webframez-react
    • initWebframezReact
    • createNodeRequestHandler
    • createFileRouter
    • createHTMLShell
    • sendRSC
    • createRSCHandler
  • @webtypen/webframez-react/webframez-core
    • initWebframezReact
  • @webtypen/webframez-react/router
    • RouteChildren
  • @webtypen/webframez-react/client
    • mountWebframezClient, useRouter, useCookie
  • @webtypen/webframez-react/navigation
    • Link, Redirect
  • @webtypen/webframez-react/types
    • RouteContext, PageProps, ErrorPageProps, AbortRouteOptions, ...

Package Build

Build the package itself:

npm run build

Watch mode for package development:

npm run build:watch