Unlocking No‑Code Platform Power: Inside the Frontend Canvas Architecture
This article explores how No‑Code & Low‑Code (NCLC) platforms transform frontend development by introducing a canvas‑editor and generator architecture, UIDL communication, IOC modular design, layered rendering, event systems, drag‑and‑drop mechanics, smart snapping, and component insertion techniques.
What Is a Building Platform
Before discussing building platforms, the concept of NCLC (No Code & Low Code) must be introduced, as it drives many recent technology waves. Products such as Meego, Retool, and Notion exemplify NCLC, and the most rapidly growing form is website‑building platforms like Dreamweaver, Webflow, and various domestic solutions.
Development efficiency: Building platforms replace traditional coding with component drag‑and‑drop and configuration, dramatically reducing the time to create activity pages, promotional sites, or back‑office tools.
Staff transformation: They enable non‑technical staff, especially operations personnel, to build pages without developer involvement, lowering resource waste and improving workflow efficiency.
Derived Concepts
The platform can be summarized as Editor (canvas + settings) + Generator , where the data source is “materials” and communication follows the UIDL protocol.
Editor renders front‑end material on the canvas and produces a UIDL specification.
Generator consumes UIDL and, based on predefined templates, produces the final page.
This layered design decouples the page type from the used materials.
Architecture Design
IOC Architecture
All functional modules are coupled via an IOC container. Each module declares its usage contract, and the container injects dependencies at runtime, allowing independent iteration and easy adaptation to new terminals such as TV or mobile.
Edit‑Render Layering
The canvas is split into a render layer and an edit layer, communicating through a protocol. The edit layer hosts the real DOM elements; the render layer is a mask of virtual elements that enables instant preview and clean interaction.
When a user selects a component, anchor points appear on the render layer, while actual edits occur on the edit layer.
<code>interface ComponentAddAction {}
interface ComponentDragAction {}
// ... other action interfaces
</code> <code>interface ComponentFocusRenderer {}
interface ComponentMirrorRenderer {}
// ... other renderer interfaces
</code>To keep the edit and render layers synchronized, the
resizeand
scrollevents trigger re‑rendering of the render layer.
Event System
The platform defines a comprehensive event system that maps each editor action (init, dragEnd, etc.) to lifecycle callbacks, allowing modules to consume events for loading materials, rendering schemas, or handling drag‑and‑drop.
Specification Design
UIDL Specification
UIDL: a structured description of all UI‑related information needed to build a page.
UIDL consists of four parts:
UIDL meta information (version, etc.)
Project meta information (id, title, author, etc.)
Page Schema – a tree of component instances
Materials and their configuration
<code>interface ComponentProps {
id: string;
[key: string]: any;
}
interface Schema {
id: string;
type: MaterialId;
name: string;
children: Schema[];
props: ComponentProps;
}
interface UIDL {
meta: { version: string };
project: { id: string; title: string; version: string; author: User; url: string };
schema: Schema;
materials: { components: Component[] };
}
</code>Material Specification
Materials describe the reusable building blocks. They are categorized by terminal (mobile web, mini‑program, TV), shape (component, plugin, action), and function (basic, container, interactive).
Canvas Design
The canvas addresses three core challenges: adding components, dragging components, and selecting components.
Adding Components
When a component is added, a Schema node is generated and later inserted into the UIDL. The generation parses the component’s settings and produces a node like:
<code>genSchema(component: ComponentMaterial): Schema {
const children: Schema[] = [];
const props = {};
const styles: React.CSSProperties = SchemaService.defaultStyles;
return {
id: this.genComponentId(),
type: component.id,
name: component.name,
props,
children,
styles,
};
}
</code>Materials are loaded lazily; only the needed material bundle is fetched, reducing initial load time.
Packaging Standards
Four module formats are compared (AMD, CJS, ESM, UMD). Modern frontend development favors ESM for its standardization and bundler support.
Material Loading
SystemJS is recommended for loading modules because it supports AMD, ESM, and CJS, and integrates well with modern bundlers.
Dependency Analysis
Materials may depend on base frameworks (e.g., React), specific libraries (e.g., xg‑player), or other components. Common frameworks are treated as shared dependencies and are not bundled with each material.
Sandboxing
Each material runs in a sandbox to avoid interference. Logical isolation can use
evalor
Functionwith a proxy window; style isolation can use CSS modules, styled‑components, or Shadow DOM.
<code>const varBox = {};
const fakeWindow = new Proxy(window, {
get(target, key) { return varBox[key] || window[key]; },
set(target, key, value) { varBox[key] = value; return true; }
});
const fn = new Function('window', code);
fn(fakeWindow);
</code>Dragging Components
A drag library must emit three phases: mouse down (start), mouse move (drag), mouse up (end). It provides position, direction, distance, and boundary scrolling information.
During dragging, a mirror component is rendered to give immediate visual feedback.
<code>let componentMap = {};
let mirror = { move: xxx, destroy: xxx };
onMouseDown = (e) => {
const schema = genSchema(e);
loadComponent(schema);
mirror = renderMirror(schema);
};
onMouseMove = (e) => { mirror.move(e); };
onMouseUp = (e) => { mirror.destroy(); };
</code>Anchor points (8 per component) allow resizing; each anchor manipulates a subset of the component’s rect (width, height, left, top).
<code>const pointList = ['t','r','b','l','lt','rt','lb','rb'];
const genPointStyle = (point) => {
// calculate style based on point and component geometry
};
</code>Smart Snapping
Three snapping types improve placement precision:
Position snapping: aligns edges when the distance is within a small threshold (≈3 px).
Distance snapping: matches existing margins between components.
Size snapping: aligns width/height when the size difference is within tolerance.
Reference lines are drawn on the canvas to visualize the snap.
Selecting Components
After a component is selected, an event provider dispatches actions without modifying the component itself. Quick operations include delete, copy‑paste, cut, inline text editing, and rotation.
<code>function withEventProvider<P>(Component: React.ComponentType<P>) {
const Wrapped: React.ComponentType<P> = (props) => (
<div style={{display:'contents'}} onClick={e => console.log(e, props)}>
<Component {...props} />
</div>
);
const name = Component.displayName ?? Component.name ?? 'Unknown';
Wrapped.displayName = `withEventProvider(${name})`;
return Wrapped;
}
</code>Multi‑select allows users to drag a rectangular area, automatically computing the minimal bounding box of all fully contained components and enabling batch move or resize.
<code>let startPoint = null;
const area = { width:0, height:0, x:0, y:0 };
onMouseDown = e => { startPoint = new Point(e); };
onMouseMove = e => {
area.width = Math.abs(e.x - startPoint.x);
area.height = Math.abs(e.y - startPoint.y);
area.x = Math.min(e.x, startPoint.x);
area.y = Math.min(e.y, startPoint.y);
};
</code>Conclusion
The canvas is the core of a building platform, handling component addition, drag‑and‑drop, smart snapping, insertion, and selection. Future articles will cover the settings panel and generator.
Watermelon Frontend Tech Team
We are from ByteDance, the frontend division of Watermelon Video, responsible for its product development. We share business practices from the product to provide valuable experience to the industry, covering areas such as marketing setups, interactive features, engineering capabilities, stability, Node.js, and middle‑back office development.
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.