[{"data":1,"prerenderedAt":1185},["ShallowReactive",2],{"content-/blog/vue-tooling-upgrade-strategy":3,"related-blog":1158},{"_path":4,"_dir":5,"_draft":6,"_partial":6,"_locale":7,"title":8,"description":9,"keywords":10,"author":11,"date":12,"category":13,"image":14,"body":15,"_type":1152,"_id":1153,"_source":1154,"_file":1155,"_stem":1156,"_extension":1157},"/blog/vue-tooling-upgrade-strategy","blog",false,"","大型团队中的工具链升级：Vue.js 版本迁移实战","分享大型组织中 Vue.js 跨版本升级的实战经验，包括策略规划、组织协调、渐进式迁移和团队协作","Vue.js, 工具链升级, 版本迁移, 大型团队, 前端架构, 组件库, 项目管理","HTMLPAGE","2025-12-02","Vue.js","/content-images/blog/blog.jpg",{"type":16,"children":17,"toc":1119},"root",[18,35,40,46,51,56,61,74,86,106,111,135,147,152,157,163,168,187,192,202,207,225,237,242,251,256,261,268,280,285,290,295,318,324,336,345,350,383,552,565,577,599,604,615,620,628,633,666,671,676,681,699,711,716,759,764,769,775,780,798,803,809,814,832,838,843,849,854,860,865,871,876,882,887,892,897,902,907,913,918,923,956,961,966,971,1004,1009,1032,1037,1055,1060,1065,1070,1103,1108,1113],{"type":19,"tag":20,"props":21,"children":22},"element","p",{},[23,26,33],{"type":24,"value":25},"text","在软件开发中，升级第三方包通常看起来很简单：运行 ",{"type":19,"tag":27,"props":28,"children":30},"code",{"className":29},[],[31],{"type":24,"value":32},"npm update",{"type":24,"value":34},"，验证功能仍然正常，完成。但当涉及到大型组织、跨越多个团队、影响整个应用生态系统的工具链升级时，情况就完全不同了。",{"type":19,"tag":20,"props":36,"children":37},{},[38],{"type":24,"value":39},"这篇文章将分享一个真实案例：一个有 350+ 名开发者的大型技术团队如何协调完成 Vue 2 到 Vue 3 的升级。这不仅仅是关于技术的故事，更是关于组织、沟通、策略和团队合作的故事。",{"type":19,"tag":41,"props":42,"children":44},"h2",{"id":43},"我们的组织背景",[45],{"type":24,"value":43},{"type":19,"tag":20,"props":47,"children":48},{},[49],{"type":24,"value":50},"假设你在一个有 350 多名开发者的大型技术部门工作，被分成多个敏捷团队，各自维护不同的数字产品。工作分配原则是：70% 的时间用于团队的核心目标，30% 用于任何对整个技术部门有益的事情。",{"type":19,"tag":20,"props":52,"children":53},{},[54],{"type":24,"value":55},"这个 30% 的灵活时间很关键——它允许跨团队的工作、知识分享和基础设施改进。正是通过这种方式，我们既要维护各自的应用代码，又要共同维护内部共享的工具库。",{"type":19,"tag":41,"props":57,"children":59},{"id":58},"中心化代码的瓶颈",[60],{"type":24,"value":58},{"type":19,"tag":20,"props":62,"children":63},{},[64,66,72],{"type":24,"value":65},"为了确保应用的一致性，我们构建了一个内部设计系统和组件库，叫做 ",{"type":19,"tag":67,"props":68,"children":69},"strong",{},[70],{"type":24,"value":71},"Kompas",{"type":24,"value":73},"（荷兰语\"罗盘\"的意思）。这个库基于 Vue 构建，是几乎所有应用的硬依赖。",{"type":19,"tag":20,"props":75,"children":76},{},[77,79,84],{"type":24,"value":78},"Kompas 的特殊之处在于它 ",{"type":19,"tag":67,"props":80,"children":81},{},[82],{"type":24,"value":83},"没有专属的团队",{"type":24,"value":85}," 来维护。相反，我们采取了开放贡献的策略：任何开发者都可以添加新组件或为现有组件新增功能。这样做的好处是：",{"type":19,"tag":87,"props":88,"children":89},"ul",{},[90,96,101],{"type":19,"tag":91,"props":92,"children":93},"li",{},[94],{"type":24,"value":95},"开发者可以快速迭代自己需要的功能",{"type":19,"tag":91,"props":97,"children":98},{},[99],{"type":24,"value":100},"知识分散在整个组织，避免单点依赖",{"type":19,"tag":91,"props":102,"children":103},{},[104],{"type":24,"value":105},"组件库保持活跃和相关",{"type":19,"tag":20,"props":107,"children":108},{},[109],{"type":24,"value":110},"一个团队在一个 sprint 内可以完成这样的流程：",{"type":19,"tag":112,"props":113,"children":114},"ol",{},[115,120,125,130],{"type":19,"tag":91,"props":116,"children":117},{},[118],{"type":24,"value":119},"在 Kompas 中做出需要的改动",{"type":19,"tag":91,"props":121,"children":122},{},[123],{"type":24,"value":124},"从多个团队获得代码审查",{"type":19,"tag":91,"props":126,"children":127},{},[128],{"type":24,"value":129},"发布新版本的组件库",{"type":19,"tag":91,"props":131,"children":132},{},[133],{"type":24,"value":134},"在自己的应用中使用新版本",{"type":19,"tag":20,"props":136,"children":137},{},[138,140,145],{"type":24,"value":139},"这一切能够运转的秘诀是",{"type":19,"tag":67,"props":141,"children":142},{},[143],{"type":24,"value":144},"自动化",{"type":24,"value":146},"：linting、格式化、质量检查、测试、可视化对比、发版——所有这些都自动化处理。这给开发者留出了贡献的空间，同时保证了质量。",{"type":19,"tag":20,"props":148,"children":149},{},[150],{"type":24,"value":151},"Kompas 像一个活的文档，每周有多个 minor 版本和补丁发布。通过语义化版本管理，各个应用团队可以放心地保持更新。",{"type":19,"tag":20,"props":153,"children":154},{},[155],{"type":24,"value":156},"对于更大的任务（比如设置可视化快照测试），我们建立了临时工作小组，叫做\"前端章节\"，成员自愿加入。这些小组在可用的 30% 时间里完成工作并定期汇报。",{"type":19,"tag":41,"props":158,"children":160},{"id":159},"危机时刻vue-3-的宣布",[161],{"type":24,"value":162},"危机时刻：Vue 3 的宣布",{"type":19,"tag":20,"props":164,"children":165},{},[166],{"type":24,"value":167},"所有这些都运转得很好——直到 Vue 3 被宣布，并且 Vue 2 的生命周期终止日期设定在 2023 年 12 月 31 日。",{"type":19,"tag":20,"props":169,"children":170},{},[171,173,178,180,185],{"type":24,"value":172},"这是一个 ",{"type":19,"tag":67,"props":174,"children":175},{},[176],{"type":24,"value":177},"巨大的破坏性变化",{"type":24,"value":179},"。Kompas 是用 Vue 2 构建的，而这意味着整个应用生态都被锁定在 Vue 2。现在，一个重要的决定摆在我们面前：",{"type":19,"tag":67,"props":181,"children":182},{},[183],{"type":24,"value":184},"我们需要升级",{"type":24,"value":186},"。",{"type":19,"tag":41,"props":188,"children":190},{"id":189},"我们需要一个策略",[191],{"type":24,"value":189},{"type":19,"tag":20,"props":193,"children":194},{},[195,197],{"type":24,"value":196},"首先，我们需要回答的问题是：",{"type":19,"tag":67,"props":198,"children":199},{},[200],{"type":24,"value":201},"什么时候开始升级？",{"type":19,"tag":20,"props":203,"children":204},{},[205],{"type":24,"value":206},"我们组织了一个来自不同团队的虚拟小团队，以获取多个角度的意见。很快我们意识到：",{"type":19,"tag":87,"props":208,"children":209},{},[210,215,220],{"type":19,"tag":91,"props":211,"children":212},{},[213],{"type":24,"value":214},"我们不能一夜之间把所有东西升级到 Vue 3",{"type":19,"tag":91,"props":216,"children":217},{},[218],{"type":24,"value":219},"必须有一个过渡期支持两个版本，给团队足够的迁移时间",{"type":19,"tag":91,"props":221,"children":222},{},[223],{"type":24,"value":224},"同时维护两个版本会产生时间和复杂性成本，所以这个过渡期越短越好",{"type":19,"tag":20,"props":226,"children":227},{},[228,230,235],{"type":24,"value":229},"关键的一步是",{"type":19,"tag":67,"props":231,"children":232},{},[233],{"type":24,"value":234},"可视化",{"type":24,"value":236},"。我们绘制了每个团队的技术栈地图，识别潜在的瓶颈，让升级计划对整个组织都是可见的。",{"type":19,"tag":20,"props":238,"children":239},{},[240],{"type":24,"value":241},"然后，我们需要让所有关键利益相关者参与：产品所有者、架构师、经理。在一个民主的组织文化中，这意味着我们需要达成共识——在荷兰文化中叫做 \"polderen\"：",{"type":19,"tag":243,"props":244,"children":245},"blockquote",{},[246],{"type":19,"tag":20,"props":247,"children":248},{},[249],{"type":24,"value":250},"以一种让每个人都多多少少满意或不满意的方式寻求共识。",{"type":19,"tag":41,"props":252,"children":254},{"id":253},"制定计划",[255],{"type":24,"value":253},{"type":19,"tag":20,"props":257,"children":258},{},[259],{"type":24,"value":260},"有了愿景，我们开始制定具体方案。我们参考了官方 Vue 文档的最佳实践，并注意到了一些关键点：",{"type":19,"tag":262,"props":263,"children":265},"h3",{"id":264},"vue-27-naruto-的关键作用",[266],{"type":24,"value":267},"Vue 2.7 (Naruto) 的关键作用",{"type":19,"tag":20,"props":269,"children":270},{},[271,273,278],{"type":24,"value":272},"Vue 2.7 是一个救星。它向后兼容到 Vue 2，但",{"type":19,"tag":67,"props":274,"children":275},{},[276],{"type":24,"value":277},"向前移植了 Vue 3 的一些特性",{"type":24,"value":279},"，包括 Composition API。这意味着开发者可以逐步学习 Vue 3 的写法，而不必一下子迁移整个项目。",{"type":19,"tag":262,"props":281,"children":283},{"id":282},"生态系统的异构性",[284],{"type":24,"value":282},{"type":19,"tag":20,"props":286,"children":287},{},[288],{"type":24,"value":289},"我们意识到不是所有应用都用了 Nuxt。而 Nuxt 的主版本与 Vue 紧密耦合，所以 Nuxt 的升级是一个独立的里程碑。",{"type":19,"tag":20,"props":291,"children":292},{},[293],{"type":24,"value":294},"这给了我们一个洞察：",{"type":19,"tag":87,"props":296,"children":297},{},[298,308],{"type":19,"tag":91,"props":299,"children":300},{},[301,306],{"type":19,"tag":67,"props":302,"children":303},{},[304],{"type":24,"value":305},"独立 Vue 应用",{"type":24,"value":307}," → 理想的首批迁移候选",{"type":19,"tag":91,"props":309,"children":310},{},[311,316],{"type":19,"tag":67,"props":312,"children":313},{},[314],{"type":24,"value":315},"Nuxt 应用",{"type":24,"value":317}," → 需要等待 Nuxt 3 的稳定发布",{"type":19,"tag":41,"props":319,"children":321},{"id":320},"大分割kompas-next",[322],{"type":24,"value":323},"大分割：Kompas-next",{"type":19,"tag":20,"props":325,"children":326},{},[327,329,334],{"type":24,"value":328},"最聪明的一步是",{"type":19,"tag":67,"props":330,"children":331},{},[332],{"type":24,"value":333},"不强制所有开发者同时迁移",{"type":24,"value":335},"。相反，我们创建了一个新的工作区 \"Kompas-next\"：",{"type":19,"tag":337,"props":338,"children":340},"pre",{"code":339},"Kompas（Vue 2 兼容）\n├── components/\n└── ...\n\nKompas-next（Vue 3 兼容）\n├── components/\n└── ...\n",[341],{"type":19,"tag":27,"props":342,"children":343},{"__ignoreMap":7},[344],{"type":24,"value":339},{"type":19,"tag":20,"props":346,"children":347},{},[348],{"type":24,"value":349},"这个策略之所以能工作，是因为：",{"type":19,"tag":112,"props":351,"children":352},{},[353,363,373],{"type":19,"tag":91,"props":354,"children":355},{},[356,361],{"type":19,"tag":67,"props":357,"children":358},{},[359],{"type":24,"value":360},"Vue 2.7 的向前兼容性",{"type":24,"value":362}," — 大多数 Vue 2 代码可以升级到兼容形式",{"type":19,"tag":91,"props":364,"children":365},{},[366,371],{"type":19,"tag":67,"props":367,"children":368},{},[369],{"type":24,"value":370},"Vue 2/3 语法的相似性",{"type":24,"value":372}," — 基础语法变化不大",{"type":19,"tag":91,"props":374,"children":375},{},[376,381],{"type":19,"tag":67,"props":377,"children":378},{},[379],{"type":24,"value":380},"Vue Demi",{"type":24,"value":382}," — 一个库，可以让同一个组件同时兼容两个版本",{"type":19,"tag":337,"props":384,"children":388},{"code":385,"language":386,"meta":7,"className":387,"style":7},"// 使用 Vue Demi，组件可以同时在 Vue 2 和 Vue 3 中运行\nimport { ref, defineComponent } from 'vue-demi'\n\nexport default defineComponent({\n  setup() {\n    const count = ref(0)\n    return { count }\n  }\n})\n","javascript","language-javascript shiki shiki-themes github-dark github-dark",[389],{"type":19,"tag":27,"props":390,"children":391},{"__ignoreMap":7},[392,404,431,441,466,480,520,534,543],{"type":19,"tag":393,"props":394,"children":397},"span",{"class":395,"line":396},"line",1,[398],{"type":19,"tag":393,"props":399,"children":401},{"style":400},"--shiki-default:#6A737D;--shiki-dark:#6A737D",[402],{"type":24,"value":403},"// 使用 Vue Demi，组件可以同时在 Vue 2 和 Vue 3 中运行\n",{"type":19,"tag":393,"props":405,"children":407},{"class":395,"line":406},2,[408,414,420,425],{"type":19,"tag":393,"props":409,"children":411},{"style":410},"--shiki-default:#F97583;--shiki-dark:#F97583",[412],{"type":24,"value":413},"import",{"type":19,"tag":393,"props":415,"children":417},{"style":416},"--shiki-default:#E1E4E8;--shiki-dark:#E1E4E8",[418],{"type":24,"value":419}," { ref, defineComponent } ",{"type":19,"tag":393,"props":421,"children":422},{"style":410},[423],{"type":24,"value":424},"from",{"type":19,"tag":393,"props":426,"children":428},{"style":427},"--shiki-default:#9ECBFF;--shiki-dark:#9ECBFF",[429],{"type":24,"value":430}," 'vue-demi'\n",{"type":19,"tag":393,"props":432,"children":434},{"class":395,"line":433},3,[435],{"type":19,"tag":393,"props":436,"children":438},{"emptyLinePlaceholder":437},true,[439],{"type":24,"value":440},"\n",{"type":19,"tag":393,"props":442,"children":444},{"class":395,"line":443},4,[445,450,455,461],{"type":19,"tag":393,"props":446,"children":447},{"style":410},[448],{"type":24,"value":449},"export",{"type":19,"tag":393,"props":451,"children":452},{"style":410},[453],{"type":24,"value":454}," default",{"type":19,"tag":393,"props":456,"children":458},{"style":457},"--shiki-default:#B392F0;--shiki-dark:#B392F0",[459],{"type":24,"value":460}," defineComponent",{"type":19,"tag":393,"props":462,"children":463},{"style":416},[464],{"type":24,"value":465},"({\n",{"type":19,"tag":393,"props":467,"children":469},{"class":395,"line":468},5,[470,475],{"type":19,"tag":393,"props":471,"children":472},{"style":457},[473],{"type":24,"value":474},"  setup",{"type":19,"tag":393,"props":476,"children":477},{"style":416},[478],{"type":24,"value":479},"() {\n",{"type":19,"tag":393,"props":481,"children":483},{"class":395,"line":482},6,[484,489,495,500,505,510,515],{"type":19,"tag":393,"props":485,"children":486},{"style":410},[487],{"type":24,"value":488},"    const",{"type":19,"tag":393,"props":490,"children":492},{"style":491},"--shiki-default:#79B8FF;--shiki-dark:#79B8FF",[493],{"type":24,"value":494}," count",{"type":19,"tag":393,"props":496,"children":497},{"style":410},[498],{"type":24,"value":499}," =",{"type":19,"tag":393,"props":501,"children":502},{"style":457},[503],{"type":24,"value":504}," ref",{"type":19,"tag":393,"props":506,"children":507},{"style":416},[508],{"type":24,"value":509},"(",{"type":19,"tag":393,"props":511,"children":512},{"style":491},[513],{"type":24,"value":514},"0",{"type":19,"tag":393,"props":516,"children":517},{"style":416},[518],{"type":24,"value":519},")\n",{"type":19,"tag":393,"props":521,"children":523},{"class":395,"line":522},7,[524,529],{"type":19,"tag":393,"props":525,"children":526},{"style":410},[527],{"type":24,"value":528},"    return",{"type":19,"tag":393,"props":530,"children":531},{"style":416},[532],{"type":24,"value":533}," { count }\n",{"type":19,"tag":393,"props":535,"children":537},{"class":395,"line":536},8,[538],{"type":19,"tag":393,"props":539,"children":540},{"style":416},[541],{"type":24,"value":542},"  }\n",{"type":19,"tag":393,"props":544,"children":546},{"class":395,"line":545},9,[547],{"type":19,"tag":393,"props":548,"children":549},{"style":416},[550],{"type":24,"value":551},"})\n",{"type":19,"tag":112,"props":553,"children":554},{"start":443},[555],{"type":19,"tag":91,"props":556,"children":557},{},[558,563],{"type":19,"tag":67,"props":559,"children":560},{},[561],{"type":24,"value":562},"隔离测试",{"type":24,"value":564}," — Kompas-next 有自己的测试套件，确保稳定性",{"type":19,"tag":20,"props":566,"children":567},{},[568,570,575],{"type":24,"value":569},"我们确实需要对每个组件进行轻微修改以适应新标准，但",{"type":19,"tag":67,"props":571,"children":572},{},[573],{"type":24,"value":574},"大部分代码可以复用",{"type":24,"value":576},"。结果是我们有了两个组件库版本：",{"type":19,"tag":87,"props":578,"children":579},{},[580,589],{"type":19,"tag":91,"props":581,"children":582},{},[583,587],{"type":19,"tag":67,"props":584,"children":585},{},[586],{"type":24,"value":71},{"type":24,"value":588}," — Vue 2 兼容版本，维持现状",{"type":19,"tag":91,"props":590,"children":591},{},[592,597],{"type":19,"tag":67,"props":593,"children":594},{},[595],{"type":24,"value":596},"Kompas-next",{"type":24,"value":598}," — Vue 3 兼容版本，为新应用做准备",{"type":19,"tag":41,"props":600,"children":602},{"id":601},"组织工作",[603],{"type":24,"value":601},{"type":19,"tag":20,"props":605,"children":606},{},[607,609,614],{"type":24,"value":608},"到这一步，大部分的调研和沟通都由一个小核心团队完成。现在我们需要",{"type":19,"tag":67,"props":610,"children":611},{},[612],{"type":24,"value":613},"扩大参与",{"type":24,"value":186},{"type":19,"tag":20,"props":616,"children":617},{},[618],{"type":24,"value":619},"我们制定的规则很简单，也很聪明：",{"type":19,"tag":243,"props":621,"children":622},{},[623],{"type":19,"tag":20,"props":624,"children":625},{},[626],{"type":24,"value":627},"如果你接触到一个还没转换的组件，就把它转换成同时兼容 Vue 2 和 Vue 3（使用 Vue Demi）。添加到 Kompas-next 文件夹的导入中，附带测试。",{"type":19,"tag":20,"props":629,"children":630},{},[631],{"type":24,"value":632},"这个规则的妙处在于：",{"type":19,"tag":87,"props":634,"children":635},{},[636,646,656],{"type":19,"tag":91,"props":637,"children":638},{},[639,644],{"type":19,"tag":67,"props":640,"children":641},{},[642],{"type":24,"value":643},"它与现有工作流一致",{"type":24,"value":645}," — 开发者已经在修改 Kompas，现在只是多做一个转换步骤",{"type":19,"tag":91,"props":647,"children":648},{},[649,654],{"type":19,"tag":67,"props":650,"children":651},{},[652],{"type":24,"value":653},"它是递进的",{"type":24,"value":655}," — 每个接触组件的人都帮忙迁移一个",{"type":19,"tag":91,"props":657,"children":658},{},[659,664],{"type":19,"tag":67,"props":660,"children":661},{},[662],{"type":24,"value":663},"它是分布式的",{"type":24,"value":665}," — 不需要一个集中的\"迁移小组\"日夜不休地工作",{"type":19,"tag":20,"props":667,"children":668},{},[669],{"type":24,"value":670},"结果是：Kompas-next 库开始快速增长，许多组件得到转换，而且这一切都是在各个团队的日常工作中自然发生的。",{"type":19,"tag":41,"props":672,"children":674},{"id":673},"早期采用者的反馈",[675],{"type":24,"value":673},{"type":19,"tag":20,"props":677,"children":678},{},[679],{"type":24,"value":680},"那些不依赖 Nuxt 的应用可以率先迁移到 Vue 3，提供宝贵的反馈：",{"type":19,"tag":87,"props":682,"children":683},{},[684,689,694],{"type":19,"tag":91,"props":685,"children":686},{},[687],{"type":24,"value":688},"我们的包设置是否正确？",{"type":19,"tag":91,"props":690,"children":691},{},[692],{"type":24,"value":693},"组件 API 是否直观？",{"type":19,"tag":91,"props":695,"children":696},{},[697],{"type":24,"value":698},"有没有我们遗漏的边界情况？",{"type":19,"tag":20,"props":700,"children":701},{},[702,704,709],{"type":24,"value":703},"看到第一个应用运行在 Vue 3 上是一个我们都可以自豪的里程碑。这证明了",{"type":19,"tag":67,"props":705,"children":706},{},[707],{"type":24,"value":708},"协作和统一策略",{"type":24,"value":710},"的力量。",{"type":19,"tag":262,"props":712,"children":714},{"id":713},"从反馈中学到的东西",[715],{"type":24,"value":713},{"type":19,"tag":112,"props":717,"children":718},{},[719,729,739,749],{"type":19,"tag":91,"props":720,"children":721},{},[722,727],{"type":19,"tag":67,"props":723,"children":724},{},[725],{"type":24,"value":726},"一些组件保持\"陈旧\"",{"type":24,"value":728}," — 没有人修改它们。我们的智慧决定是：陈旧 = 稳定。这些组件可以通过手动指派来一次性迁移，因为改动很小。",{"type":19,"tag":91,"props":730,"children":731},{},[732,737],{"type":19,"tag":67,"props":733,"children":734},{},[735],{"type":24,"value":736},"Vue 3 特定功能",{"type":24,"value":738}," — 我们开始为 Kompas 添加 Vue 3 特定的特性，比如自定义的 Composables。这证明了投资的回报。",{"type":19,"tag":91,"props":740,"children":741},{},[742,747],{"type":19,"tag":67,"props":743,"children":744},{},[745],{"type":24,"value":746},"从 Vuex 到 Pinia",{"type":24,"value":748}," — 同时，我们将状态管理从 Vuex 迁移到 Pinia。同样使用渐进式方法。",{"type":19,"tag":91,"props":750,"children":751},{},[752,757],{"type":19,"tag":67,"props":753,"children":754},{},[755],{"type":24,"value":756},"Nuxt 模块到插件",{"type":24,"value":758}," — 在 Nuxt 应用中，我们将模块重写为插件。这个变化影响范围更小，因为它只影响使用这些模块的团队。",{"type":19,"tag":41,"props":760,"children":762},{"id":761},"关键经验教训",[763],{"type":24,"value":761},{"type":19,"tag":20,"props":765,"children":766},{},[767],{"type":24,"value":768},"经过这个过程，我们整理出了几个重要经验：",{"type":19,"tag":262,"props":770,"children":772},{"id":771},"_1-明确过渡期越短越好",[773],{"type":24,"value":774},"1. 明确过渡期，越短越好",{"type":19,"tag":20,"props":776,"children":777},{},[778],{"type":24,"value":779},"在宣布升级和真正完成之间，有一个窗口期。明确这个期限有助于：",{"type":19,"tag":87,"props":781,"children":782},{},[783,788,793],{"type":19,"tag":91,"props":784,"children":785},{},[786],{"type":24,"value":787},"避免决策瘫痪",{"type":19,"tag":91,"props":789,"children":790},{},[791],{"type":24,"value":792},"给团队紧迫感",{"type":19,"tag":91,"props":794,"children":795},{},[796],{"type":24,"value":797},"帮助规划资源",{"type":19,"tag":20,"props":799,"children":800},{},[801],{"type":24,"value":802},"我们设定的最后期限是 2023 年 12 月 31 日，与 Vue 2 的 EOL 一致。",{"type":19,"tag":262,"props":804,"children":806},{"id":805},"_2-将工作分解成小步骤迭代进行",[807],{"type":24,"value":808},"2. 将工作分解成小步骤，迭代进行",{"type":19,"tag":20,"props":810,"children":811},{},[812],{"type":24,"value":813},"不是\"一次大迁移\"，而是\"每个接触到的组件都升级\"。这样：",{"type":19,"tag":87,"props":815,"children":816},{},[817,822,827],{"type":19,"tag":91,"props":818,"children":819},{},[820],{"type":24,"value":821},"风险分散",{"type":19,"tag":91,"props":823,"children":824},{},[825],{"type":24,"value":826},"问题更容易调试",{"type":19,"tag":91,"props":828,"children":829},{},[830],{"type":24,"value":831},"团队不会感到被压垮",{"type":19,"tag":262,"props":833,"children":835},{"id":834},"_3-尽早频繁地寻求反馈",[836],{"type":24,"value":837},"3. 尽早、频繁地寻求反馈",{"type":19,"tag":20,"props":839,"children":840},{},[841],{"type":24,"value":842},"第一个应用升级后，立即从团队收集反馈。这让我们能快速调整策略。",{"type":19,"tag":262,"props":844,"children":846},{"id":845},"_4-让利益相关者参与",[847],{"type":24,"value":848},"4. 让利益相关者参与",{"type":19,"tag":20,"props":850,"children":851},{},[852],{"type":24,"value":853},"产品所有者需要知道这会如何影响他们的时间表。架构师需要验证方案。经理需要理解资源影响。早点让他们参与，避免后期的惊喜。",{"type":19,"tag":262,"props":855,"children":857},{"id":856},"_5-定义符合组织文化的策略",[858],{"type":24,"value":859},"5. 定义符合组织文化的策略",{"type":19,"tag":20,"props":861,"children":862},{},[863],{"type":24,"value":864},"对我们有效的策略可能对你无效。理解你的组织是如何工作的，然后设计符合这种工作方式的升级计划。",{"type":19,"tag":262,"props":866,"children":868},{"id":867},"_6-培养协作心态建立清晰沟通",[869],{"type":24,"value":870},"6. 培养协作心态，建立清晰沟通",{"type":19,"tag":20,"props":872,"children":873},{},[874],{"type":24,"value":875},"这不是一个小团队的项目。这是整个组织的事。频繁的沟通、开放的渠道和明确的所有权至关重要。",{"type":19,"tag":262,"props":877,"children":879},{"id":878},"_7-庆祝小胜利",[880],{"type":24,"value":881},"7. 庆祝小胜利",{"type":19,"tag":20,"props":883,"children":884},{},[885],{"type":24,"value":886},"第一个应用升级、第 50 个组件转换、Nuxt 3 准备就绪……每个里程碑都值得庆祝。这保持了动力。",{"type":19,"tag":41,"props":888,"children":890},{"id":889},"剩下的工作",[891],{"type":24,"value":889},{"type":19,"tag":20,"props":893,"children":894},{},[895],{"type":24,"value":896},"老实说，我们还没有完全完成。但我们现在有了一个蓝图。",{"type":19,"tag":20,"props":898,"children":899},{},[900],{"type":24,"value":901},"和许多软件工程挑战一样，这不是一个\"完成后就完成了\"的问题。Vue 创始人 Evan You 在 2023 年的演讲中提到，Vue 计划进行更频繁的更新。这意味着工具链升级的需要将继续。",{"type":19,"tag":20,"props":903,"children":904},{},[905],{"type":24,"value":906},"但现在我们知道该怎么做了。",{"type":19,"tag":41,"props":908,"children":910},{"id":909},"实用建议适用于你的团队",[911],{"type":24,"value":912},"实用建议：适用于你的团队",{"type":19,"tag":20,"props":914,"children":915},{},[916],{"type":24,"value":917},"如果你的组织面临类似的升级挑战（Vue、React、Angular 或任何其他大型工具），这里有一些可以立即应用的建议：",{"type":19,"tag":262,"props":919,"children":921},{"id":920},"评估你的情况",[922],{"type":24,"value":920},{"type":19,"tag":87,"props":924,"children":925},{},[926,936,946],{"type":19,"tag":91,"props":927,"children":928},{},[929,934],{"type":19,"tag":67,"props":930,"children":931},{},[932],{"type":24,"value":933},"依赖图的复杂性",{"type":24,"value":935}," — 有多少应用依赖这个库？",{"type":19,"tag":91,"props":937,"children":938},{},[939,944],{"type":19,"tag":67,"props":940,"children":941},{},[942],{"type":24,"value":943},"版本间的破坏性变化",{"type":24,"value":945}," — 迁移有多困难？",{"type":19,"tag":91,"props":947,"children":948},{},[949,954],{"type":19,"tag":67,"props":950,"children":951},{},[952],{"type":24,"value":953},"社区支持",{"type":24,"value":955}," — 升级社区是否有成熟的工具和文档？",{"type":19,"tag":262,"props":957,"children":959},{"id":958},"建立核心团队",[960],{"type":24,"value":958},{"type":19,"tag":20,"props":962,"children":963},{},[964],{"type":24,"value":965},"不一定很大。3-5 个有不同背景的人（前端、后端、架构、产品）足以开始规划。",{"type":19,"tag":262,"props":967,"children":969},{"id":968},"制定时间表",[970],{"type":24,"value":968},{"type":19,"tag":87,"props":972,"children":973},{},[974,984,994],{"type":19,"tag":91,"props":975,"children":976},{},[977,982],{"type":19,"tag":67,"props":978,"children":979},{},[980],{"type":24,"value":981},"调研阶段",{"type":24,"value":983}," — 2-4 周了解新版本、识别问题",{"type":19,"tag":91,"props":985,"children":986},{},[987,992],{"type":19,"tag":67,"props":988,"children":989},{},[990],{"type":24,"value":991},"过渡阶段",{"type":24,"value":993}," — 6-12 个月支持两个版本",{"type":19,"tag":91,"props":995,"children":996},{},[997,1002],{"type":19,"tag":67,"props":998,"children":999},{},[1000],{"type":24,"value":1001},"清理阶段",{"type":24,"value":1003}," — 2-4 周清理遗留代码",{"type":19,"tag":262,"props":1005,"children":1007},{"id":1006},"设置反馈循环",[1008],{"type":24,"value":1006},{"type":19,"tag":87,"props":1010,"children":1011},{},[1012,1017,1022,1027],{"type":19,"tag":91,"props":1013,"children":1014},{},[1015],{"type":24,"value":1016},"早期采用者试用新版本",{"type":19,"tag":91,"props":1018,"children":1019},{},[1020],{"type":24,"value":1021},"收集他们的问题和建议",{"type":19,"tag":91,"props":1023,"children":1024},{},[1025],{"type":24,"value":1026},"根据反馈调整方案",{"type":19,"tag":91,"props":1028,"children":1029},{},[1030],{"type":24,"value":1031},"与全组织分享学习",{"type":19,"tag":262,"props":1033,"children":1035},{"id":1034},"自动化一切",[1036],{"type":24,"value":1034},{"type":19,"tag":87,"props":1038,"children":1039},{},[1040,1045,1050],{"type":19,"tag":91,"props":1041,"children":1042},{},[1043],{"type":24,"value":1044},"CI/CD 测试两个版本",{"type":19,"tag":91,"props":1046,"children":1047},{},[1048],{"type":24,"value":1049},"自动生成迁移报告",{"type":19,"tag":91,"props":1051,"children":1052},{},[1053],{"type":24,"value":1054},"自动化代码转换工具",{"type":19,"tag":41,"props":1056,"children":1058},{"id":1057},"结论",[1059],{"type":24,"value":1057},{"type":19,"tag":20,"props":1061,"children":1062},{},[1063],{"type":24,"value":1064},"在大型组织中升级关键工具不是一个技术问题，它是一个组织、沟通和变更管理的问题。技术部分往往是最简单的部分。",{"type":19,"tag":20,"props":1066,"children":1067},{},[1068],{"type":24,"value":1069},"关键是：",{"type":19,"tag":87,"props":1071,"children":1072},{},[1073,1078,1083,1088,1093,1098],{"type":19,"tag":91,"props":1074,"children":1075},{},[1076],{"type":24,"value":1077},"有清晰的策略",{"type":19,"tag":91,"props":1079,"children":1080},{},[1081],{"type":24,"value":1082},"让所有利益相关者参与",{"type":19,"tag":91,"props":1084,"children":1085},{},[1086],{"type":24,"value":1087},"将大工作分解成小步骤",{"type":19,"tag":91,"props":1089,"children":1090},{},[1091],{"type":24,"value":1092},"保持透明和频繁的沟通",{"type":19,"tag":91,"props":1094,"children":1095},{},[1096],{"type":24,"value":1097},"庆祝进度",{"type":19,"tag":91,"props":1099,"children":1100},{},[1101],{"type":24,"value":1102},"为未来的升级建立可重复的流程",{"type":19,"tag":20,"props":1104,"children":1105},{},[1106],{"type":24,"value":1107},"这个过程很辛苦，但如果规划得当，可以相对无痛地完成。而且，下一次升级会更容易，因为你已经有了过程。",{"type":19,"tag":20,"props":1109,"children":1110},{},[1111],{"type":24,"value":1112},"升级永远不会真正\"完成\"，但现在你知道如何去做了。",{"type":19,"tag":1114,"props":1115,"children":1116},"style",{},[1117],{"type":24,"value":1118},"html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"title":7,"searchDepth":433,"depth":433,"links":1120},[1121,1122,1123,1124,1125,1129,1130,1131,1134,1143,1144,1151],{"id":43,"depth":406,"text":43},{"id":58,"depth":406,"text":58},{"id":159,"depth":406,"text":162},{"id":189,"depth":406,"text":189},{"id":253,"depth":406,"text":253,"children":1126},[1127,1128],{"id":264,"depth":433,"text":267},{"id":282,"depth":433,"text":282},{"id":320,"depth":406,"text":323},{"id":601,"depth":406,"text":601},{"id":673,"depth":406,"text":673,"children":1132},[1133],{"id":713,"depth":433,"text":713},{"id":761,"depth":406,"text":761,"children":1135},[1136,1137,1138,1139,1140,1141,1142],{"id":771,"depth":433,"text":774},{"id":805,"depth":433,"text":808},{"id":834,"depth":433,"text":837},{"id":845,"depth":433,"text":848},{"id":856,"depth":433,"text":859},{"id":867,"depth":433,"text":870},{"id":878,"depth":433,"text":881},{"id":889,"depth":406,"text":889},{"id":909,"depth":406,"text":912,"children":1145},[1146,1147,1148,1149,1150],{"id":920,"depth":433,"text":920},{"id":958,"depth":433,"text":958},{"id":968,"depth":433,"text":968},{"id":1006,"depth":433,"text":1006},{"id":1034,"depth":433,"text":1034},{"id":1057,"depth":406,"text":1057},"markdown","content:blog:vue-tooling-upgrade-strategy.md","content","blog/vue-tooling-upgrade-strategy.md","blog/vue-tooling-upgrade-strategy","md",[1159,1169,1177],{"_path":1160,"_dir":5,"_draft":6,"_partial":6,"_locale":7,"title":1161,"description":1162,"keywords":1163,"author":11,"date":1164,"category":1165,"image":14,"_type":1152,"_id":1166,"_source":1154,"_file":1167,"_stem":1168,"_extension":1157},"/blog/2025-q1-updates","2025 Q1 产品更新","第一季度重大功能发布：AI 生成优化、新模板上线、编辑器增强等","2025 Q1 产品更新, Blog, HTMLPAGE","2025-11-26","待分类","content:blog:2025-q1-updates.md","blog/2025-q1-updates.md","blog/2025-q1-updates",{"_path":1170,"_dir":5,"_draft":6,"_partial":6,"_locale":7,"title":1171,"description":1172,"keywords":1173,"author":11,"date":1164,"category":1165,"image":14,"_type":1152,"_id":1174,"_source":1154,"_file":1175,"_stem":1176,"_extension":1157},"/blog/2025-roadmap","2025 产品路线图","展望 2025 年的产品规划：AI 能力增强、模板扩充、国际化等","2025 产品路线图, Blog, HTMLPAGE","content:blog:2025-roadmap.md","blog/2025-roadmap.md","blog/2025-roadmap",{"_path":1178,"_dir":5,"_draft":6,"_partial":6,"_locale":7,"title":1179,"description":1180,"keywords":1181,"author":11,"date":1164,"category":1165,"image":14,"_type":1152,"_id":1182,"_source":1154,"_file":1183,"_stem":1184,"_extension":1157},"/blog/ab-testing","A/B 测试","通过 A/B 测试验证设计方案","A/B 测试, Blog, HTMLPAGE","content:blog:ab-testing.md","blog/ab-testing.md","blog/ab-testing",1774945276026]