Frontend Development 15 min read

Micro‑Frontend Integration and Platformization at Bilibili: Design, Implementation, and Lessons Learned

Bilibili consolidated over thirty fragmented internal back‑ends into a unified micro‑frontend platform called Source Universe Workbench by selecting the micro‑app framework, implementing centralized routing, cross‑domain XHR interception, shared services, and observability, which streamlined user experience, eliminated duplicated infrastructure, and provided actionable insights for legacy system management.

Bilibili Tech
Bilibili Tech
Bilibili Tech
Micro‑Frontend Integration and Platformization at Bilibili: Design, Implementation, and Lessons Learned

Introduction

Bilibili has accumulated dozens of internal management back‑ends over years of growth, resulting in fragmented technology stacks, duplicated functionality, and inconsistent user experience.

Background Analysis

The team maintains more than 30 B‑side back‑ends, over 300 modules and 1,400 pages. Common pain points include repeated construction of basic capabilities (authentication, logging), independent repositories that hinder unified technical evolution, and high switching costs for users.

Goal Planning

Since 2021 the team set three technical goals: (1) unify entry points and experience, (2) provide shared platform capabilities to reduce duplication, and (3) build observability for all business services.

Overall Design – Micro‑Frontend Selection

Two popular micro‑frontend solutions were evaluated: qiankun (built on single‑spa) and micro‑app . The comparison focused on style isolation, sub‑application integration cost, and runtime performance.

Style isolation with qiankun relies on ShadowDOM, which often requires manual adaptation and can degrade user experience. Micro‑app uses CSS Modules, offering higher compatibility across first‑ and second‑party applications.

// qiankun style isolation example // Assume the app name is react16 .app-main { font-size: 14px; } // After enabling isolation div[data-qiankun-react16] .app-main { font-size: 14px; }

// micro‑app style isolation example // Before enabling isolation .ant-table table { width: 100%; } // After enabling isolation micro-app[name=app_name] .ant-table table { width: 100%; }

Both solutions provide JavaScript sandboxes; micro‑app’s Proxy‑based sandbox was chosen for its lower intrusion.

Micro‑Frontend Choice

Considering the need for minimal code changes, lossless integration of legacy back‑ends, and unified routing, the team selected micro‑app as the micro‑frontend framework.

Project "源宇宙工作台" (Source Universe Workbench)

The platform abstracts each first‑ and second‑party back‑end as an App and mounts them inside a base page containing a <micro-app> element. The workflow is:

User accesses the platform, triggering centralized routing, permission checks, and telemetry.

The base page loads the appropriate sub‑application via <micro-app> .

All XHR requests from sub‑applications are intercepted and proxied through a Node.js gateway, solving cross‑domain issues.

const router = createRouter({ history: createWebHistory((window.__MICRO_APP_BASE_ROUTE__ || '') + '/'), routes: getRoutes(), }); // Access sub‑app window from the base app console.log(window.__MICRO_APP_PROXY_WINDOW__.__MICRO_APP_BASE_ROUTE__); // Prints '/live-app/bchat'

Legacy URLs are preserved via a redirect script:

<% if(NODE_ENV === 'production'){ %> <% } %>

Cross‑Domain Handling

Simple CORS is handled by adding Access‑Control‑Allow‑Origin headers on the SLB. Complex CORS (JSON payloads, custom headers, PUT/DELETE) is resolved by routing requests through a Node.js gateway that performs pre‑flight handling and forwards the call.

XHR Interception via ajax‑hook

The gateway intercepts sub‑application XHR using the ajax‑hook library, completing relative URLs and optionally proxying to the backend:

import { proxy, unProxy } from "ajax-hook"; microApp.start({ lifeCycles: { beforemount(app) { proxy({ onRequest(config, handler) { // Complete relative URLs if (!/^f(ile|tp):\/\/.test(config.url)) { config.url = createURL(config.url, addProtocol(appConfig?.url)).toString(); } if (appConfig?.is_proxy_intercept) { // Proxy to gateway handler.next({ url: '/nb/mapi/proxy/call', method: 'POST', headers: { 'content-type': 'application/x-www-form-urlencoded' }, body: qs.stringify({ real_url: config.url, method: config.method, params: config.body, }) }); } else { handler.next(config); } }, }); }, }, });

Platform Features

Centralized routing information reporting via @datachange.

Global site‑wide search across all integrated back‑ends.

Tab management for quick navigation, pinning, and drag‑drop ordering.

Integrated feedback system for issue reporting.

Optional centralized permission control based on the unified entry point.

Global error listening for logging and alerting.

Asset and Debt Exploration

By collecting route metadata and page view statistics, the platform quantifies the number of pages, active users, and code complexity of each back‑end, enabling the team to identify legacy systems and plan deprecation.

Business Benefits

Unified user experience across all internal tools.

Reduced duplicated infrastructure through shared platform capabilities.

Visibility into platform health, allowing detection of redundant or abandoned services.

Foundation for fine‑grained, platform‑level operational cost management.

Overall, the micro‑frontend approach allowed Bilibili to consolidate dozens of disparate management systems with minimal development effort while laying the groundwork for future platform‑wide enhancements.

ArchitectureFrontend Developmentplatform engineeringmicro-frontendCross-Domain
Bilibili Tech
Written by

Bilibili Tech

Provides introductions and tutorials on Bilibili-related technologies.

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.