How to Build an Extensible Page Builder with Component Replacement and State Sharing
This article explains the challenges of scaling a page‑building editor, proposes three architectural solutions, and details a design that enables fine‑grained component replacement and shared internal state through a global model, middleware, and extensible plug‑in mechanisms.
Background
Large‑scale business operations rely on complex page creation, such as on Taobao, where numerous pages support various marketing scenarios. A "page building system" was abstracted to handle this, and Tianma's service provides the building capability via an API. However, API‑only integration leaves significant front‑end work for clients, prompting the creation of a unified building editor (version 1.0).
While version 1.0 meets most needs, new business scenarios demand additional features, such as pre‑publish review, removal of irrelevant configurations, and selective reuse of editor capabilities.
Introduce a review workflow before publishing.
Allow minimal data configuration (e.g., only an image) in specific contexts.
Reuse only parts of the editor, such as custom page editing and publishing flow.
Three solution paths were considered:
Clients develop a completely new editor.
We extend the existing editor with branching logic for each scenario.
We split the editor into fine‑grained components for selective use.
Approach 1 leads to duplicated effort and maintenance overhead. Approach 2 results in ever‑growing conditional code that becomes hard to maintain. Approach 3 adds component maintenance costs and requires clients to understand internal data flows, offering limited value.
Goal: Find a solution that lets clients quickly customize without dismantling existing components.
We identified that clients want to use about 80% of the editor’s capabilities while extending the remaining 20% for custom rendering logic and data access.
Two Design Ideas
Extensible Architecture
All clients interact with the same backend services provided by Tianma. Inspired by VS Code extensions, we propose making the editor extensible: core page‑building functions remain stable, while clients add capabilities via extensions. The editor acts as a component container where each child component registers itself.
Component registration example:
{
name: 'ComponentName',
component: 'ComponentInstance'
}Component Data State Sharing
Traditional Redux shares state among child components via a common parent, but sharing state directly between two independent business components is difficult. We aim for a mechanism where each component maintains its own internal state yet can access each other's state when needed.
Implementation steps follow.
Design Implementation
Step 1: Core Build Process Overview
Define a build flow: create page → select build type → enter editor → build page → data injection → publish. Currently, module building is the core process.
Step 2: Editor Layer Design
The editor is split into UI and Data layers.
UI
Header: page‑level actions such as settings and publishing.
Editor: core editing area, including plugins, preview, module management, and data configuration.
Data
Model: global state management.
Step 3: Model Layer Design
Previously, state was passed via props between components. To decouple, we introduce a global model that centralizes state.
The model is divided into four categories:
Global configuration
Module operations
Page operations
Plugin related
Step 4: Support Internal Component Replacement
We define an interface for injectable components and a registration function to map component names to implementations, allowing both npm‑based and remote CDN modules.
interface IInjectComponent {
name: string; // unique component name
component?: React.ComponentType | string; // replacement component
} function registerComponent(props: IInjectComponent | IInjectComponent[]) {
// replace component mapping
}Usage example:
function InjectComponent(props) {
const { name, defaultComponent, ...otherProps } = props;
const component = getComponent(name) || defaultComponent;
if (isRemote(component)) {
return <MicroModule url={component} {...otherProps} />;
} else {
return React.createElement(component, otherProps);
}
}
registerComponent({ name: 'publish-component', component: PublishComponent });Step 5: Share Business Component Internal State
We expose component state via a global singleton store with namespace‑based registration and retrieval.
// Register model
export default registerModel(ModuleA, { name: 'ComA-ModuleA' }); // Consume in extension component
function ExtCom() {
const comAModelA = useModel('ComA-ModuleA');
console.log(comAModelA.state1);
// ...
}Step 6: Middleware‑Based Local State Modification
For minor UI tweaks (e.g., changing a button label) we introduce a middleware that intercepts props before rendering.
// Original button usage
function App() {
return <Button text="发布" />;
}After injection:
<InjectComponent name="publish-button" component={Button} text="发布" />The middleware adjusts props to produce the desired label without rewriting the component logic.
Step 7: Generalizable Extensible Component Solution
By wrapping any component with
<InjectComponent name="ComponentName" defaultComponent={DefaultComponent} {...defaultProps} />, developers can quickly add extensibility to existing business components.
Future Work
Current limitations include bundled default components increasing bundle size, lack of a VS Code‑like extension ecosystem, and the need for on‑demand component packaging. We plan to integrate the solution into the Ice ecosystem and open‑source it.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Taobao Frontend Technology
The frontend landscape is constantly evolving, with rapid innovations across familiar languages. Like us, your understanding of the frontend is continually refreshed. Join us on Taobao, a vibrant, all‑encompassing platform, to uncover limitless potential.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
