专题合集 · 框架版本对比
前端Wiki/专题合集/框架版本对比手册

前端框架版本对比手册

本页收录前端三大经典「版本级选型」对比:Vue 2 vs Vue 3、Webpack vs Vite、Tailwind CSS vs 原生 CSS。每 组对比均给出原理差异、对比表格、最小代码示例与选型建议,末尾附从 Vue 2 升级 Vue 3、从 Webpack 迁移 Vite 的完整清单。适合在技术选型、升级评估、面试复习时查阅。

01Vue 2 vs Vue 3

Vue 3 不是「Vue 2 加几个 API」,而是一次从响应式内核到编译策略的重写。理解两版差异的核心切入点是响应式原理与组件代码组织方式,其余破坏性变更大多围绕这两点展开。Vue 3 于 2020 年 9 月正式发布,Vue 2 已于 2023 年 12 月 31 日停止维护,新建项目应直接使用 Vue 3(推荐 <script setup> 写法)。

响应式原理:Object.defineProperty vs Proxy

Vue 2 用 Object.defineProperty 给对象的每个属性逐一劫持 getter/setter;Vue 3 改用 ES6 Proxy 代理整个对象。这是两版最根本的差别,直接决定了「新增属性」「数组索引修改」「Map/Set」等场景是否响应式。详见 Proxy 与 Reflect 词条。

对比维度Vue 2Vue 3
劫持机制Object.defineProperty 逐属性重写 getter/setterProxy 代理整个对象,13 种 trap 拦截
新增 / 删除属性非响应式,需 Vue.set / Vue.delete(this.$set)天然响应式,直接赋值即可
数组监听重写 7 个变更方法(push、pop、splice 等),索引赋值不触发索引赋值、length 修改均可触发
Map / Set 支持不响应式原生响应式(由 reactive 实现)
初始化成本递归遍历所有属性,深层对象一次性全部劫持懒代理,访问到深层属性才继续代理,初始化更快
性能大对象初始化慢;无法监听属性新增初始化与更新性能均更好,约为 Vue 2 的 1.3~2 倍(官方基准)
浏览器要求IE 11 可用(需 es5 构建)不支持 IE 11,需 Proxy(Chrome 49+ / Edge 12+ / Firefox 18+ / Safari 10+)

组合式 API(Composition API)

Vue 2 的选项式 API(Options API)按 data、methods、computed 分组组织代码,同一业务逻辑被拆散到各选项;Vue 3 引入组合式 API,把同一逻辑关注点的状态、方法、计算属性聚拢到一个函数里,大组件的可维护性显著改善。详见 组合式 API。

对比维度Vue 2(选项式 API)Vue 3(组合式 API)
代码组织按选项类型分组,同类逻辑散落各处按功能分组,相关代码聚合成 setup 函数 / 组合式函数
逻辑复用mixin,存在命名冲突、来源不清的问题(见 mixin 混入)自定义组合式函数(useXxx),来源明确、无命名冲突
this 指向指向组件实例,可用 this 访问 route、store 等setup 中无 this,通过参数和导入获取上下文
TypeScript 友好度类型推断困难,需 vue-class-component / vue-property-decorator 装饰器原生友好,严格模式下推断完整
学习曲线平缓,模板写法直观需理解 ref / reactive 与依赖收集,曲线略陡
兼容性仅 Vue 2(Vue 2.7 向后移植了组合式 API)Vue 3 原生;推荐 <script setup> 语法糖

最小代码示例:同一计数器组件的两种写法

<!-- Vue 2:选项式 API -->
<script>
export default {
  data() { return { count: 0 } },
  computed: { double() { return this.count * 2 } },
  methods: { add() { this.count++ } },
  mounted() { console.log('mounted') }
}
</script>

<!-- Vue 3:<script setup> 组合式 API -->
<script setup>
import { ref, computed, onMounted } from 'vue'
const count = ref(0)                 // 响应式状态
const double = computed(() => count.value * 2)
function add() { count.value++ }
onMounted(() => console.log('mounted'))
</script>

Fragment、Teleport 与 Suspense

Vue 2 模板强制单一根节点,弹窗与异步组件都要写 hack;Vue 3 从编译器层面原生支持这三个能力。

能力Vue 2Vue 3
多根节点(Fragment)报错 "Component template should contain exactly one root element",需额外包裹元素支持多个根节点,渲染为 Fragment,不影响 DOM 层级
Teleport 传送门弹窗需手动挂载到 body(Vue.extend + $mount)<teleport to="body"> 声明式渲染到任意节点,见 Teleport
Suspense 异步组件仅简单异步组件(factory + loading 分支),无统一 fallback<suspense> 带 fallback 插槽,可配合异步 setup(),见 Suspense

生命周期映射

组合式 API 中,选项式生命周期改为以 on 开头的导入函数,并在 生命周期文档中给出了一一映射:

Vue 2 选项式Vue 3 组合式说明
beforeCreate / createdsetup() 本身setup 执行在这两个钩子之间,直接写业务逻辑即可
beforeMountonBeforeMount挂载前,DOM 未生成
mountedonMounted挂载完成,可操作 DOM
beforeUpdateonBeforeUpdate响应式数据变更、DOM 打补丁前
updatedonUpdatedDOM 打补丁后,避免在此修改状态
beforeDestroyonBeforeUnmount卸载前,清理定时器 / 事件监听(改名更贴切)
destroyedonUnmounted卸载完成
activated / deactivatedonActivated / onDeactivated配合 keep-alive 缓存组件
errorCapturedonErrorCaptured捕获后代组件错误
—(新增)onRenderTracked / onRenderTriggered调试用:精确追踪哪个依赖触发了重渲染

TypeScript 支持

对比维度Vue 2Vue 3
源码语言JavaScript,类型靠 vue-class-component / 装饰器模拟用 TypeScript 重写,类型定义随源码生成,保持同步
组件 props 类型需 PropType 断言,编辑器提示弱基于字面量推导,类型推断完整到模板
模板检查volar 之前基本无模板类型检查Volar(Vue 官方 VS Code 插件)可对模板表达式做类型检查
脚手架默认Vue CLI 需手动勾选 TScreate-vue 默认可选 TS + <script setup lang="ts">

打包体积与性能

对比维度Vue 2Vue 3
运行时大小(gzip)vue.runtime.min.js 约 20KB约 12KB(tree-shaking 后按需引入)
Tree shaking整体引入,难以按需摇掉编译器与运行时分离,API 具名导入可摇掉
重渲染机制全量 diff(组件级)基于 虚拟 DOM 的静态提升 + PatchFlag,动态节点精准更新
编译优化无静态标记静态提升、缓存事件处理器、Block 树收集动态子节点
✔ 该选哪个

新建项目:无条件选 Vue 3 + Vite + <script setup>,Vue 2 已停止维护(2023-12-31 EOL)且不再收到安全更新。存量 Vue 2 项目:先升级到 Vue 2.7(官方向后移植了组合式 API 与 <script setup>),在新功能上试用组合式 API;配合 @vue/compat 兼容构建逐步迁移到 Vue 3。详见迁移清单章节与 Vue2 迁移 Vue3 词条。状态管理从 Vuex 迁到 Pinia,UI 库 element-ui 换 element-plus。

02Webpack vs Vite

两者解决的都是「把源码变成浏览器可运行的产物」的问题,但路线相反:Webpack 是编译时打包——启动即把所有模块编译成一个 bundle;Vite 是运行时按需编译——开发期用浏览器原生 ESM,请求哪个模块才编译哪个。详见 Webpack 与 Vite 词条。

构建原理与冷启动速度

对比维度WebpackVite
开发期工作方式编译时把所有模块打包成 bundle,再启动 dev serverdev server 直接启动,借助浏览器原生 ESM 按请求编译模块
冷启动速度与项目规模强相关,中大型项目几十秒到几分钟与项目规模几乎无关,通常亚秒级启动
首屏加载(开发期)一个本地 bundle,首屏不再编译按路由按需编译,首屏只编译用到的模块
HMR 热更新通过模块图反向推导受影响模块,热更新边界计算较重通过 import.meta.hot 精确失效,配合 SWC/esbuild 速度接近原生
预构建无此概念用 esbuild 把 CommonJS 依赖预构建成 ESM(如 lodash、react)

配置复杂度与生态

对比维度WebpackVite
配置文件webpack.config.js,entry/output/loader/plugin/resolve 等众多概念vite.config.js,多数场景零配置开箱即用
资源处理一切皆模块:css-loader、style-loader、babel-loader、file-loader 等 loader内置 CSS、静态资源、TS、JSX 处理,扩展靠 插件(rollup 插件兼容)
生态成熟度极其成熟:Module Federation、长缓存策略、增量编译、_DLL 等大量实践快速成长,周边插件已覆盖主流场景,但深度定制能力不及 Webpack
微前端 / 多入口Module Federation 原生支持,大型 MPA 常见配置可通过插件实现,复杂场景需自行组合
适用团队有历史包袱、需要精细控制产物的大型项目新项目、追求开发体验与速度的中大型项目

生产构建

对比维度WebpackVite
底层打包器自研打包器(基于 tapable 事件流)Rollup(生产构建)+ esbuild/SWC(转译)
代码分割splitChunks 配置强大但复杂默认按动态 import 分包,配置简单
压缩terser / swc 压缩esbuild 或 terser(可选)
CSS 处理loader 链(MiniCssExtractPlugin + Autoprefixer)内置 PostCSS + Autoprefixer,CSS 代码分割开箱即用
SSR / SSG需自行搭建或用框架(Next.js、Nuxt 2)原生 SSR API;Nuxt 3、VitePress、SvelteKit 均基于 Vite
与 newer 工具关系Webpack 5 支持 Module Federation;Turbopack 定位其继任者与 Turbopack、Rsbuild 互通生态

最小代码示例:同一项目的构建配置对比

// webpack.config.js(Vue 2 时代常见形态,约 40~80 行起步)
const path = require('path');
module.exports = {
  mode: 'development',
  entry: './src/main.js',
  output: { path: path.resolve(__dirname, 'dist'), filename: '[name].js' },
  module: {
    rules: [
      { test: /\.vue$/, loader: 'vue-loader' },
      { test: /\.js$/,  loader: 'babel-loader', exclude: /node_modules/ },
      { test: /\.css$/, use: ['style-loader', 'css-loader', 'postcss-loader'] }
    ]
  },
  devServer: { hot: true, port: 8080 }
};

// vite.config.js(等价能力,通常 5~10 行)
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
export default defineConfig({
  plugins: [vue()],
  server: { port: 5173 }
  // CSS、静态资源、 TS、 HMR 全部内置,无需配置 
})
✔ 该选哪个

新项目:默认 Vite(Vue 用 create-vue、React 用 vite-plugin-react,Nuxt 3 / SvelteKit / VitePress 同生态)。存量 Webpack 项目:先用 Webpack 5 的持久化缓存与 SWC loader 提速;若改造成本可控再迁移 Vite,注意 Module Federation / 特殊 loader 依赖是否可替代。需要深度定制产物(如 Module Federation 微前端、多端 SDK 构建)时 Webpack 仍更稳。

03Tailwind CSS vs 原生 CSS

这不是「框架 vs 无框架」的选择,而是两种 CSS 组织哲学:原子化(utility-first,把样式拆成单用途类)vs 语义化(类名表达业务含义,样式集中在样式表)。Tailwind v3 的 JIT 引擎与 v4 的 Lightning CSS 架构已把「包体积」痛点基本消除。详见 Tailwind 与 原子化 CSS 词条。

对比维度Tailwind CSS原生 CSS
类名原子化px-4 py-2 rounded-lg 组合原子类,直接写在 HTML 上自定义语义类名(如 .btn-primary),样式与结构分离
设计令牌内置 spacing / color / font-size 体系,团队天然统一;通过 tailwind.config.js 扩展需自行约定,常配合 CSS 变量与设计稿规范
响应式前缀md:flex、lg:grid-cols-3 一类即媒体查询手写 @media 或容器查询块
暗色模式dark:bg-gray-900 前缀切换,依赖 prefers-color-scheme 或 class 策略(见 暗色模式)手写 dark 主题样式与变量切换逻辑
维护性改样式不用跨文件,但 HTML 类名长、可读性见仁见智结构干净,但样式扩散、命名(BEM 等)负担重,见 BEM
学习成本需熟悉一套约定式类名(约数百个常用类),有记忆门槛零学习成本,但工程化规范要自己建
包体积JIT 按使用类名生成,最终通常 10~30KB;无未使用样式取决于项目规模与清理力度,老项目常有 100KB+ 死代码
与组件框架搭配Vue / React 单文件组件中天然契合,配合 headless UI 生态配合 CSS Modules / CSS in JS 保证隔离
调试体验类名即样式,DevTools 直接可读;但样式来源分散样式集中,可读性与覆盖清晰

最小代码示例:同一个按钮的两种写法

<!-- Tailwind:原子类直接写 -->
<button class="bg-blue-600 text-white font-medium px-4 py-2 rounded-lg
                   hover:bg-blue-700 dark:bg-blue-500 transition-colors">
  提交
</button>

<!-- 原生 CSS:语义类 + 样式表 -->
<button class="btn-primary">提交</button>

/* styles.css */
.btn-primary {
  background: #2563eb; color: #fff; font-weight: 500;
  padding: .5rem 1rem; border-radius: .5rem;
  transition: background .15s;
}
.btn-primary:hover { background: #1d4ed8; }
@media (prefers-color-scheme: dark) {
  .btn-primary { background: #3b82f6; }
}
✔ 该选哪个

选 Tailwind:新项目、设计令牌尚未建立、多人协作需强约束样式一致性、大量重复 UI 组件场景。选原生 CSS:对包体积零依赖有要求(活动页、嵌入式小组件)、团队已有成熟命名规范(BEM)与 PostCSS 流水线、样式高度主题化需深度定制。折中方案:Tailwind 做布局与原子能力,复杂业务组件用 CSS Modules 局部覆盖;也可以评估 UnoCSS、WindiCSS 等同类方案。若只是不想要预处理器,现代 CSS 嵌套 + 容器查询 + CSS 变量已覆盖大部分原生书写需求。

04迁移清单

从 Vue 2 升级 Vue 3

从 Webpack 换 Vite

版本说明:本页所述 Vue/Vite/Tailwind 特性以 Vue 3.5、Vite 6、Tailwind v3/v4 为参照;Webpack 行为以 v5 为参照。相关系统学习见 Vue 教程目录、前端工程化目录、CSS 框架目录;逐条术语见 词条大全。