Skip to content

[Framework]: Dinou: Full-Stack React 19 framework with RSC, Server Functions, SSR, SSG, ISG, ISR. #8513

Description

@roggc

Name

Dinou

Homepage

https://dinou.dev

Install instructions

https://dinou.dev/docs/getting-started

Is your framework open source?

Yes

Well maintained

Changelog

All notable changes to this project will be documented in this file.

The format is based on Keep a Changelog,
and this project adheres to Semantic Versioning.

[4.0.16] - 2026-06-30

Fixed

  • Cookie Deletion Attributes: Reconstructed streaming cookie deletion to serialize and include domain, secure, and sameSite properties, ensuring browsers match scopes and delete cookies correctly.
  • Defensive Redirects: Added a safety check in resolveRelativeUrl to fallback to / if the destination path is invalid (such as undefined or null), avoiding server crashes.
  • TypeScript Type Definitions: Updated the clearCookie signature in index.d.ts to accept the full CookieOptions interface, resolving compilation errors when using sameSite or secure attributes.

[4.0.15] - 2026-06-29

Added

  • VFS Routing Cache: Introduced an in-memory Virtual File System (VFS) to cache filesystem structures under src/ at production startup, resolving dynamic routes entirely in-memory and eliminating synchronous event loop-blocking disk I/O.

Fixed

  • Cross-Platform Separators: Normalized Server Functions manifest keys and runtime lookup checks to consistently use forward slashes (/), preventing OS path format mismatches (\ vs /) and subsequent 400 Bad Request execution errors.

[4.0.14] - 2026-06-29

Added

  • Soft Redirects: Exposes the SPA transition navigation internally via window.__DINOU_ROUTER_NAVIGATE__ to enable smooth client-side redirects from both Server Functions and RSC payloads, keeping the React client state intact and preventing full browser page reloads.

Fixed

  • External Links Interception: Restored native browser navigation for external domains, protocol-relative links (//...), and special protocols (mailto:, tel:, etc.) by preventing the SPA router from capturing or prefetching non-internal routes.

[4.0.13] - 2026-06-29

Added

  • Universal Redirects: Full support for redirects on Server Components, getProps, Server Actions, and client SPA navigation.
  • Standard Relative Paths: Support for relative paths (../sibling, ./child, ?query, #hash) matching directory-first URL resolution.
  • Absolute Link Hover: Links now render resolved absolute paths to ensure correct browser previews and right-click behaviors.

Fixed

  • RSC Stream Stability: Resolved socket crashes (Connection closed) and duplicate Express header warnings when redirects occur during streamed RSC requests.
  • SSR Process Leaks: Render processes are now cleaned up immediately after an HTML redirect is triggered.

Security

  • Redirect Sanitization: Blocked unsafe external domains (https://...), protocol-relative URLs (//...), and scripting payloads (javascript:...).

Refactored

  • Shared Helpers: Unified path resolution logic into a shared module (url-resolver.js).

[4.0.12] - 2026-06-28

Security

  • Fix DOM XSS / Script Injection Vulnerability: Replaced inline HTML/Script injection (<script> tags executed via createContextualFragment in client-side proxies) with a secure, data-driven line-based protocol for active streams and custom HTTP headers/JSON payload signaling for redirects.
  • CSP (Content Security Policy) Compatibility: Removed all 'unsafe-inline' script injections, ensuring full compatibility with strict security policies.

Fixed

  • Stream Redirection & Cookie Handling: Improved robustness and predictability of stream reading in server-function proxies by switching to a line-by-line (\n delimited) streaming command parser, eliminating regex-based tag extraction.

Active community

Hello, my community is low at the moment. It has 10 Github stars (https://github.com/roggc/dinou). I've been the only one publishing posts and articles about Dinou. You can see them by searching on Google: "dinou" react framework.
Thank you.

Clear onboarding

https://dinou.dev/docs/getting-started

There are two options. One is using the command: npx create-dinou@latest my-app. Then you should do cd my-app and npm run dev and you are ready to start developing.

The other way is manually:
1- mkdir my-app
2- cd my-app
3- npm init -y
4- npm i react react-dom dinou
5- mkdir src
6- Create a 'page.jsx' file inside src with a Client or Server component (RCC or RSC).

"use client"
export default function Page(){
return <div>Hi from Dinou!</div> 
}

7- Execute npx dinou dev to start developing.

Ecosystem compatibility

I am not aware right now of any library or tool that is not compatible with Dinou.

Self-hosting option

The framework runs on a standard Node.js server. Depending on whether the framework is ejected or not, a user can build and run the application on any server (such as a VPS or Docker container) using:

If not ejected and installed manually:

npx dinou build
npx dinou start

If ejected or installed with the command 'npx create-dinou@latest my-app':

npm run build
npm run start

Under the hood, the production server launches a standard Node.js/Express architecture (./dinou/core/server.js) using the --conditions react-server flag and a custom module loader to handle React Server Components natively.

For flexibility, the framework officially supports three different bundlers for the build process: esbuild, Rollup, and Webpack (npm run build:rollup, etc).

Limitations to features when self-hosting
None. Every feature works fully when self-hosted, including Server-Side Rendering (SSR) and React Server Components (RSC). There are no cloud or third-party dependencies.

Whether you require a server to deploy the framework
Yes. A Node.js runtime server is required to execute the production backend and handle server-side rendering.

Example of the package.json scripts section of a project made with Dinou when it is ejected (npm run eject):

  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "dev": "npm run dev:esbuild",
    "build": "npm run build:esbuild",
    "start": "npm run start:esbuild",
    "dev:rollup": "concurrently \"npm run dev:express\" \"npm run dev_rollup\"",
    "build:rollup": "cross-env NODE_ENV=production rollup -c ./dinou/rollup/rollup.config.js",
    "start:rollup": "cross-env NODE_ENV=production node --conditions react-server --import ./dinou/core/register-loader.mjs ./dinou/core/server.js",
    "dev:webpack": "concurrently \"npm run dev:express:webpack\" \"npm run dev_webpack\"",
    "build:webpack": "cross-env NODE_ENV=production webpack --config dinou/webpack/webpack.config.js",
    "start:webpack": "cross-env NODE_ENV=production DINOU_BUILD_TOOL=webpack node --conditions react-server --import ./dinou/core/register-loader.mjs ./dinou/core/server.js",
    "dev:express": "node --conditions react-server --import ./dinou/core/register-loader.mjs ./dinou/core/server.js",
    "dev_rollup": "rollup -c ./dinou/rollup/rollup.config.js -w",
    "dev_esbuild": "node dinou/esbuild/dev.mjs",
    "dev:esbuild": "concurrently \"npm run dev:express\" \"npm run dev_esbuild\"",
    "dev_webpack": "webpack serve --config dinou/webpack/webpack.config.js",
    "dev:express:webpack": "cross-env DINOU_BUILD_TOOL=webpack node --conditions react-server --import ./dinou/core/register-loader.mjs ./dinou/core/server.js",
    "build:esbuild": "cross-env NODE_ENV=production node dinou/esbuild/build.mjs",
    "start:esbuild": "cross-env NODE_ENV=production node --conditions react-server --import ./dinou/core/register-loader.mjs ./dinou/core/server.js"
  },

Developer Experience

Fast Refresh has been implemented when developing using esbuild (npm run dev) and Rollup (npm run dev:rollup), but not when doing it with webpack (npm run dev:webpack), because it is strange somebody wants to develop with webpack because it is slow. React Compiler has been implemented in Rollup (dev and build), Webpack (dev and build) and esbuild (build).

User Experience

Dinou is a lightweight, full-stack React 19 framework that enables developers to build high-performance, responsive applications. It integrates React Server Components (RSC), Server Actions/Functions, and streaming SSR out-of-the-box, allowing developers to target different bundlers (Esbuild, Rollup, or Webpack).

A key architectural feature of Dinou is its complete ejectability: developers can run npm run eject to copy the entire build pipeline, compiler configurations, and runtime server core directly into their local codebase for total, custom control and modification, though it can also be used out-of-the-box as a standard, unejected npm dependency.

📂 Advanced Routing & Nested Layouts

  • File-System Conventions (page.tsx & page_functions.ts): Routes are defined by the folder structure containing a page component file (supporting .tsx, .jsx, .ts, or .js). Folders can also declare a page_functions file to export route-level logic, including data load properties (getProps), dynamic paths (getStaticPaths), and rendering settings (dynamic bailouts and revalidate timers).
  • Dynamic Segments: Dinou features a robust file-system based router supporting single parameters ([id]), optional parameters ([[id]]), catch-all segments ([...slug]), and optional catch-all segments ([[...slug]]).
  • Zero-I/O Memory Mapping: To prevent disk bottlenecks during route resolution under load, Dinou maps the entire routing structure into an in-memory Virtual File System (VFS) at server startup. In production, layout matches and file checks resolve instantly in $O(1)$ time from memory.
  • Persistent Layouts & Parallel Slots: Nested layouts (layout.tsx) and route groups ((group)) ensure UI shells remain persistent during navigation. Layouts can render parallel route slots (prefixed with @) into independent React Server Component subtrees.
  • Soft Navigation & Prefetching: The custom <Link> client component intercepts standard anchor clicks to perform soft navigation. It supports background prefetching on hover (onMouseEnter), pre-loading assets before the user clicks to guarantee instant transitions.
  • Transition-Aware Navigation: Under the hood, Dinou wraps client-side transitions inside React 19's native useTransition / startTransition. This keeps the current page fully interactive and prevents intermediate page flicker or blank screens while the target route is loading in the background.
  • Isomorphic Routing Hooks: Hooks like usePathname() and useSearchParams() are fully isomorphic. During Server-Side Rendering (SSR), they read context directly from the server's local thread storage (getContext()), preventing client/server hydration mismatches. Transition loading states can be queried via useNavigationLoading().
  • Universal Redirection & Suspense Control: The redirect(destination) utility dynamically performs a native HTTP 307 redirect if headers are not yet sent. In client-side navigation or open streams, it renders a <ClientRedirect> component that triggers browser navigation and suspends the current React render tree (throw new Promise(() => {})) to prevent flashing intermediate screens.
  • Granular Error Isolation & Error Pages: Dinou supports folder-level error boundaries (error.tsx). If a route slot or page fails, Dinou catches the crash, passes the serialized trace to the matching error component, and keeps the rest of the application fully interactive.
  • Custom Not Found Pages (not_found.tsx): If a URL is unmatched, Dinou crawls the route tree to render the closest parent not_found.tsx page. This supports layouts, custom preprocessing properties via page_functions.js, and local layout bypassing using no_layout_not_found controls.
  • Route Controls: Developers can use no_layout and reset_layout files to break layout inheritance locally.

✂️ Component-Level Code-Splitting

  • Automatic Detection: During compilation, Dinou scans components and extracts those marked with the "use client" directive along with their local dependencies.
  • Browser Chunks: Client components are compiled into separate, hashed ESM browser chunks.
  • React Client Manifest: A generated manifest maps component exports to their respective chunk URLs. The browser only downloads and hydrates the minimal JavaScript bundle required when interactive components are loaded on the page.

⚡ HTML Generation & Process-Isolated Streaming SSR

  • Isomorphic Execution: Dinou resolves and executes synchronous and asynchronous Server Components (async/await) directly on the server during the HTML generation phase. It traverses the React element tree and resolves component functions into static HTML and Client hydration placeholders.
  • Streaming SSR: Dinou uses React 19's renderToPipeableStream to stream HTML chunks to the browser immediately, letting Suspense boundaries render skeletons while slow components load.
  • Process-Isolated Execution (RSC vs. SSR Environment): Because React 19's server runtime (under the --conditions react-server flag) is incompatible with client-side DOM rendering (react-dom/server) in the same execution context, Dinou runs them in two distinct processes. The parent process handles RSC compilation under the server flag, while a spawned child process (forked without the flag) handles the HTML stream generation (react-dom/server).
  • Streaming Context Bridging (IPC): If a Server Component sets a cookie or redirects after the HTML stream has started, the child process sends an IPC message to the parent Express server. The parent then injects browser-side execution scripts (e.g., <script>document.cookie = "...";</script>) directly into the active HTML stream, updating the client without raising server-side "headers already sent" exceptions.

🔄 Data-Fetching & Waterfall Prevention

  • Server-Side Rendering (RSC): Data fetching is performed directly inside asynchronous Server Components using async/await. Database and API queries execute close to the source before generating HTML, eliminating client-server network waterfalls.
  • Secure Server Functions: Interactive client elements can invoke server-side operations ("use server") using secure Server Functions. These functions can return standard data or return fully serialized React component trees (representing either Client or Server Components) directly to the browser. Calls are verified against CSRF origin checks and AST-verified export lists to block unauthorized function execution.
  • Unified Layout & Page Preprocessing: Developers can place a page_functions.js (with a shared getProps function) at any route folder. When a route is matched, the server executes getProps once to resolve the data for both the root layout and the page component in a single pass before rendering starts. This allows developers to fetch all required database and API queries concurrently (e.g., via Promise.all inside getProps), preventing layout-to-page rendering waterfalls.

🌐 Smart Hybrid Rendering (SSG, SSR, & ISG/ISR)

  • Bailout Detection via Proxy Spies: At production startup, Dinou inspects pages using Proxy objects to intercept request context (cookies, headers, queries). If a page reads dynamic request context during this phase, it bails out from static compilation.
  • IPC-Bridging via RSC Tree Serialization (SSG): For static-eligible routes, the parent process serializes the resolved React element tree into a custom JSON format at server startup. To compile the final files, this JSON is passed to the child process, which deserializes the tree in its own environment (resolving and loading modules in the process via React.createElement). This ensures the final static HTML (index.html) and RSC payload (rsc.rsc) files are written to disk (dist2) with complete data consistency, requiring zero database re-execution.
  • Dynamic Rendering Path (SSR & RSC Streaming): Dynamic routes that bailed out from static generation are rendered on-demand: serving full Server-Side Rendering (SSR) HTML for initial browser loads and reloads, while delivering dynamic, raw RSC stream payloads (text/x-component) for client-side navigation transitions.
  • On-Demand Incremental Static Generation (ISG): When a dynamic route is successfully requested via SSR (status 200), Dinou hooks into the response finish event to run generatingISG in the background. It test-renders the route with the Proxy Spies; if it is static-eligible, Dinou compiles and writes the HTML and RSC files to the dist2 folder, automatically promoting the route to static so all future requests serve static files directly from disk.
  • Background Revalidation (ISR): Expired static pages serve stale content instantly while a background promise runs buildStaticPage to regenerate the static HTML and RSC files.
  • Atomic File Promotion: Background builds write output to temporary .tmp files first and use transactional safe-rename operations to publish them, preventing file corruption under concurrent traffic spikes.

Compatible with our future vision for React

Dinou is designed to align with React's vision of using Server Components (RSC) and Server Functions as the standard foundation for modern full-stack applications.

🚀 Future Integration & Evolvability

  • Native React 19 APIs: Dinou relies directly on standard rendering tools (renderToPipeableStream and react-server-dom-webpack). It uses no custom abstraction wrappers, ensuring compatibility with future React engine updates.
  • Minimal & Ejectable Core: The framework core is small and fully ejectable, giving developers direct access to compilers and custom ESM loaders. This makes it easy to integrate new React features (like the React Compiler) immediately.
  • Alternative Hosting Environments: Dinou demonstrates that RSC can run on lightweight, standard Express servers, contributing to ecosystem diversity.

🪄 Granular Reactivity: The "Dinou Pattern" (https://dinou.dev/docs/pattern & https://dinou.dev/docs/data-fetching)

Dinou implements a clean state-mutation model using Server Functions that return Client Components:

  • UI-Returning Server Functions: Server Functions can run database mutations and directly return React Client Components.
  • Headless State Updaters: After a mutation, the Server Function returns a "Headless State Updater" Client Component. When mounted, it updates global state atoms (e.g., Jotai) and resets interaction flags.
  • Granular Re-fetching: By combining the updater with react-enhanced-suspense, data-fetching Server Functions are bound to a declarative resourceId (cache key). When the state updates, only the affected Suspense boundary re-fetches its data from the server, preventing full page reloads and reducing network payloads.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions