Working with Generated React Code
WaveMaker allows applications to be exported as a standard React (Next.js) project, producing a complete frontend codebase that follows modern React and Next.js conventions while preserving WaveMaker’s runtime engine, data bindings, and page composition model. The generated code aligns with React best practices and is structured to be modular, maintainable, and production ready, while accurately reflecting the UI, logic, and data bindings defined in WaveMaker Studio.
The exported project includes a fully configured Next.js application with TypeScript support, environment configuration, static assets, page modules, and WaveMaker runtime wiring. This enables teams to work with a familiar React ecosystem while continuing to benefit from WaveMaker’s low-code page composition and service binding model.
Key characteristics of the generated React code include:
-
Component Based Page Architecture: Each WaveMaker page is generated as a self-contained React page module, typically organized under react-pages/ with the following structure:
- A routing entry (
page.tsx) to integrate with Next.js navigation - A React component file (
[PageName].component.tsx) that defines the page’s UI layout - A page-specific stylesheet (
[PageName].css) - A script/controller file (
[PageName].script.js) for page behavior and lifecycle hooks - A variable definition file (
[PageName].variable.ts) for page state, service bindings, and data flow
This structure enforces a clear separation of concerns between UI layout, styling, behavior, and data, making individual pages easier to maintain, test, and evolve independently without impacting unrelated parts of the application.
- A routing entry (
-
WaveMaker Runtime Integration with React: The generated React components are not plain React components; they are bound to the WaveMaker runtime. The runtime layer manages:
- Page lifecycle (initialization, ready state, teardown)
- Two-way data binding between UI components and variables
- Service invocation and response mapping
- Navigation and event wiring
This allows React to serve as the rendering framework while WaveMaker continues to control page composition, data flow, and interaction patterns defined in Studio.
-
Security & Performance Optimizations: The exported React application leverages Next.js production features and standard frontend optimizations.
- Route-level rendering via Next.js for optimized page loading
- Tree-shaking and code-splitting during production builds to reduce bundle size
- Static asset optimization for images and public files
- Environment-based configuration using .env for separating development and production settings
These practices ensure the generated React app is secure, performant, and suitable for enterprise grade deployments.
-
Deployment Ready Frontend Output: The React project compiles into standard static and server-rendered assets (depending on Next.js configuration), making it suitable for:
- Hosting on traditional web servers
- Deployment on CDNs
- Integration into CI/CD pipelines
- Containerized deployment environments
This allows the exported frontend to fit seamlessly into modern DevOps workflows and frontend deployment pipelines, similar to hand crafted React/Next.js applications.
Steps to Export a WaveMaker Project as React ZIP
- Open your project in WaveMaker Studio Make sure the project you want to export is loaded and ready.
- Click on “Export Project” This opens the export options menu.
- Select “Project as React ZIP” Choose the option to export your application as an React source bundle.
- Confirm the Export Job A dialog appears saying the export job has been created (Click OK to proceed)
- Open Project Notifications Click the Project Notification icon to view background jobs.
- Navigate to the Jobs Tab In the popup, go to the Jobs tab to see export progress.
- Find the Export Job Locate the job related to “React ZIP export”.
- Download the React ZIP Click the Download button for the completed job.
Understanding the WaveMaker React Project Structure
When you export a WaveMaker application as a React ZIP, you get a standard React (Next.js + TypeScript) project with WaveMaker-specific runtime, page composition, and build layers on top.
The exported project follows modern React and Next.js conventions while preserving WaveMaker’s low-code model for UI composition, event handling, and data binding. This allows teams to work in a familiar React ecosystem without losing the productivity benefits of WaveMaker Studio.
Documentation-react-app/
├─ .build/ // Used for internal build metadata.
|
├─ .env // Environment variables (API URLs, secrets, runtime configs)
|
├─ .npmignore // Files to exclude when publishing package (if used as lib)
|
├─ .prettierrc // Code formatting rules for consistent styling across the team
|
├─ README.md // Project documentation and setup instructions
|
├─ next-env.d.ts // Next.js TypeScript environment definitions (auto-generated)
|
├─ next.config.ts // Next.js configuration Controls routing, builds, environment variables, etc.
|
├─ package.json // Project metadata + dependencies + scripts (npm run dev/build)
|
├─ package-lock.json // Locked dependency versions (auto-generated)
|
├─ tsconfig.json // TypeScript compiler configuration
|
├─ app // Main application source code
│ ├─ _app.tsx // Root React wrapper component.
│ ├─ app.css // Global CSS styles for the entire application
│ ├─ app.script.js // Wavemaker runtime bootstrap file
│ ├─ (other generated folders/files) // Pages, Components, Services, Variables, Routes
│ ├─ react-pages
│ ├─ page.tsx // Page Router / Entry Wrapper (Registers the page with Next.js routing)
│ ├─ [PageName].component.tsx // Main UI Layout (actual React component for your page UI)
│ ├─ [PageName].css // Page Level Styling (CSS scoped to this page)
│ ├─ [PageName].script.js // Page Logic & Events (page specific JavaScript logic)
│ ├─ [PageName].variable.ts // Page State & Data Binding (page level state & variables)
│
├─ public
│ └─ Static assets (served directly by the web server)
│ ├─ Readme.txt // Static assets info
│ ├─ files // Public downloadable files (PDFs, docs, exports)
│ ├─ i18n // Localization files
│ │ └─ en.json // English translations for UI labels and messages
│ └─ images // UI branding assets
│ ├─ imagelists // Default UI images
│ └─ logos // App branding
WaveMaker Page Component Structure
In a WaveMaker React export, each WaveMaker page is generated as a standalone React component. All the UI, logic, state, and bindings for a page are split across multiple files to separate concerns and make customization safer.
Files Generated for Each WaveMaker Page
Each wavemaker page (for example: Main/) contains the following files:
- Main.component.html Contains the HTML template for the page (All WaveMaker components and layout definitions are rendered here)
- Main.component.css Holds page specific styles
- Main.component.script.js Intended for developer written JavaScript logic
- Main.component.ts Declares the React component for the page (Wires together template, styles, variables, and expressions)
- Main.component.variable.ts Contains all WaveMaker generated page variables
- Main.component.expression.ts Contains auto generated expression logic (🚫 Do not edit manually)
This modular structure helps keep presentation, behavior, expressions, and state management cleanly organized.
Generated React Markup of WaveMaker Page
<React.Fragment>
<WmPage name="page" pagetitle="Users" data-widget-id="widget-id81" iswidget="false" >
<WmHeader iswidget="false" content="header" name="header" data-widget-id="widget-id82">
<Header onRender={(partialContext: any) => {
fragment.Widgets["header"] = partialContext;
}} />
</WmHeader>
<WmContent iswidget="false" data-role="page-content" role="main" name="content" data-widget-id="widget-id83" >
<WmLeftPanel iswidget="false" columnwidth={2} content="leftnav" name="leftpanel" data-widget-id="widget-id84">
<Leftnav onRender={(partialContext: any) => {
fragment.Widgets["leftpanel"] = partialContext;
}} />
</WmLeftPanel>
<WmPageContent columnwidth={10} name="pagecontent" data-widget-id="widget-id85" iswidget="false" >
<WmContainer direction="column" alignment="top-left" gap="4" name="container1" variant="default" wrap={false} data-widget-id="widget-id86" styles={{"width":"100%"}} className='app-container-default' ></WmContainer>
</WmPageContent>
</WmContent>
<WmFooter iswidget="false" content="footer" name="footer" data-widget-id="widget-id95">
<Footer onRender={(partialContext: any) => {fragment.Widgets["footer"] = partialContext;}} />
</WmFooter>
</WmPage>
</React.Fragment>