前端技术发展史:从静态文档到现代 Web 应用平台

前端技术的发展,并不是 HTML、CSS、JavaScript、jQuery、Vue、React、TypeScript、Vite 等技术简单地一代替代一代,而是 Web 从“浏览超文本文档”逐步演化为“运行复杂软件应用”的过程。最初的 Web 只需要解决信息如何通过网络被访问,随后逐渐出现页面样式、用户交互、异步通信、组件化、状态管理、模块化、工程化、类型系统、服务器渲染以及全栈 Web Framework。本文按照时间与技术演化关系,梳理现代前端三十多年的发展历程,并解释每项重要技术为什么出现、解决了什么问题,以及它们在今天前端体系中的位置。


一、什么是前端

今天我们所说的“前端”,通常是指:

运行在用户侧,以浏览器为主要运行环境,负责用户界面展示、用户交互以及与服务端进行数据通信的软件系统。

但 Web 刚诞生的时候,并不存在今天意义上的“前端工程师”。

因为最早的 Web 只是一个:

分布式超文本文档系统

浏览器负责读取服务器上的文档:

用户
  ↓
Browser
  ↓ HTTP
Web Server
  ↓
HTML Document
  ↓
Browser Render
  ↓
网页

随后 Web 不断发展:

文档
↓
带样式的文档
↓
可以交互的网页
↓
可以局部更新的网页
↓
复杂 Web Application
↓
组件化 Web Application
↓
工程化 Web Application
↓
前后端融合的现代 Web Platform

因此,如果要真正理解前端,就应该把前端发展史理解成:

浏览器能力、Web 标准和软件工程抽象不断提升的历史。


二、前端三十多年的宏观发展历程

可以首先把前端历史压缩成下面这条时间线:

| 时间 | 代表技术/思想 | 主要解决的问题 | | ------------ | ---------------------------- | ----------------------------------------- | | 1989~1991 | WWW、URL/URI、HTTP、HTML | 如何通过互联网共享和访问文档 | | 1994~1996 | CSS | 如何把内容结构与视觉样式分离 | | 1995~1997 | JavaScript、ECMAScript | 网页如何具有程序逻辑和用户交互 | | 1990s~2000s | DOM、Browser API | JavaScript 如何操作网页 | | 2000~2005 | XMLHttpRequest、Ajax | 如何不刷新整个网页就与服务器通信 | | 2006~2010 | jQuery | 如何简化 DOM、Ajax,并处理浏览器差异 | | 2009~2012 | Node.js、npm | JavaScript 如何走出浏览器,前端如何工程化 | | 2010~2014 | 响应式设计、Bootstrap、SPA | 如何适配移动设备并构建复杂单页应用 | | 2013~2015 | React、Vue、Angular | 如何管理复杂 UI、组件和状态 | | 2012~2018 | Webpack、Babel、ES Modules | 如何组织、转换和构建大型前端代码 | | 2012~至今 | TypeScript | 如何降低大型 JavaScript 项目的类型风险 | | 2020~至今 | Vite 等新一代工具 | 如何改善大型前端项目开发和构建效率 | | 现代 | Next.js、Nuxt 等 | 如何统一 CSR、SSR、SSG、服务端能力和部署 | | 现代 | PWA、Web Components、Web API | Web 如何进一步接近应用平台 |

如果再进一步压缩,可以得到前端历史中最重要的六次变化:

第一次:
文档 → 有样式的文档

第二次:
文档 → 可以运行程序的网页

第三次:
整页刷新 → 异步局部更新

第四次:
手动操作 DOM → 数据驱动 UI

第五次:
页面开发 → 软件工程

第六次:
纯客户端应用 → 客户端 + 服务端 + 构建 + 部署的一体化 Web 应用

三、1989:World Wide Web——一切从“共享文档”开始

1989 年,Tim Berners-Lee 在 CERN 提出了 World Wide Web 的构想。1990 年,他实现了早期 Web Browser、Web Server,并建立了 URI、HTTP、HTML 等核心概念;1991 年 Web 开始向更广泛的研究社区开放。W3C 对早期 Web 历史的记录也明确提到 HTML、HTTP 和 URI 是这一体系的基础。

这时候需要解决的根本问题不是:

怎么开发一个网站?

而是:

互联网上不同计算机中的信息,怎样互相连接并被人方便地访问?

于是出现了三个非常重要的概念:

URI / URL
解决:资源在哪里

HTTP
解决:浏览器和服务器怎么通信

HTML
解决:服务器返回的文档是什么结构

于是形成了 Web 最基本的运行模型:

URL
 ↓
浏览器发送 HTTP Request
 ↓
Web Server
 ↓
返回 HTML
 ↓
浏览器解析 HTML
 ↓
显示网页

直到今天,我们开发 Vue、React、Spring Boot、Next.js,本质上仍然没有脱离这个基本模型。


四、HTML——Web 世界的结构层

HTML,全称:

HyperText Markup Language
超文本标记语言

它解决的问题是:

如何描述一份 Web 文档的结构和语义?

例如:

<h1>Java 学习路线</h1>

<p>这是一篇关于 Java 的文章。</p>

<a href="/java">查看 Java 教程</a>

浏览器看到的并不是单纯的文字,而是:

h1
→ 一级标题

p
→ 段落

a
→ 超链接

HTML 的核心价值因此不是“让页面好看”。

而是:

描述内容是什么。

现代 HTML 进一步强调 Semantic HTML:

<header></header>

<nav></nav>

<main></main>

<article></article>

<section></section>

<footer></footer>

这不仅影响页面结构,也关系到搜索引擎、可访问性以及浏览器对文档语义的理解。MDN 也将 HTML 定义为描述网站内容、结构及机器可读语义的基础 Web 技术。

官方教程: MDN · HTML 学习教程


五、CSS——解决“内容”和“表现”混在一起的问题

早期 Web 最大的问题之一是:

HTML 可以描述内容,但是页面表现能力有限。

开发者开始希望控制:

字体
颜色
大小
间距
位置
布局
背景
动画

如果所有这些信息都继续塞进 HTML,代码就会逐渐变成:

内容
+
结构
+
样式

全部混合在一起。

1994 年,Håkon Wium Lie 提出了影响后来 CSS 的层叠样式表方案。W3C 的 CSS 历史记录指出,当时 Web 已经逐渐成为电子出版平台,但缺少真正描述页面视觉表现的机制,这成为 CSS 出现的重要背景。

于是逐渐形成:

HTML
负责 What

CSS
负责 How it looks

例如:

<button class="login-button">
    登录
</button>
.login-button {
    width: 120px;
    height: 40px;
    border-radius: 8px;
}

HTML 不再关心这个按钮是什么颜色。

CSS 也不关心这个按钮执行业务上的什么操作。

这实际上已经体现了一个非常重要的软件设计思想:

Separation of Concerns——关注点分离。

官方教程: MDN · CSS 学习教程


六、CSS 布局能力的演进

CSS 出现以后,并没有立即拥有今天这么强大的布局系统。

很长时间里,开发者为了实现网页布局,需要使用:

Table
↓
Float
↓
Position
↓
Flexbox
↓
Grid

其中很多技术最初甚至并不是为完整页面布局设计的。

例如 float 最初主要适用于类似图片与文字环绕的场景,但因为当时缺少更好的布局工具,被大量用于页面布局。

后来出现了两个真正现代化的 CSS 布局系统。

Flexbox

Flexbox 主要解决:

一维布局。

即:

横向

A B C D

或者:

纵向

A
B
C
D

它非常适合:

导航栏
按钮组
卡片列表
水平/垂直居中

MDN 将 Flexbox 定义为用于在一个维度中组织项目的布局模型。

官方教程: MDN · Flexbox 教程

CSS Grid

Grid 进一步解决:

二维布局。

即同时控制:

Row
+
Column

因此更适合完整页面区域:

┌──────────── Header ────────────┐
│                               │
├──── Sidebar ───┬──── Main ────┤
│                │              │
│                │              │
├────────────────┴──────────────┤
│             Footer            │
└───────────────────────────────┘

MDN 将 CSS Grid 定义为 Web 的二维布局系统。

官方教程: MDN · CSS Grid 教程


七、1995:JavaScript——网页第一次真正“活起来”

HTML 和 CSS 能够解决:

页面有什么
+
页面长什么样

但仍然解决不了:

用户点击按钮怎么办?
输入表单怎么办?
页面数据改变怎么办?
定时任务怎么办?
如何动态修改页面?

于是 Web 需要一门:

能够在浏览器中执行程序逻辑的语言。

JavaScript 因此出现。

JavaScript 最初由 Brendan Eich 在 Netscape 创建,并进入 Netscape Navigator 浏览器。随后为了避免不同厂商各自实现完全不同的脚本语言,相关工作开始进入 Ecma 标准化体系。ECMA-262 的第一版于 1997 年通过,形成了 ECMAScript 标准。

于是前端第一次形成今天仍然存在的三层结构:

HTML
Structure
页面是什么

CSS
Presentation
页面长什么样

JavaScript
Behavior
页面做什么

例如:

<button id="btn">点击</button>
const button = document.querySelector("#btn");

button.addEventListener("click", () => {
    alert("Hello Web");
});

这意味着 Web 从:

Document

开始向:

Application

发生变化。

官方教程: MDN · JavaScript Guide


八、DOM——JavaScript 与网页之间的桥梁

这里必须区分一个经常被初学者混淆的概念:

JavaScript ≠ DOM

JavaScript 是编程语言。

DOM 是浏览器提供给程序操作文档的接口。

浏览器加载:

<body>
    <h1>Hello</h1>
    <button>Login</button>
</body>

以后,会把它转换成类似:

Document
└── html
    └── body
        ├── h1
        │   └── "Hello"
        │
        └── button
            └── "Login"

也就是:

DOM Tree

MDN 对 DOM 的定义非常明确:DOM 将 HTML 等文档在内存中表示为逻辑树,使程序能够修改文档的结构、样式和内容。

于是:

document.querySelector("h1").textContent = "Hello Java";

实际上发生的是:

JavaScript
 ↓
Browser DOM API
 ↓
修改 DOM Tree
 ↓
Browser Render
 ↓
用户看到变化

这是理解所有现代前端框架之前必须掌握的底层关系:

HTML
 ↓ Parse
DOM
 ↑
JavaScript

官方教程: MDN · Document Object Model


九、传统 Web 的问题——每操作一次就刷新一次网页

早期 Web 的运行方式非常直接。

例如用户查询商品:

点击查询
↓
浏览器发送 HTTP Request
↓
服务器查询数据库
↓
服务器重新生成 HTML
↓
Browser 下载整个页面
↓
重新显示

也就是说:

一次交互
≈
一次完整页面刷新

对于浏览文章来说问题并不大。

但是当 Web 开始承担:

邮箱
地图
聊天
搜索建议
后台管理系统
在线办公

这种模式的问题就明显了。

用户每操作一次:

页面消失
↓
等待
↓
整个页面重新加载

Web 的交互体验很难接近桌面软件。

于是出现了下一次关键转折。


十、Ajax——从“整页刷新”走向“局部更新”

浏览器逐渐拥有了 XMLHttpRequest 等能力,使 JavaScript 能够:

在页面不重新加载的情况下,与服务器进行 HTTP 通信。

2005 年,Jesse James Garrett 在文章 Ajax: A New Approach to Web Applications 中将这种组合式开发方法称为 Ajax,即:

Asynchronous
JavaScript
And
XML

Ajax 本身并不是一门新的编程语言,而是一套结合 JavaScript、DOM、HTTP 通信等能力的应用开发方式。它的重要价值是改变了传统 Web“一次操作、一次整页加载”的交互模型。

传统模式:

Browser
 ↓
HTTP Request
 ↓
Server
 ↓
完整 HTML
 ↓
刷新整个页面

Ajax:

Browser
 ↓
JavaScript
 ↓
HTTP Request
 ↓
Server
 ↓
Data
 ↓
JavaScript
 ↓
修改部分 DOM

例如:

用户搜索:jav
↓
JavaScript 发请求
↓
GET /search?q=jav
↓
服务器返回数据
↓
JavaScript 更新搜索建议
↓
页面不刷新

这一步极其重要。

因为它让 Web 从:

网页

开始真正走向:

Web Application。

今天我们常用:

fetch("/api/users")
    .then(response => response.json())
    .then(data => {
        console.log(data);
    });

Fetch API 已经成为现代浏览器进行网络请求的重要标准接口,MDN 将其描述为比 XMLHttpRequest 更现代、更灵活的资源请求接口。

官方教程: MDN · Fetch API


十一、2006:jQuery——解决 DOM 操作和浏览器兼容性的痛苦

Ajax 让网页越来越复杂。

但此时开发前端仍然非常痛苦。

其中两个核心问题是:

DOM API 使用繁琐

+

浏览器实现存在差异

例如不同浏览器:

Internet Explorer
Firefox
Safari
Chrome

在 DOM、事件和网络请求等行为上曾存在大量兼容性问题。

于是 jQuery 出现。

2006 年 1 月,jQuery 在 BarCampNYC 被公开宣布,同年 8 月发布稳定的 jQuery 1.0。

以前:

document.getElementById("user");

jQuery:

$("#user");

以前操作 DOM:

document.querySelector("#title").style.display = "none";

jQuery:

$("#title").hide();

而且 jQuery 同时封装了:

DOM
Event
Ajax
Animation
Browser Compatibility

因此它在很长一段时间里几乎成为 Web 开发的标准配置:

HTML
+
CSS
+
JavaScript
+
jQuery
+
Ajax

很多传统 Java Web 项目最终形成:

JSP
+
Servlet / Spring MVC
+
jQuery
+
Bootstrap

jQuery 今天已经不再是现代前端架构的中心,但它在前端历史上非常重要。

它解决的是:

浏览器原生开发体验过于繁琐的问题。

官方教程: jQuery Learning Center


十二、CSS 工程化——Sass、Bootstrap 与响应式设计

随着网站越来越大,问题不仅出现在 JavaScript。

CSS 同样开始失控。

一个大型项目可能拥有:

数千
甚至数万行 CSS

于是开发者开始思考:

CSS 能不能有变量?
能不能复用?
能不能拆模块?
能不能写函数?

Sass

Sass 等 CSS Preprocessor 出现后,可以使用:

Variables
Nesting
Mixin
Function
Module

最终再:

Sass
 ↓ Compile
CSS
 ↓
Browser

Sass 官方将自己定义为一种编译为 CSS 的样式表语言,用于帮助大型样式表进行组织和复用。

官方教程: Sass Documentation

Bootstrap

另一个方向则是:

把常见 UI 和布局模式直接封装起来。

于是出现 Bootstrap 等 UI Framework。

开发者不再从零实现:

Button
Modal
Navbar
Grid
Form
Card
Dropdown

而是直接复用成熟组件。

Bootstrap 同时大力推动了:

Responsive
Mobile First

等 Web 开发模式。

官方教程: Bootstrap Documentation


十三、移动互联网——响应式网页成为默认要求

智能手机普及以后,一个网页必须同时面对:

Desktop
Laptop
Tablet
Phone
甚至 TV / Watch

固定宽度页面逐渐无法满足需求。

于是:

Responsive Web Design

成为重要设计思想。

2010 年,Ethan Marcotte 提出了 Responsive Web Design 这一术语,其核心思想包括:

Flexible Layout
+
Flexible Image
+
Media Query

今天又进一步结合:

Flexbox
Grid
Container Query
Mobile First

构建响应式界面。MDN 也将响应式设计描述为让 Web 页面能够针对不同设备尺寸和分辨率自动调整布局和表现的一组实践。

于是前端第一次真正需要认真面对:

同一套 Web 应用运行在完全不同尺寸的设备上。

官方教程: MDN · Responsive Web Design


十四、2009:Node.js——JavaScript 走出浏览器

这是现代前端工程化最关键的历史节点之一。

早期 JavaScript:

JavaScript
 ↓
Browser

也就是说:

JavaScript 基本只能依赖浏览器执行。

Node.js 改变了这一点。

2009 年已经可以看到由 Ryan Dahl 编写的 Node.js 早期文档;Node.js 今天的官方定义是一个开源、跨平台的 JavaScript Runtime,它可以让 V8 JavaScript 引擎运行在浏览器之外。

于是变成:

Browser
   ↓
JavaScript

Node.js
   ↓
JavaScript

这看起来只是:

JavaScript 能运行在服务器。

但对前端真正巨大的影响是:

开发阶段也可以使用 JavaScript 编写各种工程工具。

于是逐渐出现:

CLI
Package Manager
Bundler
Compiler
Linter
Formatter
Test Runner
Development Server
Build Tool

现代前端工程化由此拥有了完整基础设施。

官方教程: Node.js Learn


十五、npm——前端进入依赖管理时代

大型软件一定会遇到一个问题:

别人写好的库怎么使用?

如果每次都:

下载 xxx.js
↓
复制到项目
↓
<script src="">

依赖管理很快就会失控。

npm 提供:

Registry
+
CLI
+
Package Management

开发者可以:

npm install vue

然后项目通过:

{
  "dependencies": {
    "vue": "..."
  }
}

描述自己的依赖关系。

npm 官方将 npm 描述为由网站、CLI 和软件 Registry 组成的 JavaScript 软件生态系统。

于是:

下载 JS 文件

逐渐变成

声明 Dependency
↓
Package Manager 自动管理

这也是为什么今天前端项目中会出现:

package.json
node_modules
package-lock.json
pnpm-lock.yaml

官方教程: npm Documentation


十六、模块化——大型 JavaScript 不可能永远写在一个文件里

项目变大以后:

function login() {}
function register() {}
function logout() {}
function search() {}
function upload() {}
function pay() {}

全部放进:

app.js

必然失控。

于是 JavaScript 开始进入模块化时代。

最终现代 JavaScript 建立起:

export function login() {
}
import { login } from "./user.js";

也就是:

ES Modules
ESM

模块化解决的问题是:

代码拆分
职责隔离
依赖关系
命名冲突
代码复用

于是一个现代项目可以形成:

src
├── api
├── components
├── views
├── stores
├── router
├── utils
└── main.js

MDN 的 JavaScript Modules 文档完整描述了 importexport、动态加载等现代模块机制。

官方教程: MDN · JavaScript Modules


十七、Webpack——浏览器代码正式进入“构建时代”

当项目拥有:

JavaScript Module
CSS
Image
Font
TypeScript
Framework Component
第三方依赖

之后,问题变成:

这些资源最后怎么变成浏览器能够高效加载的文件?

于是出现:

Bundler

Webpack 是这一时代最具代表性的工具之一。

Webpack 会从:

Entry

出发,分析:

Dependency Graph

然后将应用需要的模块处理成:

Bundle

Webpack 官方对自己的定义就是:

modern JavaScript application 的静态模块打包器。

它会建立模块依赖图,然后生成浏览器最终使用的静态资源。

可以理解成:

源代码

Vue / React
JS
CSS
Images
Modules
Dependencies

       ↓

    Webpack

       ↓

浏览器可部署资源

dist/
├── index.html
├── app.js
└── app.css

这意味着前端开发第一次明显分为:

Source Code

和

Production Artifact

官方教程: Webpack Concepts


十八、真正的问题出现了——DOM 操作已经无法支撑大型应用

当 Web 应用越来越复杂以后,一个页面可能同时存在:

用户信息
商品列表
购物车
搜索条件
分页
弹窗
消息
权限
路由
订单状态

例如购物车数量改变:

Cart Data
↓
Header 数量改变
↓
Cart Page 改变
↓
Price 改变
↓
Order Summary 改变

如果依然由程序员手动:

document.querySelector(...)

去寻找并修改每一个 DOM:

Business State

与

UI State

就非常容易失去同步。

于是现代前端最重要的思想之一出现:

不要告诉浏览器“具体修改哪个 DOM”,而是描述“当前数据状态下 UI 应该是什么”。

这就是:

Imperative UI

↓

Declarative UI

十九、从“操作 DOM”到“数据驱动 UI”

传统方式:

用户点击
↓
程序员找到 DOM
↓
修改 DOM
↓
更新页面

现代 Framework:

用户点击
↓
修改 State
↓
Framework
↓
更新 UI

可以压缩成:

UI = f(State)

例如:

count++;

开发者不再关心:

应该找到哪个 span
应该怎么修改 innerHTML

而是声明:

当 count 改变时,
这个 UI 应该展示新的 count。

React 官方今天仍然把这种模式称为 Declarative UI:开发者描述不同 State 对应的 UI,而不是逐个命令式修改界面元素。

这是现代前端与 jQuery 时代最大的思想差异之一。


二十、组件化——现代前端最重要的抽象

一个复杂页面:

首页

实际上可以拆成:

App
├── Header
│   ├── Logo
│   ├── Search
│   └── UserMenu
│
├── Sidebar
│
├── ArticleList
│   ├── ArticleCard
│   ├── ArticleCard
│   └── ArticleCard
│
└── Footer

于是出现:

Component

一个组件通常封装:

Structure
+
Style
+
Behavior
+
State

组件可以:

开发
复用
组合
测试
维护

现代前端由此从:

“开发一个页面”

转向:

“建立一棵组件树”

React 官方教程也直接把 UI 描述为由可复用、可嵌套的小组件组合而成。


二十一、Angular——大型 Web Application 的框架化

随着 SPA 越来越复杂,前端需要的不再只是:

DOM Library

而是:

Application Framework

Angular 系列框架的重要意义在于把:

Component
Dependency Injection
Routing
Form
HTTP
Build
Testing

等应用级能力组织进完整的 Framework 体系。

现代 Angular 官方也强调其目标是为能够随团队规模和代码规模扩展的 Web Application 提供完整开发平台。

它代表了一条重要路线:

前端开始像后端一样拥有完整的应用程序架构。

官方教程: Angular Documentation


二十二、2013:React——UI 被重新理解为 State 的函数

React 在 2013 年 5 月 29 日正式开源。React 官方版本历史仍然保留了这一时间点。

React 最重要的历史意义并不是:

发明了组件。

而是进一步推动了:

Component
+
State
+
Declarative UI
+
One-way Data Flow

这种现代 UI 思维。

React 的核心思想可以高度抽象为:

State
 ↓
Render
 ↓
UI

数据变化以后:

State Change
↓
React Render
↓
新的 UI 描述
↓
更新页面

开发者更多思考:

当前 State 是什么?

而不是:

我现在应该修改哪个 DOM?

这实际上改变了前端工程师组织 UI 逻辑的方式。

官方教程: React Learn


二十三、2014:Vue——渐进式、响应式的另一条路线

Vue 由尤雨溪在 2014 年作为个人项目创建。Vue 官方 FAQ 对这一历史有明确记录。

Vue 延续了现代前端:

Component
+
Declarative UI
+
Reactive State

的思想,同时强调:

Progressive
渐进式

Vue 官方今天对 Vue 的定义仍然是:

建立在标准 HTML、CSS 和 JavaScript 之上的声明式、组件化 UI Framework。

并通过 Reactive System 自动跟踪 JavaScript State 的变化并更新 DOM。

例如:

<script setup>
import { ref } from "vue";

const count = ref(0);
</script>

<template>
    <button @click="count++">
        {{ count }}
    </button>
</template>

开发者只关心:

count

而 Vue 负责:

State Change
↓
Dependency Tracking
↓
Render
↓
DOM Update

官方教程: Vue.js Guide


二十四、SPA——网页开始越来越像桌面软件

React、Vue、Angular 等技术兴起之后:

Single Page Application
SPA

成为非常重要的应用形态。

传统多页应用:

/index
↓
服务器返回 index.html

/article
↓
服务器返回 article.html

/user
↓
服务器返回 user.html

SPA:

首次加载 Application
↓
JavaScript 接管部分页面导航
↓
URL Change
↓
Router
↓
切换 Component
↓
通常不重新加载整份 HTML

例如 Vue Router 官方对 Client-side Routing 的描述就是:

URL
↓
Router
↓
Component

URL 改变时,页面无需重新从服务器完整加载。

于是:

页面

逐渐变成:

Application View

官方教程: Vue Router Guide


二十五、状态管理——组件多了以后,数据关系再次复杂起来

组件化解决了:

UI 组织问题

但又带来新的问题:

Component A
Component B
Component C
Component D

都需要 User State

如果所有数据不断:

Parent
↓
Child
↓
Child
↓
Child

传递,应用很快又会复杂起来。

于是出现:

Store

即:

Global / Shared State

例如 Vue 生态中的 Pinia:

Component A ─┐
Component B ─┼── Store
Component C ─┤
Component D ─┘

Pinia 官方也将自己的核心作用描述为跨 Component/Page 共享 State。

这说明现代前端已经不再只是:

页面开发。

而是开始处理:

应用程序状态管理。

官方教程: Pinia Documentation


二十六、TypeScript——JavaScript 项目开始面对“大型软件”的问题

JavaScript 的动态类型非常灵活:

let user = 1;

user = "LingXi";

user = {};

user = [];

对于:

几十行
几百行

代码来说非常方便。

但如果项目变成:

100000+
甚至 1000000+ 行

问题就出现了。

例如:

function getUser(user) {
    return user.name;
}

这里:

user 到底是什么?
有没有 name?
name 是 string 吗?
可以为空吗?

单靠运行时才能发现。

于是 TypeScript 在 JavaScript 之上增加:

Static Type System

例如:

interface User {
    id: number;
    name: string;
}

function getName(user: User): string {
    return user.name;
}

TypeScript 官方 Handbook 直接指出:JavaScript 从简单网页脚本发展成大型前后端程序之后,代码规模与复杂度增长,而语言原本表达代码单元关系的能力不足;TypeScript 的核心目标就是成为 JavaScript 的静态类型检查器。

因此:

JavaScript
+
Static Type System
=
TypeScript

TypeScript 并不是:

JavaScript 的替代品。

更准确地说:

TypeScript 是 JavaScript 大型软件工程化过程中形成的一套类型系统和开发工具。

官方教程: TypeScript Handbook


二十七、Vite——前端工程化进入更快的开发时代

Webpack 解决了模块构建问题。

但随着项目越来越大:

Dependencies ↑
Components ↑
Modules ↑

传统开发阶段的 Bundle 模式可能导致:

Dev Server 启动慢
Hot Update 慢
大型项目等待时间增加

与此同时,现代浏览器已经原生支持:

ES Modules

于是出现了新的思路:

为什么开发阶段一定要先把整个 Application 打成一个巨大 Bundle?

Vite 利用现代浏览器的 Native ESM 能力,在开发阶段按需提供模块,并对依赖进行预处理,从而改善启动与 HMR 体验。

Vite 官方也明确指出,它诞生的重要背景正是传统构建工具面对大型 Web Application 时出现启动和热更新性能问题。

于是现代 Vue 项目常见:

Vue
+
TypeScript
+
Vite

而不是早期大量手工配置 Webpack 的方式。

需要注意:

Vue ≠ Vite
React ≠ Vite

Vue/React:

UI 层

Vite:

Build Tool
Development Tool

这是完全不同的系统层。

官方教程: Vite Guide


二十八、为什么 SPA 之后又重新出现 SSR

SPA 很强大,但它并不是完美方案。

纯客户端渲染大致需要:

Browser
↓
下载 HTML
↓
下载 JavaScript
↓
执行 JavaScript
↓
请求数据
↓
生成 UI

如果 JavaScript Bundle 很大,就可能影响:

First Load
Performance
SEO
低性能设备体验

于是现代前端没有简单回到旧时代,而是重新组合:

Server Rendering
+
Client Rendering
+
Hydration
+
Static Generation

因此出现今天非常重要的概念:

CSR
Client-Side Rendering

SSR
Server-Side Rendering

SSG
Static Site Generation

现代 Web Application 可以根据不同页面选择不同策略,而不是全站固定使用一种方式。


二十九、Next.js 与 Nuxt——Framework 再向上一层

React 和 Vue 主要解决:

UI
Component
State
Rendering

但是完整生产级应用还需要:

Routing
SSR
SSG
Data Fetching
Server
Build
Image Optimization
Deployment
Code Splitting
Caching

于是又出现更高一层 Framework。

React:

React
↓
Next.js

Vue:

Vue
↓
Nuxt

Next.js 官方当前将自身定义为:

用于构建 Full-stack Web Application 的 React Framework。

现代 Next.js 甚至允许 Server Component 与 Client Component 共存,根据功能决定代码在:

Server
还是
Browser

执行。

Next.js 官方教程: Next.js Getting Started

Nuxt 则是 Vue 生态中的对应路线。Nuxt 官方将自己定义为基于 Vue.js 构建类型安全、高性能、生产级 Full-stack Web Application 的 Framework,并默认提供 Server-side Rendering 等能力。

Nuxt 官方教程: Nuxt Documentation

于是前端再次发生变化:

UI Framework

↓

Application Framework

↓

Full-stack Web Framework

三十、Web Components——组件化甚至进入浏览器标准

Component 的思想并不只属于:

Vue
React
Angular

Web Platform 本身也逐渐提供:

Web Components

主要包含:

Custom Elements
Shadow DOM
HTML Template

于是开发者甚至可以创建:

<star-card></star-card>

这样的自定义 HTML Element。

Web Components 的目标是提供:

Reusable
Encapsulated
Custom Element

MDN 也将其描述为一组创建可复用、自封装自定义元素的 Web Platform 技术。

这说明:

很多曾经必须依赖 Framework 才能获得的能力,也在逐渐进入浏览器原生平台。

官方教程: MDN · Web Components


三十一、PWA——Web 开始进一步接近原生应用

浏览器继续获得:

Service Worker
Cache Storage
Push Notification
Web App Manifest
Offline
Install

等能力。

于是出现:

Progressive Web App
PWA

Web Application 可以逐渐实现:

安装到设备

离线访问

资源缓存

后台能力

更接近 Native App 的体验

PWA 并不是某个 JavaScript Framework,而是一种利用现代 Web Platform 能力构建应用的方式。

Google web.dev 的 PWA 教程也重点覆盖 Manifest、Service Worker、Installable 和 Offline 等能力。

官方学习资料: web.dev · Learn PWA


三十二、现代 CSS 也在继续工程化

今天 CSS 自己已经非常强大:

Flexbox
Grid
Custom Properties
Animation
Media Query
Container Query
Logical Properties

与此同时仍然存在:

Sass
CSS Modules
CSS-in-JS
Utility CSS

等工程方案。

例如 Tailwind CSS 代表另一种思路:

传统:

.button {
    ...
}

↓

Utility First:

flex
items-center
gap-4
p-4

它不是替代 CSS。

本质仍然是:

HTML / Component
↓
CSS Rules
↓
Browser Rendering

只是改变了:

开发者组织 CSS 的方式。

官方教程: Tailwind CSS Documentation


三十三、今天完整的前端技术体系到底是什么

走到今天以后,可以把整个前端技术体系理解成几个层级。

┌─────────────────────────────────────┐
│           Application Layer         │
│                                     │
│ Dashboard / Blog / Mall / SaaS      │
├─────────────────────────────────────┤
│          Full-stack Framework       │
│                                     │
│ Next.js / Nuxt                      │
├─────────────────────────────────────┤
│             UI Framework            │
│                                     │
│ Vue / React / Angular               │
├─────────────────────────────────────┤
│       Application Infrastructure    │
│                                     │
│ Router / State / HTTP / Form        │
├─────────────────────────────────────┤
│           Language Layer            │
│                                     │
│ JavaScript / TypeScript             │
├─────────────────────────────────────┤
│          Engineering Layer          │
│                                     │
│ Node.js / npm / Vite / Webpack      │
│ ESLint / Test / Build               │
├─────────────────────────────────────┤
│          Web Platform API           │
│                                     │
│ DOM / Fetch / Storage / Worker      │
│ WebSocket / Canvas / Web Components │
├─────────────────────────────────────┤
│           Web Foundation            │
│                                     │
│ HTML + CSS + HTTP + Browser         │
└─────────────────────────────────────┘

因此千万不要形成这种错误认知:

HTML
↓
CSS
↓
JavaScript
↓
Vue

好像 Vue 是 JavaScript 的“下一代”。

它们实际上处于不同层级。

更加准确的是:

Browser
│
├── HTML
├── CSS
├── JavaScript
└── Web APIs
       │
       ↓
JavaScript / TypeScript
       │
       ↓
Vue / React / Angular
       │
       ↓
Router / State / HTTP
       │
       ↓
Application

与此同时:

Node.js
   │
   ├── npm
   ├── Vite
   ├── Webpack
   ├── ESLint
   └── Test

主要服务于:

Development
Build
Tooling
Engineering

三十四、前端发展史真正的主线:不断提升抽象层级

如果只看技术名称:

HTML
CSS
JavaScript
Ajax
jQuery
Node.js
Webpack
React
Vue
TypeScript
Vite
Next.js
Nuxt

会觉得前端技术非常混乱。

但如果从软件抽象角度看,整个历史其实异常清晰。

第一阶段:

我要描述一个文档
↓
HTML

第二阶段:

我要控制它长什么样
↓
CSS

第三阶段:

我要让网页能够执行程序
↓
JavaScript

第四阶段:

我要通过程序操作网页
↓
DOM

第五阶段:

我要不刷新页面就和服务器通信
↓
Ajax

第六阶段:

原生 DOM 和浏览器兼容太麻烦
↓
jQuery

第七阶段:

页面越来越复杂
手动修改 DOM 管不过来了
↓
Declarative UI

第八阶段:

UI 太大
↓
Component

第九阶段:

Component 太多
↓
Router + State Management

第十阶段:

JavaScript 项目太大
↓
Module
TypeScript

第十一阶段:

代码和资源太多
↓
Webpack / Bundler

第十二阶段:

构建和开发越来越慢
↓
Vite

第十三阶段:

纯 SPA 存在首屏、SEO、服务端能力等问题
↓
SSR / SSG / Hybrid Rendering

第十四阶段:

前端应用需要完整生产能力
↓
Next.js / Nuxt

所以整个前端历史可以压缩成一句话:

前端的发展,本质上是浏览器能力不断增强、Web 应用复杂度不断提高之后,人类不断创造更高层的软件抽象来管理复杂度的过程。


三十五、另一个重要主线:Web 从 Document 变成 Application

如果从 Web 自身的发展看,则可以得到另外一条非常清晰的路线:

1990s

Web Document
超文本文档

HTML + CSS

Styled Document
具有表现能力的文档

JavaScript + DOM

Interactive Page
可以交互的网页

Ajax

Dynamic Web Application
动态 Web 应用

React / Vue / Angular

Component Application
组件化应用

Node.js + npm + Webpack + TypeScript

Engineered Application
工程化软件

Next.js / Nuxt / Server Components / SSR

Full-stack Web Application
全栈 Web Application

也就是说:

浏览器已经从一个“HTML 阅读器”,逐渐进化成了一个通用的软件运行平台。


三十六、前端与 Java 后端到底如何连接

在现代前后端分离应用中,可以把整个系统理解成:

                       User
                         │
                         ↓
                     Browser
                         │
            ┌────────────┼────────────┐
            │            │            │
           HTML         CSS       JavaScript
                                      │
                                      ↓
                                Vue / React
                                      │
                      ┌───────────────┼──────────────┐
                      │               │              │
                  Component         Router         State
                      │
                      ↓
                 Fetch / Axios
                      │
                      │ HTTP / JSON
                      ↓
                Spring Boot
                      │
                  Controller
                      │
                   Service
                      │
                    Mapper
                      │
                    MySQL

例如用户执行:

登录

完整过程不是:

Vue 登录

而是:

用户点击 Login Button
↓
Browser 产生 Click Event
↓
Vue Event Handler
↓
读取 Form State
↓
Fetch / Axios
↓
HTTP POST /api/login
↓
Spring Boot Controller
↓
Service
↓
Database
↓
返回 JSON
↓
HTTP Response
↓
Vue 修改 State
↓
Framework 更新 UI
↓
Browser Render
↓
用户看到登录成功

理解了这条链路以后:

HTML
CSS
JavaScript
Vue
Axios
HTTP
Spring Boot
MySQL

就不再是七个孤立知识点。

而是一条完整的软件运行链路。


三十七、为什么今天仍然必须学习 HTML、CSS 和 JavaScript

很多初学者会产生一个误区:

已经有 Vue 和 React 了,为什么还要学习原生 HTML、CSS、JavaScript?

原因非常简单:

Vue
React
Angular
Next.js
Nuxt

最终都必须落到:

Browser

而 Browser 真正认识的是:

HTML
CSS
JavaScript
Web APIs

Vue 官方甚至直接说明 Vue 建立在标准 HTML、CSS 和 JavaScript 之上。

因此:

Framework

是:

Higher-Level Abstraction

而不是:

Replacement of Web Platform

只学习 Framework API 而不了解:

DOM
Event
HTTP
JavaScript
CSS
Browser

就很容易变成:

会调用框架,但不知道程序到底为什么能够运行。


三十八、现代前端开发的一条完整链路

今天开发一个 Web Application,大致可以经历:

需求
↓
UI / UX
↓
HTML Structure
↓
CSS Layout
↓
JavaScript / TypeScript
↓
Vue / React Component
↓
Router
↓
State
↓
Fetch / Axios
↓
HTTP API
↓
Backend
↓
Database

开发阶段:

Node.js
↓
npm / pnpm
↓
Vite
↓
Dev Server
↓
HMR

生产阶段:

Source Code
↓
Build
↓
Optimization
↓
Static Assets / Server Bundle
↓
Web Server / CDN / Node Server
↓
Browser

如果是传统 Java 前后端分离项目:

Vue
↓
npm run build
↓
dist
↓
Nginx

后端:

Spring Boot
↓
JAR
↓
JVM

最终:

Browser
   │
   ├── 请求静态资源 → Nginx
   │
   └── 请求 API → Spring Boot
                      │
                      ↓
                    MySQL

这已经构成了一套完整的软件系统。


三十九、如何正确理解今天的前端

今天再学习前端,不应该形成:

HTML
CSS
JS
Vue
React
Webpack
Vite
TypeScript
Node
npm
Pinia
Router
Axios
Next
Nuxt

全部都是需要背的名词

而应该建立:

Web Platform
│
├── HTML
├── CSS
├── JavaScript
├── DOM
├── Event
├── Fetch
└── Browser API

Language
│
├── JavaScript
└── TypeScript

UI
│
├── Vue
├── React
└── Angular

Application
│
├── Component
├── Router
├── State
└── HTTP

Engineering
│
├── Node.js
├── npm / pnpm
├── Vite
├── Webpack
├── ESLint
└── Test

Full-stack Framework
│
├── Next.js
└── Nuxt

Delivery
│
├── Build
├── CDN
├── Web Server
├── SSR
├── SSG
└── Deployment

这样,当以后看到一个新的前端技术时,只需要问几个问题:

它位于哪一层?

它解决什么问题?

没有它以前怎么做?

它依赖什么?

它替代了什么工作?

它最终运行在哪里?

很快就可以判断它在整个体系中的位置。


四十、总结

回顾三十多年的前端发展,真正改变 Web 的并不是某一个 Framework。

最底层始终是:

HTML
+
CSS
+
JavaScript
+
Browser
+
HTTP

其上的技术则不断围绕一个问题发展:

随着 Web Application 越来越复杂,我们怎样更高效、更可靠地描述和管理这种复杂度?

于是才逐渐出现:

DOM
↓
Ajax
↓
jQuery
↓
Component
↓
React / Vue / Angular
↓
Node.js
↓
npm
↓
Module
↓
Webpack
↓
TypeScript
↓
Vite
↓
Next.js / Nuxt

如果把整个前端历史最终压缩成一条主线,就是:

Document
↓
Styled Document
↓
Interactive Document
↓
Dynamic Web
↓
Web Application
↓
Single Page Application
↓
Component Application
↓
Engineered Application
↓
Full-stack Web Application
↓
Web Application Platform

所以学习前端最重要的并不是记住今天有多少 Framework。

而是理解:

每一项技术为什么会出现,它解决了上一代技术留下的什么问题,它位于整个 Web 系统的哪一层,以及它最终如何与浏览器、网络、服务端和用户连接起来。

理解了这一点以后,再学习 Vue、React、TypeScript、Vite、Next.js 或未来出现的新 Framework,都只是不断向已有的 Web 认知体系中增加新的节点,而不是重新学习一个完全陌生的世界。