Frontend Overview

Table of Contents

Current Capabilities

This Frontend guide documents the current built-in Vext frontend capability: route-driven React 19 pages, SSR, hydration, nested layouts, frontend i18n, Fast Refresh, render refresh, code splitting, static assets, CDN upload, performance budgets, and hydration validation.

What Vext Frontend Is

Vext Frontend is the built-in full-stack React 19 experience for Vext projects. The URL still belongs to src/routes/**; the route handler prepares server data and calls res.render() to render a page from src/frontend/pages/**.

Use it when you want one Vext application to own API routes, services, SSR, hydration, frontend assets, and production static serving without adding a second application framework.

Use --template api --frontend none when the project is API-only.

Create a Full-stack Project

npx vextjs create my-app
cd my-app
npm run dev

The default scaffold is a full-stack React project. The frontend can still be disabled in config or created as API-only:

npx vextjs create my-api --template api --frontend none

Project Structure

src/
  routes/
    index.ts
    admin/
      dashboard.ts
  services/
    user.service.ts
  frontend/
    pages/
      index.tsx
      layout.tsx
      error/
        default.tsx
    components/
      UserCard.tsx
    styles/
      card.style.ts
      dashboard.module.css
    assets/
      logo.png
    locales/
      en-US.ts
      zh-CN.ts
public/
  favicon.svg

The important boundary is physical:

  • src/routes/** and src/services/** run on the server.
  • src/frontend/pages/** and src/frontend/components/** are bundled for the browser.
  • Do not import services, database clients, secrets, or Node-only modules from frontend files.
  • public/** is copied to the frontend output and can be published through the deploy manifest.

First Page

Create a page:

// src/frontend/pages/index.tsx
export default function HomePage(props: { greeting: string }) {
  return <main>{props.greeting}</main>;
}

Render it from a route:

// src/routes/index.ts
export default (app) => {
  app.get("/", {}, async (req, res) => {
    const greeting = await app.services.example.greeting("Vext");
    res.render("index", { greeting });
  });
};

res.render(page, props?, options?) has three arguments:

ArgumentMeaning
pagePage id under src/frontend/pages/**, without extension. admin/dashboard.tsx becomes "admin/dashboard".
propsJSON-safe server data serialized into the SSR document and reused during hydration.
optionsRendering options such as status, head, layoutData, messages, nonce, or page-specific behavior.

Reading Paths

Use the left navigation as the main map. It is intentionally split into concept, task, and reference layers.

NeedStart here
First successful pageGetting Started
Understand URL and page ownershipRouting and Pages
Choose SSR, hydration, or CSRRendering Modes
Pass service data to pagesData Flow
Build nested shellsLayouts and Components
Debug SSR outputSSR
Debug browser attach/mismatchHydration
Build a client-router sub-appCSR and SPA Fallback
Cache render dataRender Data and Cache
Tune development feedbackFast Refresh and Render Refresh
Ship frontend assetsBuild and Deploy and Static Assets and CDN
Keep JS smallCode Splitting and Performance Budgets
Validate production hydrationHydration Validation
Find config fieldsConfiguration
Check current boundariesBoundaries and Roadmap

The old Frontend integration page is kept only as a compatibility entry for existing links.