Frontend Development 22 min read

Design and Implementation of Ctrip's New Homepage: Island Architecture, Component Development, and Data Configuration System

The article presents a comprehensive case study of Ctrip's 2022 PC homepage redesign, detailing the motivations, requirement analysis, island‑style architecture, cross‑team component development, server‑side rendering, public component challenges, and the dynamic data‑configuration platform that together enable fast, maintainable, and scalable web delivery.

Ctrip Technology
Ctrip Technology
Ctrip Technology
Design and Implementation of Ctrip's New Homepage: Island Architecture, Component Development, and Data Configuration System

The Ctrip Frontend Framework team rebuilt the PC homepage in 2022 to address maintenance difficulty, an outdated and fragmented tech stack, and poor user experience, aiming to provide a modern, performant, and accessible web solution.

Project Background

The legacy homepage had been in use for 22 years, suffering from black‑box legacy code, inconsistent technology choices across business units, and visual‑interaction designs that no longer met user expectations.

Requirement Analysis

Key requirements included selecting a lightweight server‑side rendering (SSR) model, using Node.js as the application carrier, and standardising on React for the client side. Cross‑team collaboration was essential: business teams develop component modules, while the framework team provides build pipelines, SSR support, and deployment tooling.

Overall Architecture Design

The architecture is divided into four parts:

Business module development – each business line creates its own React component with a unique ID, CSS Modules for style isolation, and optional server‑side data fetching.

Business module build – webpack builds separate client and server bundles; the client assets (js+css) are uploaded to a static asset system.

Business module server‑side rendering – a sandbox executes the server bundle, stores the rendered HTML and data in Redis, and exposes a cloud‑function for on‑demand rendering.

Application page assembly – a scheduled job pulls component HTML from Redis, assembles the full homepage, and serves the cached HTML to users.

Core Functional Implementations

Component Development Environment

A CLI wraps webpack and Babel configurations, enforces CSS Modules, and generates both client and server entry files. The client entry renders the component with data received from the server:

import React from 'react'
import ReactDOM from 'react-dom'
import Comp from '__COMP_PATH__'

const render = async () => {
  let data
  const container = document.getElementById('__MFE___MODULE___DATA__')
  if (container && container.textContent) {
    try { data = JSON.parse(container.textContent) } catch (e) { console.log(e) }
  }
  const root = document.getElementById('__MODULE__')
  if (module.hot) {
    ReactDOM.render(
, root)
  } else {
    ReactDOM.hydrate(
, root)
  }
}
render()

The server entry fetches initial props, stores data via setMfeData , and returns the rendered string:

import React from 'react'
import { renderToString } from 'react-dom/server'
import Comp from '__COMP_PATH__'

const render = async () => {
  let data
  if (Comp.getInitialProps) { data = await Comp.getInitialProps(_ctx) }
  setMfeData(data)
  return renderToString(
)
}
export default render()

SSR Service (Sandbox Execution)

const vm = require('vm')

const render = async ({content, request}) => {
  const script = new vm.Script(content)
  const moduleObj = {exports: {}}
  const sandBox = {
    ...global,
    process,
    require,
    module: moduleObj,
    console,
    _ctx: {req: {url: request.rawPath, query: request.queryStringParameters, headers: request.headers}, env: 'prod'},
    setMfeData: data => { mfeData = data }
  }
  const ctx = vm.createContext(sandBox)
  script.runInContext(ctx)
  const comp = await sandBox.module.exports.default
  return {comp, mfeData}
}

Page Assembly

let indexCache = ''
const renderPage = async (content) => {
  const $ = cheerio.load(content)
  for (let module of modules) {
    try {
      let data = moduleData[module] || ''
      if (!data) continue
      data = typeof data === 'string' ? JSON.parse(data) : data
      const {comp, version, mfeData, style} = data
      parse(module, comp, $, version, mfeData, style)
    } catch (e) { console.log(e) }
  }
  const payload = $.html()
  if (!payload) throw Error('renderPage error - html is null')
  indexCache = payload
}

Public Component Challenges and Solutions

Different business units use varied stacks (Java, Node, React, Vue, jQuery). The solution is to ship a lightweight Preact bundle that can run in any environment and be aliased to React for compatibility.

Hot‑update of public components without affecting business pages – components are packaged as Node.js jobs that periodically push HTML to Redis; client pages fetch the latest HTML on each request.

Style isolation – CSS Modules prevent leakage, and a fixed‑position left menu is wrapped in a dedicated container to avoid interfering with existing page layouts.

Performance – a skeleton placeholder is rendered first, then the actual component HTML is fetched asynchronously; multiple component JS bundles are merged with a shared Preact runtime.

Dynamic Data Configuration System

To separate code deployment from data updates, a management platform was built consisting of a frontend application for uploading JSON configuration files and a Node.js service that validates, stores, and publishes the data to QConfig. The system provides:

Schema definition for each component (via manual entry or uploaded .d.ts files).

Automatic validation of uploaded JSON against the schema.

Preview of the component and full page using the latest data, pulling other components' HTML from Redis.

Versioned publishing that updates only the data, leaving component code untouched.

The preview workflow runs the SSR service in a sandbox, merges the component HTML with production HTML of other modules, and returns the assembled page for visual verification.

Conclusion

The case study demonstrates an island‑style architecture for a large‑scale homepage, covering component development, cross‑team collaboration, SSR implementation, hot‑update mechanisms, and a dynamic data‑configuration platform, offering practical insights for similar component‑centric web projects.

frontendreactNode.jscomponent architectureServer-side Renderingdata configurationIsland Architecture
Ctrip Technology
Written by

Ctrip Technology

Official Ctrip Technology account, sharing and discussing growth.

0 followers
Reader feedback

How this landed with the community

login 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.