Technical Architecture and Design of a Landing Page Editor

The article details the technical architecture and design of the StarCreate landing‑page editor, describing its monorepo structure, low‑code JSON template, backend permission system, canvas implementation choices, Valtio state management, and the resulting operational benefits and future expansion plans.

DeWu Technology
DeWu Technology
DeWu Technology
Technical Architecture and Design of a Landing Page Editor

Building a landing‑page editor for advertising requires coordination across multiple teams and a clear technical architecture. The article describes the design and implementation of the "StarCreate" editor, which closes the loop between ad creation and delivery.

1. Architecture Overview – The system consists of an application layer, a B‑end editor SDK, a C‑end Node rendering layer, and a data‑service layer built on nest.js. A monorepo managed with pnpm and turbo hosts three entry points: SSR, the Node backend, and the H5 editor.

2. Basic Framework – Shared utilities and common logic are placed in shared packages, allowing developers to add a new component once and reuse it across Node and H5 projects without launching multiple services during local development.

3. Template JSON Design

The editor uses a low‑code JSON protocol with four main sections:

{
  // template type
  templateType: string,
  // immutable configuration
  globalConfig: {},
  // default (built‑in) configuration
  defaultConfig: {},
  // variable configuration edited by operators
  variableConfig: {}
}

These sections separate global capabilities (e.g., auto‑switching devices), default settings, and operator‑editable parameters.

4. Backend Permission Design – The Node service handles four responsibilities: ad‑builder APIs, internal HTTP calls, SSR rendering, and gateway routing. Guard middleware and custom decorators are used for user authentication and logging.

5. B‑end Editor Selection

The editor consists of a canvas, component configuration, and a toolbar. Two canvas‑preview approaches were evaluated:

Dynamic Remote Component – Components are packaged as UMD modules, uploaded to a CDN, and loaded lazily with React.lazy and Suspense. Communication uses postMessage when embedded in an iframe.

Iframe – The canvas runs in an isolated iframe, providing sandboxing, fast load times, and separate preview and production routes.

Code example for the dynamic component:

const DynamicComponent = ({name, children, ...props}) => {
  const Component = useMemo(() => {
    return React.lazy(async () => fetchComponent(name))
  }, [name])

  return (
    <Suspense fallback={<div style={{alignItems: 'center', justifyContent: 'center', flex: 1}}><span style={{fontSize: 50}}>Loading...</span></div>}>
      <Component {...props}>{children}</Component>
    </Suspense>
  )
}
export default React.memo(DynamicComponent)

Code example for preview and production routes:

// preview route
export default HocPreview(({ componentList }) => <Container componentList={componentList} />)

// production route
export default HocApp(({ componentList }: { componentList: any }) => {
  return <Container componentList={componentList} />
})

Code example for the high‑order component that wraps the iframe:

export const HocPreview = (Template) => {
  return ({ data }) => {
    const [componentList, setComponentList] = useState(data?.componentList ?? [])
    useEffect(() => {
      if (window.self !== window.top && !window.location.hash) {
        const compElemList = document.querySelectorAll('.editor-box>div>*')
        compElemList.forEach((item, index) => {
          item.addEventListener('mouseenter', () => {
            window.parent.postMessage(index, '*')
            compElemList.forEach(c => c.classList.remove('actived'))
            item.classList.add('actived')
          })
        })
      }
      window.addEventListener('message', ({ data }) => {
        setComponentList([...data])
      })
      document.querySelector('html')?.classList.add('no-scroll-bar')
    }, [])
    const handleClick = (e) => {
      if (window.self !== window.top) e.stopPropagation()
    }
    return (
      <div className="editor-box" onClickCapture={handleClick}>
        <Template componentList={componentList} />
      </div>
    )
  }
}

6. State Management – Two React state libraries were compared: Valtio (proxy‑based, fine‑grained reactivity) and Zustand (simple API, high performance). The team chose Valtio for its similarity to Vue’s reactivity model.

7. Benefits

Improved experience for ad‑operations staff.

Data collection for iterative optimization of external landing pages.

Faster rollout during peak campaigns, leading to higher conversion efficiency.

Reduced manual errors and associated losses.

8. Future Plans – Expand common capabilities of external landing pages, enhance data insight pipelines, and build a rapid‑experiment mechanism to meet business goals.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

ReactEditor Architecturelanding pageMonorepoNode.jsSSRtemplate design
DeWu Technology
Written by

DeWu Technology

A platform for sharing and discussing tech knowledge, guiding you toward the cloud of technology.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.