现代浏览器已能处理多数前端框架最初要解决的问题,这促使我们重新思考:在当下的开发中,是否所有项目都需要依赖React、Vue这样的框架?
本文将探讨框架真正必要的场景,以及那些原生 Web API 已经足够胜任的情况,帮助你判断在今天,我们究竟在多大程度上需要前端框架。

尽管如此,开发者在面对问题时,仍常常默认选择 React、Angular、Vue 等 JavaScript 框架 来处理,哪怕这些问题浏览器本身已经能原生解决。这样的默认选择,往往牺牲了实际的用户体验成本 —— 页面体积更大、性能更慢、SEO 效果更差,只换来了开发上的方便。
框架主义与反框架主义
“框架主义”和“反框架主义”并非正式术语。它们是对开发者在新项目中的两种默认倾向的概括,核心区别在于你从何处起步。
框架主义倡导“框架优先”思维。开发者一开始就选定一个框架(通常是React),并将其作为项目基准。这种做法假设用户设备性能强、网络稳定,项目从一开始就比较“重”,等到性能问题出现时再做优化。
反框架主义则采取了截然相反的方法。它从“零依赖”开始,只在必要时才引入框架。框架被视为解决特定问题的工具,而非默认选择。开发者优先利用浏览器原生能力,只有在遇到真正的限制时才引入框架。这种思路假设用户可能使用较慢设备、网络条件不佳,因此从一开始就更加谨慎与高效。
技术层面对比
如今的跨浏览器兼容问题在很大程度上已不再是问题。Internet Explorer已退出舞台,Safari也支持了大多数现代Web API。那些当初促使我们使用React等框架的“平台差距”,如今大多已经被填补。
近几年,Web平台有了显著进步。对于绝大多数常见需求来说,原生JavaScript已经绰绰有余。
以下是平台本身提供的一些关键能力:
Web Components(网页组件)
Web Components建立在三项核心技术之上:
- Custom Elements(自定义元素):定义新的HTML标签
- Shadow DOM(影子DOM):实现封装与样式隔离
- Template元素:实现可复用的模板结构
这些API共同构建出一种无需框架支持的组件化体系。下面是一个简单的Web Component示例:
class TodoItem extends HTMLElement {
constructor() {
super();
this.attachShadow({ mode: 'open' });
}
connectedCallback() {
this.shadowRoot.innerHTML = `
<style>
:host { display: block; padding: 10px; }
.completed { text-decoration: line-through; }
</style>
<div class="${this.hasAttribute('completed') ? 'completed' : ''}">
<slot></slot>
</div>
`;
}
}
customElements.define('todo-item', TodoItem);
上面的组件包含封装的样式和生命周期方法(constructor() 创建shadow root,而 connectedCallback() 在元素加入DOM时触发)。
你可以像使用普通HTML标签一样,把它加到页面里:
<!-- 基本用法 -->
<todo-item>学习 Web Components</todo-item>
<!-- 含“完成”状态 -->
<todo-item completed>选择 UX 而非 DX</todo-item>
这种方式无需编译步骤、没有虚拟DOM,也不需要构建工具。代码直接在浏览器中运行,无需框架初始化,因此启动几乎是即时的。
不过,Web Components 并不自带响应式机制。与React等框架不同,后者只需声明UI,框架就会自动更新界面;而Web Components是命令式的——你需要自己管理DOM更新、监听属性或状态变化。除非你使用像Lit这样的辅助库,否则这些都得手动实现。
理想的使用场景:叶子组件(Leaf Components)
独立的叶子组件——例如表情选择器、日期选择器、颜色选择器等——非常适合用Web Components来实现。它们位于组件树的最外层,不包含嵌套子组件,因此能够避免与服务器端渲染或多层Shadow DOM之间通信相关的复杂问题。
静态内容 + 轻量交互
当处理以静态内容为主且只需少量交互时,原生方法表现出色。大多数网站本质上仍是HTML文档,只是偶尔需要动态行为,这些行为可以通过原生JavaScript渐进增强实现。
例如,以下代码展示了如何使用Fetch API为一个基础的联系表单添加异步提交功能:
document.querySelector('form').addEventListener('submit', async (e) => {
e.preventDefault();
const formData = new FormData(e.target);
const response = await fetch('/api/submit', {
method: 'POST',
body: formData
});
if (response.ok) {
e.target.innerHTML = '<p>谢谢,你的信息已成功发送!</p>';
}
});
其他 Web 平台特性
除了Web Components和基础交互外,现代Web平台如今几乎已覆盖当初框架承担的大部分职责。
- 原生ES模块和动态导入可实现依赖管理与代码分割;
- Import Maps让加载第三方库更加简单;
- Fetch API负责网络请求;
- 在样式层面,现代CSS动画、容器查询以及自定义属性,让我们能在无需依赖复杂JavaScript框架的情况下实现灵活的响应式布局。
维护性
从长期来看,原生方案在可维护性方面更有优势。十年前写的原生JavaScript代码,今天仍然可以直接运行;而基于框架的应用,通常每次框架大版本更新都需要大量重构。原生Web API不依赖外部工具链或包管理生态,且在向后兼容性上更稳定。这意味着你投入学习的原生知识可以在未来多年持续生效。
服务器端渲染(Server-side Rendering)
过去,服务器端渲染几乎完全依赖框架。但如今Web平台在这方面也取得了重大进展。Declarative Shadow DOM已在主流浏览器中得到支持,它允许我们直接在HTML中通过 shadowrootmode 属性定义shadow root,而无需使用JavaScript。
下面的示例展示了这种方式的好处:组件可以立即渲染,而不必等待JavaScript执行,从而加快首屏渲染速度。CSS还可以直接响应属性变化,比如 completed 状态可通过 :host([completed]) 选择器自动添加删除线。
<todo-item completed>
<template shadowrootmode="open">
<style>
:host { display: block; padding: 10px; }
:host([completed]) div { text-decoration: line-through; }
</style>
<div><slot></slot></div>
</template>
Pick UX over DX
</todo-item>
<script>
class TodoItem extends HTMLElement {
constructor() {
super(); // 不再需要 attachShadow()
}
}
customElements.define('todo-item', TodoItem);
</script>
AI 与 “框架默认化” 现象
如今的AI编码工具强化了“框架优先”的默认趋势。它们往往自动生成基于React或其他流行框架的代码,并常常搭配Tailwind等工具。这并不是因为这些技术总是最优解,而是因为它们在训练数据中占了绝对主导地位。
Paul Kinlan将这种由AI驱动的趋势称为“死框架理论”。他认为React已经赢得了前端之战,其他替代品几乎“生不逢时”。虽然这个结论可能过于悲观,但核心观点——AI默认倾向于框架化输出——确实成立。
为了验证这一点,有人做了一个小实验——让AI生成一个记忆卡片游戏。
| 版本 |
使用框架 |
提示内容 |
框架依赖 |
字体 |
图标 |
核心体积 |
| V1 |
React + Tailwind |
创建一个记忆游戏 |
React, ReactDOM, Tailwind, lucide-react |
Google Fonts |
lucide-react + emoji |
65.62 KB |
| V2 |
React |
创建一个简单的记忆游戏 |
React, ReactDOM, lucide-react |
Google Fonts |
lucide-react (8 图标) |
63.63 KB |
| V3 |
无框架 |
创建一个简单的 HTML 记忆游戏 |
无 |
系统字体 |
UTF-8 emoji |
2.16 KB |
在所有版本中,游戏功能完全相同。React版本在外观上略显精致,但其实这些图标也可通过内联SVG在无框架环境中实现。
结果非常明显:V1和V2的体积约为原生版本的30倍,其中95%的代码是框架开销。React和Tailwind并没有让应用“更好”,只是让它更“重”。
这正是“死框架理论”的一个实例。如果提示不够具体,AI就会默认生成React版本。要改变这种结果,开发者必须在提示中明确指定技术栈。但在现实中,大多数人不会这么做——因此,这无形中让“框架主义”在AI时代继续占据优势。
DX 与 UX 的取舍(开发体验 vs 用户体验)
框架确实会带来明显的性能开销。以前面提到的记忆卡片游戏为例,React版本的体积大约是原生JavaScript实现的30倍。
在大型生产环境的应用中,这种开销会进一步扩大。当你添加路由、状态管理、UI库以及各种工具函数后,单是框架相关的代码就可能达到150–300KB。
当然,随着应用复杂度的上升,原生实现的项目的体积也会增加,因此比例比较并非完全线性。但可以确定的是:框架始终会引入一层固定的额外负担,无论项目规模如何,它都会存在。
从用户体验的角度来看,更轻的页面体积和更快的加载速度,无疑是“反框架主义”方法的胜利。但这也带来了开发体验上的取舍——手写Web Components往往更繁琐:传递属性、处理事件、手动更新状态都比使用框架麻烦得多,跨多个组件进行状态管理也缺乏成熟的标准模式。
一些能在 DX 与 UX 之间“折中”的轻量替代方案
以下这些更轻量的库,可以在“原生代码的繁琐”与“框架臃肿”之间找到平衡点:
- HTMX(约14KB)在无需JavaScript重型前端的情况下增强HTML功能
- Alpine.js(约15KB)直接在HTML中提供响应式功能
- Preact(约3KB)提供了一个与React兼容的API,体积小巧
- Lit(约5KB)为Web组件提供了响应式模板和作用域样式
- Solid(约7KB)提供了类似React的语法,却没有虚拟DOM的开销
这些库能显著改善原生开发体验,同时保持合理的打包体积。但要记住,用户并不关心你的开发体验。他们只关心网站能否在他们的设备和网络条件下快速加载,并且正常运行。
对于中小型项目而言,React等重量级框架带来的DX优势,通常并不足以抵消它们在UX上的成本。当然,在企业级、大型团队协作的高交互式应用中,框架仍然有其合理性。但这些场景,仅占使用框架的网站和应用的一小部分。
接下来呢?优先考虑用户,立足现实
现代Web平台已经能够支撑大型应用。
- Netflix曾将其登录页从React改写为原生JavaScript,结果页面加载时间和“可交互时间”均减少了50%以上,JavaScript打包体积也缩小了约200KB。
- GitHub则通过开源库Catalyst广泛使用自定义Web Components来减少样板代码。
- Adobe甚至将Photoshop移植到Web上,采用了基于Lit的Web Components。
这些并不是特例,而是说明Web平台已经具备生产级能力。
不过,现实的就业市场要复杂得多。所谓“简历驱动开发”是真实存在的现象。React依然在招聘市场上占据主导地位。想保持就业竞争力,你几乎肯定需要掌握React。但要注意:招聘市场反映的是企业当前使用的技术,而不是新项目的最佳技术选择。
如果你想成为优秀的开发者,而不仅仅是“可就业”,你需要理解原生Web API,并且知道何时该用框架、何时不该用。
结语
反框架主义并不是拒绝工具,而是倡导从“问题”出发,而非跟随“潮流”;在追求方便之前,先权衡真实影响;最终,选择最能服务用户的技术。对于技术选型和更多开发实践,欢迎在 云栈社区 进行深入交流。
原文链接:https://blog.logrocket.com/anti-frameworkism-native-web-apis/