How Bilibili Scaled Its Frontend: From MVC to Vue SSR and Koa
This article chronicles Bilibili’s front‑end evolution in 2017, detailing the shift from a backend‑centric MVC model to front‑back separation, the adoption of Node middle‑layers, Vue and React SSR, Docker deployment, caching strategies, and subsequent refactoring to improve performance and scalability.
Bilibili’s Frontend Journey
In 2017 Bilibili transitioned from a backend‑centric MVC architecture to a front‑back separation model to reduce coupling and communication overhead.
Front‑Back Separation Modes
Two basic patterns were explored: a simple static‑HTML approach without a middle layer, and a Node‑based middle layer introduced in 2009 that enabled JavaScript to run on the server.
The static approach serves an HTML template with linked JS/CSS, fetching data via AJAX. The Node middle‑layer approach bundles assets with Webpack, uploads them to a CDN, and serves the HTML from a static server while the backend provides APIs.
SSR Challenges and Solutions
Initial SSR using Vue on the server caused first‑paint white‑screen issues and poor SEO for SPA pages, prompting a shift to server‑side rendering for SEO‑critical pages.
Framework Selection
Node frameworks considered were Hapi, Express, and Koa, with Egg.js rejected for being heavyweight and opaque. Express was initially chosen for its simplicity, later replaced by Koa2 for better async/await support and middleware flow.
Front‑end frameworks Vue and React were selected for their ability to support isomorphic rendering.
Project Structure
Key directories:
client – front‑end (Vue) code and Webpack build logic
server – back‑end code (Express/Koa) with MVC‑like structure
build, config, dist, package.json, etc.
Server‑Side Rendering Implementation
Vue SSR was built using
const { createBundleRenderer } = require('vue-server-renderer')and const renderer = createBundleRenderer(serverBundle, {... }). Two entry points were defined: entry-client.js for the browser bundle and entry-server.js for the server bundle.
Deployment and Caching
The service was containerized with Docker (1 CPU, 4 GB RAM) across two instances, later scaled to six. Caching was added at both CDN and file‑system levels to handle up to 10 million daily visits.
Configuration center integration allowed dynamic versioning of front‑end bundles without restarting services.
Refactoring and Automation
Core libraries were extracted into an internal npm package, enabling other teams to reuse the SSR infrastructure. Scaffolding tools were created to generate projects with pre‑configured Webpack and package.json files.
Performance Testing
Stress tests revealed CPU bottlenecks on 1C4G servers, especially with Vue 2.3.x. Upgrading to Vue 2.4.x and adding component/page caches improved throughput, though CPU remained the limiting factor.
Conclusion
The migration from static pages to a full SSR architecture required close collaboration between front‑end and back‑end teams, iterative framework selection, and robust deployment pipelines. Ongoing challenges include memory leaks and performance tuning, but the overall front‑end performance and scalability have markedly improved.
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.
Tencent IMWeb Frontend Team
IMWeb Frontend Community gathering frontend development enthusiasts. Follow us for refined live courses by top experts, cutting‑edge technical posts, and to sharpen your frontend skills.
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.
