🧵 图谱 · 主题分线图

这张图在说什么

关系图谱-技术因果链 是一张把所有线缠在一起的”总网”,信息密但难以单独追一条脉络。 这篇把那张总网拆成 9 条独立的专线,每条线只讲一件事:抽象怎么上移、模块化怎么收敛、渲染怎么螺旋、工具链怎么提速、状态管理怎么摆动、CSS 布局怎么还债、UI 组件控制权怎么回归、算力怎么向用户靠近、前端怎么扩张领土。 单线更聚焦——你可以一次只盯着一个矛盾看它三十年的演化。

怎么看

  • 每张图只画一条主线,横向(LR)或纵向(TD)就是时间方向。
  • 边标签是这条线的”核心动作”:这一代少关心了哪一层、或为了对抗什么副作用而生。
  • 五条线合起来,就是 关系图谱-技术因果链 的总网。

一、抽象上移线 · 让开发者少关心一层

flowchart LR
    dom["手写 DOM<br/>命令式"]
    jquery["jQuery 2006<br/>命令式封装"]
    framework["React / Vue 2013+<br/>声明式"]
    svelte["Svelte<br/>编译器"]
    ai["AI Coding 2023+<br/>自然语言"]

    dom -->|"少关心: 浏览器差异 (兼容性)"| jquery
    jquery -->|"少关心: 怎么操作 DOM (改为描述 UI=f(state))"| framework
    framework -->|"少关心: 运行时框架本身 (编译期干掉)"| svelte
    svelte -->|"少关心: 怎么写代码 (改为描述意图)"| ai

    classDef hi fill:#e3f2fd,stroke:#1976d2;
    class dom,jquery,framework,svelte,ai hi;

这条线是整张前端史的脊柱

每一代做的其实是同一件事:把上一代还要操心的那一层,藏到地平线以下。 jQuery 让你不必再关心 IE 和 Netscape 的私有 API;React 让你不必再关心”怎么把 state 同步到 DOM”;Svelte 让你连”运行时框架要打包进产物”都不必关心;AI 让你连”怎么把意图翻译成代码”都可以交出去。 抽象每上移一层,生产力提升一个量级,但理解力也同步下沉一层——这正是 演进逻辑-五个永恒矛盾 里”抽象 vs 掌控”那条矛盾。详见 前端框架演进史 与深度专题 AI编程会让前端框架收敛吗


二、模块化线 · 社区先行、标准追认的潮汐

flowchart LR
    script["script 标签<br/>全局污染"]
    cjs["CommonJS / AMD<br/>社区方言"]
    browserify["Browserify 2011<br/>搬进浏览器"]
    webpack["Webpack 2014<br/>万物皆模块"]
    vite["Vite 2020<br/>开发期免打包"]
    esm["ES Modules<br/>语言标准"]

    script -->|"全局变量冲突, 无依赖管理"| cjs
    cjs -->|"Node 模块能否搬到浏览器?"| browserify
    browserify -->|"打包思路被发扬光大"| webpack
    webpack -->|"冷启动/HMR 太慢"| vite
    esm -.->|"标准最终追认, 浏览器原生支持"| vite
    cjs -.->|"标准缺位逼出社区方言"| esm

    classDef std fill:#fff3e0,stroke:#e65100;
    class esm,vite std;

一条"混乱 → 收敛"的潮汐

浏览器迟迟不给原生模块系统,社区只能自己造:CommonJS、AMD、UMD 一堆方言并存。Browserify 和 Webpack 用”打包”把方言在构建期抹平。直到 ESM 成为语言标准、浏览器原生支持,Vite 才得以借原生 ESM 实现”开发期免打包”——反过来淘汰了打包器的一部分存在理由。 注意图里 esm -.-> vite 是虚线:它表示”标准追认”——标准不是发明者,而是把社区已经跑通的实践事后扶正。这就是前端反复出现的”社区先行、标准追认”节奏。详见 ES-ModulesWebpackVite为什么Vite能取代Webpack


三、渲染模式螺旋线 · 否定之否定

flowchart TD
    mpa["MPA<br/>服务端渲染, 整页刷新"]
    spa["SPA<br/>客户端渲染, 白屏/SEO 差"]
    ssr["SSR<br/>渲染回归服务端"]
    ssg["SSG<br/>构建期预渲染"]
    isr["ISR<br/>增量再生成"]
    rsc["RSC<br/>服务端组件"]

    mpa -->|"交互弱, 体验割裂 → 搬到客户端"| spa
    spa -->|"首屏白屏 + SEO 灾难 → 搬回服务端"| ssr
    ssr -->|"内容型站点无需每次实时渲染"| ssg
    ssg -->|"全量构建太慢, 要按需更新"| isr
    isr -->|"组件级别地划分服务端/客户端"| rsc

    classDef back fill:#e8f5e9,stroke:#2e7d32;
    class mpa,ssr,ssg,isr,rsc back;

不是直线进步,而是螺旋上升

渲染的位置在”服务端 ⇄ 客户端”之间来回摆:前端先把渲染从服务端搬到客户端(SPA)以换取交互,却付出了白屏和 SEO 的代价;于是又把渲染搬回服务端(SSR/SSG/ISR/RSC)。 但这不是简单的回退——回到服务端时,前端带着组件化、水合(hydration)、流式渲染、服务端组件这些 SPA 时代练就的新能力回去了。这就是”否定之否定”:形式回到起点,内涵已完全不同。详见 渲染模式演进史


四、工具链提速线 · 用更快的语言重写一切

flowchart LR
    subgraph BUILD["打包/编译器"]
        webpack["Webpack<br/>功能全但慢 (JS 写)"]
        esbuild["esbuild / SWC<br/>Go / Rust 重写"]
        vite["Vite<br/>原生 ESM 按需编译"]
        unified["Turbopack / Rolldown<br/>Rust 统一底座"]
        webpack -->|"JS 单线程, 冷启动慢"| esbuild
        esbuild -->|"开发期用它做转译, 极速"| vite
        vite -->|"dev/prod 双引擎不一致, 想统一"| unified
    end

    subgraph PKG["包管理器"]
        npm["npm<br/>慢/黑洞"]
        yarn["Yarn<br/>锁文件/并行"]
        pnpm["pnpm<br/>硬链接/治幽灵依赖"]
        npm -->|"无锁文件, 安装慢"| yarn
        yarn -->|"node_modules 黑洞 + 幽灵依赖"| pnpm
    end

    subgraph RT["运行时"]
        node["Node.js<br/>事实标准"]
        deno["Deno<br/>安全/TS/ESM 优先"]
        bun["Bun<br/>一体化 + Zig 极速"]
        node -->|"历史包袱: 安全/模块/TS"| deno
        node -->|"想要更快的一体化运行时"| bun
    end

    classDef fast fill:#fce4ec,stroke:#c2185b;
    class esbuild,vite,unified,pnpm,deno,bun fast;

当框架格局稳定后,战场转向开发体验

2020 年后,框架之争降温,竞争焦点全面转向开发体验(DX)与构建速度。主旋律只有一句话:用更快的语言(Go / Rust / Zig)重写 JS 工具链。 三条并行的赛道殊途同归——打包器(Webpack → esbuild/SWC → Vite → Turbopack/Rolldown)、包管理器(npm → Yarn → pnpm)、运行时(Node → Deno/Bun)都在比谁更快、谁更省、谁更一体化。详见 ViteTurbopacknpm-Yarn-pnpm-包管理DenoBun为什么Vite能取代Webpack为什么pnpm解决了依赖问题


五、状态管理钟摆线 · 可预测性 vs 样板代码

flowchart LR
    manual["手动 DOM 状态<br/>状态散落各处"]
    flux["Flux 2014<br/>单向数据流思想"]
    redux["Redux 2015<br/>可预测但样板多"]
    mobx["MobX<br/>响应式, 自动追踪"]
    zustand["Zustand 2021<br/>极简 Hook"]
    pinia["Pinia<br/>Vue 官方, 轻量"]

    manual -->|"状态无单一来源, 难追踪"| flux
    flux -->|"落地为单一 Store + 纯函数 reducer"| redux
    redux -->|"样板代码太多 → 摆向响应式"| mobx
    redux -->|"样板代码太多 → 摆向极简"| zustand
    redux -.->|"在 Vue 生态摆向轻量"| pinia
    mobx -.->|"钟摆: 自动 vs 可预测之间反复"| redux

    classDef swing fill:#ede7f6,stroke:#5e35b1;
    class redux,mobx,zustand,pinia swing;

一只在"可预测"和"省事"之间来回的钟摆

状态管理的演化不是单调向前,而是一只钟摆,在两极之间摆动:

  • 可预测性那一极:Flux/Redux 用”单向数据流 + 不可变 + 纯函数 reducer”换来时间旅行、可追踪、易调试,代价是大量样板代码
  • 省事/响应式那一极:MobX 用自动依赖追踪让你”改对象就更新”,Zustand/Pinia 用极简 API 把样板砍到最低,代价是可预测性下降、调试链路变隐式。 没有哪一极是终点——每当一极的代价积累到痛点,社区就摆向另一极。这正是 演进逻辑-五个永恒矛盾 的具体演绎。详见 ReduxMobXZustandVuex-Pinia

六、CSS 布局线 · 还了二十年的债

flowchart LR
    table["table 布局<br/>用表格凑版面"]
    float["float + clearfix<br/>浮动 + 清除 hack"]
    inline["inline-block<br/>空白符 bug"]
    flex["Flexbox 2015<br/>一维布局"]
    grid["Grid 2017<br/>二维布局"]
    cq["Container Queries 2023<br/>按容器响应"]

    table -->|"语义错位, 嵌套地狱"| float
    float -->|"脱离文档流, 要清浮动 hack"| inline
    inline -->|"无法垂直居中, 空白符难缠"| flex
    flex -->|"只能一维, 复杂网格仍吃力"| grid
    grid -->|"只能按视口响应, 组件不自洽"| cq

    seed["IE 盒模型之争<br/>同一段 CSS 两种宽度"]
    seed -.->|"兼容性原罪贯穿始终"| float

    classDef native fill:#e0f2f1,stroke:#00897b;
    classDef pain fill:#fff3e0,stroke:#e65100;
    class flex,grid,cq native;
    class seed pain;

CSS 布局是一部"用错工具凑合,再被原生能力解放"的还债史

CSS 诞生时只为文档样式,根本没想过要承担”应用级布局”。于是前端被迫用错工具凑合了十几年:先用 table(本是表格数据)拼版面,再用 float(本是文字绕排图片)做多栏 + 满地 clearfix hack,再用 inline-block 又踩进空白符的坑。 直到 Flexbox(2015)和 Grid(2017) 这两个为布局而生的原生能力普及,这场长达二十年的”凑合”才真正结束;**Container Queries(2023)**进一步让组件能按自己所在容器(而非视口)响应,补齐了组件化时代的最后一块布局拼图。 注意虚线那条:IE盒模型之争——同一段 width 在 IE 和标准里算出两种宽度——是这条线的”原罪”,兼容性焦虑几乎贯穿了 float 时代的始终。详见 布局演进史CSS演进史


七、UI 组件控制权线 · 封装度的钟摆,控制权的回归

flowchart LR
    bootstrap["Bootstrap 2011<br/>只给样式 (CSS 框架)"]
    libs["AntD / MUI / Element 2015+<br/>给完整组件"]
    headless["Headless / Radix 2020+<br/>只给行为 + a11y"]
    shadcn["shadcn/ui 2023<br/>连依赖都不要"]

    bootstrap -->|"一眼同质化, 难深度定制"| libs
    libs -->|"样式难覆盖, a11y 又极难自己写"| headless
    headless -->|"行为归库, 样式归你 (配 Tailwind)"| shadcn

    tw["原子化 CSS / Tailwind"]
    tw -.->|"为 Headless/shadcn 提供样式层"| headless
    ai["AI 时代: 改本地源码比改 node_modules 顺手"]
    shadcn -.->|"源码归你, 利于 AI 直接改"| ai

    classDef ctrl fill:#ede7f6,stroke:#5e35b1;
    classDef ext fill:#eceff1,stroke:#607d8b,stroke-dasharray:4 3;
    class headless,shadcn ctrl;
    class ai ext;

一只在"封装度"和"控制权"之间摆动的钟摆

UI 组件方案的演化,是控制权一步步从库手里回到开发者手里的过程:

  • Bootstrap:只给样式,你套个 class 就有像样的页面——快,但”一眼 Bootstrap 味”,难改。
  • AntD / MUI / Element:给你封装好的完整组件(含交互+样式),中后台开箱即用——但样式覆盖痛苦、与框架强绑定、包还大。
  • Headless(Radix / Headless UI):只给最难自己写的那部分——行为、状态、无障碍(a11y),样式完全交还给你(通常配 Tailwind)。封装度下降,控制权上升。
  • shadcn/ui:连”依赖”这个概念都掀翻了——用 CLI 把组件源码复制进你的项目,你彻底拥有它。这在 AI 时代尤其契合:让 AI 改你项目里的本地源码,远比改 node_modules 里的第三方依赖顺手。 这条线和「状态管理钟摆线」「抽象上移线」共享同一种张力:省事 vs 可控。详见 UI组件库演进史BootstrapHeadless-UIshadcn-ui

八、部署托管线 · 算力一路向用户靠近

flowchart LR
    server["自建服务器<br/>中心化机房"]
    cdn["CDN<br/>边缘缓存静态资源"]
    jam["Jamstack 2015<br/>预构建静态 + API"]
    faas["Serverless / FaaS 2014<br/>函数即服务"]
    edge["Edge 2017+<br/>边缘运行时, 贴近用户"]

    server -->|"静态资源延迟高 → 推到边缘缓存"| cdn
    cdn -->|"纯静态 + 客户端调 API"| jam
    jam -->|"动态逻辑也想免运维 → 函数化"| faas
    faas -->|"冷启动 + 离用户远 → 推到边缘节点"| edge

    classDef near fill:#e1f5fe,stroke:#0277bd;
    class cdn,jam,faas,edge near;

算力的位置,一路从中心搬向用户

这条线只讲一件事:把”代码在哪里跑、内容从哪里来”一步步推到离用户更近的地方。 中心化服务器延迟高 → CDN 把静态资源缓存到边缘 → Jamstack 把页面预构建成静态托管(动态部分交给客户端调 API)→ Serverless 让动态逻辑也免运维、按需伸缩 → Edge 把代码本身推到全球边缘节点,毫秒级冷启动、贴着用户跑。 它和「渲染模式螺旋线」是一对孪生兄弟:渲染回到服务端(SSR/RSC),但这次服务端被搬到了边缘——动态内容也能像静态一样快。代价是 Edge 运行时只是 Web 标准子集(这恰好契合 Deno/Bun 的设计)。详见 部署与托管演进史Edge边缘运行时Jamstack渲染模式演进史


九、领土扩张线 · 一套 JS/TS 征服所有平台

flowchart TD
    web["浏览器<br/>前端的起点"]
    mobile["React Native 2015<br/>移动端"]
    desktop["Electron 2013<br/>桌面端"]
    mini["小程序 2017<br/>超级 App 内"]
    fullstack["全栈: Node → API routes<br/>→ BFF → tRPC"]
    rsc["RSC<br/>前后端边界内化进组件树"]

    web -->|"复用 Web 技能写原生 App"| mobile
    web -->|"Chromium+Node 写桌面应用"| desktop
    web -->|"超级 App 入口 + 即用即走 (中国)"| mini
    web -->|"Node 让前端能写后端"| fullstack
    fullstack -->|"前后端边界从网络请求变成组件树里一条线"| rsc

    classDef expand fill:#f1f8e9,stroke:#558b2f;
    class mobile,desktop,mini,fullstack,rsc expand;

前端的"领土扩张史"

前端从浏览器出发,用同一套 JS/TS 技能栈不断吞噬相邻领域:向移动端扩张(React Native)、向桌面扩张(Electron)、在中国向超级 App 内扩张(小程序),以及向服务端扩张(Node 全栈 → API routes → BFF → tRPC 端到端类型安全)。 这条线的终点是 RSC:前后端的边界不再是”一次网络请求”,而是组件树里的一条线——哪段在服务端跑、哪段在客户端跑,由组件粒度决定。扩张的二阶代价是复杂度守恒:边界模糊带来职责膨胀,前端工程师要懂的越来越多。详见 跨端与全栈演进史React-Native与移动跨端小程序生态Electron与桌面端全栈框架与BFFRSC与前后端边界模糊


一句话总结这九条线

把总网拆成五条线后会发现,它们其实是同一种张力在不同维度的投影:每一代都在”更省事 / 更快 / 更省心”和”更可控 / 更可预测 / 更透明”之间寻找新的平衡点,平衡一旦被打破,下一代就诞生了。


🔗 相关:MOC-前端技术演化史 | 关系图谱-技术因果链 | 图谱-竞争与替代关系 | 图谱-框架血缘谱系 | 时间线总览 | 演进逻辑-五个永恒矛盾 🔗 时代:1995-2005 浏览器时代 | 2005-2013 Ajax时代 | 2013-2018 SPA时代 | 2018-2023 工程化时代 | 2023-未来 AI时代 🔗 关键技术:jQuery | React | Vue | Svelte | Vite | Webpack | 渲染模式演进史 | Redux