A Weekend-by-Weekend Vue 2 to Vue 3 Migration That Actually Shipped
Disclaimer: The refactoring was done during a business lull and did not delay normal iterations. Don't secretly do this like I did; it's best to report it in advance.
The company project is a 3-year-old Vue 2 backend system. The codebase isn't large (just over 50 pages), but it has a "long history" — it went through four frontend developers, each with a different style, no TypeScript, no component library standards, and console.log everywhere.
I spent three weekends (Friday nights + all day Saturdays) upgrading it to Vue 3 + TS + Vite. It wasn't to show off; I was genuinely fed up.
Week 1: Building the skeleton, solving the "it runs" problem
First, I ran the migration tool from @vue/cli, but it only solved about 30% of the issues. The rest was done manually:
- Options API → Composition API: This was the most painful part. Some component logic was scattered across
data,computed, andmethods. During the refactor, I had to first untangle the logical relationships. My strategy was: don't change the logic yet, just change the syntax, ensuring the behavior remains identical. - Vue Router 3 → 4: The main issue was that
router.addRouteswas deprecated and replaced withrouter.addRoute. There were also minor changes to the navigation guard syntax. - Vuex → Pinia: This was actually the most satisfying part. Pinia's TypeScript support is so much better; you don't need to write as many type declarations.
I modified 20 pages over the weekend. When I came to the office on Monday for testing, I found that a form submission on one page was unresponsive. After debugging for half a day, I realized the default behavior of v-model had changed in Vue 3 — the .sync modifier was removed, and I had missed updating one place.
Lesson learned: Go through the migration guide item by item; don't rely on memory.
Week 2: Adding TypeScript, solving the "reliable" problem
Vue 3's support for TS is much better, but there are still pitfalls:
defineComponentprops types: I'm used to defining props with interfaces, but I found that if an interface has optional properties, using them in the template throws an error. I ended up usingPropTypefor explicit declarations, or usingwithDefaultsdirectly.- Generic inference for
ref:ref(null)is inferred by default asRef<null>, which causes an error if you later assign an object. You must explicitly writeref<User | null>(null). - Types for third-party libraries: Some old libraries don't have
@types, so you have to write your own.d.tsfiles. I accumulated these in ashims-custom.d.tsfile specifically for this purpose.
The most satisfying moment: After the changes, the IDE's autocomplete finally worked properly. Writing code before was like a blind man feeling an elephant; now it's like having a third eye opened.
Week 3: Engineering optimization, solving the "maintainable" problem
- ESLint + Prettier + Husky: Previously, the code style depended on my mood that day. Now it's automatically formatted before commits. I configured relatively loose rules; being too strict kills motivation.
- Auto-importing components: Using
unplugin-vue-componentsmeans you don't have to manually import components. But be careful: if component names conflict (e.g., a custom Button and Element Plus's Button), you need to specify them explicitly. - Environment variable management: I extracted the API addresses and tracking keys for development, testing, and production into
.envfiles. Previously, these were hardcoded in the code, requiring a new release for every change. Now, you just modify the configuration.
Why did my colleagues come asking for my code?
The week after the refactoring, the neighboring team also needed to upgrade to Vue 3. Their team lead came directly to copy my configuration. I said, "Actually, there are better solutions on Juejin..." He replied, "Yours works, so I want yours."
True story.
The value of refactoring isn't how advanced the tech is, but that it "can be implemented"
I now believe that the best practice for frontend engineering isn't using the latest technology; it's enabling the least skilled person on the team to write qualified code. ESLint is for mistake-proofing, TypeScript is for error-proofing, and automation tools save time.
Finally, here are the key dependency versions from my package.json (for reference):
JSON
{
"vue": "^3.4.0",
"vite": "^5.0.0",
"typescript": "^5.3.0",
"pinia": "^2.1.0",
"vue-router": "^4.2.0"
}
I want to ask everyone:
What tech stack does your company project use? Are you also considering upgrading to Vue 3? Or if you've already encountered pitfalls, feel free to share, and I'll help you avoid them.
Top 36 of 55 from juejin.cn, machine-translated. The original thread is authoritative.
Your passion for technology is something I acknowledge, but if I met a colleague like this I would stay far away. Reasons: 1. No standardized plan or milestones, relying purely on personal experience and enthusiasm. What if the schedule slips? What if you hit a technical bottleneck? 2. Even if the refactor only changes structure and not logic, problems can still arise: edge cases, compatibility issues — were these communicated with QA? Did all test cases pass? 3. The whole process was never synced with management or the team; solo operation. 4. What happens if issues arise after going live? Was there a contingency plan? Support personnel? Who takes accountability? This kind of work — donating credit to the company while keeping all the risk for yourself — is only suitable for personal demo projects, not production systems. These are just some of my immature thoughts. Hope they give you a little food for thought.
😊 Thank you for your thoughtful comment. I'll do a proper retrospective on this 👍
No problem.
Great, another pot to carry. You refactor on your own overtime, and later every bug in this project will basically be yours to own.
Haha
Haha, that risk is real, so I confirmed the schedule with my boss before the refactor — I didn't do it in secret 😂 And I split the changes into four PRs, each with a rollback plan. If bugs do appear, the whole team shares the blame, not just me. Ah, whatever, hahaha
[cry-laugh] How much do they pay you a month to hustle this hard? Originally, others could have plenty of work maintaining the old project, but you went and turned it into this Vue 3 setup. A textbook scab. If you've got that much technical drive, why not go contribute to open source? No matter how awesome you make a company project, can you show the source code to your next interviewer?
[sob][sob][sob]
A week later, the boss: 'What the hell is going on! It was working fine before!' The team lead next door: 'It was Kirk Qiqi who did it.'
[cry-laugh][cry-laugh][cry-laugh]
You think after the refactor you'll have an easier time maintaining it. In reality, what the boss sees is: it used to need 10 people to maintain, now it only needs 5. Half the team gets laid off, and you keep working overtime.
The tech stack isn't the problem. The problem is you don't need to write a single line of code by hand anymore — AI does it all. Refactoring that little bit of frontend stuff is pretty meaningless.
No problem, AI can indeed write code. But this refactor was mainly about untangling the ball of mud so AI can take over more easily later 😂 Otherwise the prompting cost would be higher than manual work...
The prompt just needs the words 'Vue 3, TypeScript, refactor.' Use Ops or GPT, get it done in an hour with almost no bugs.
If the backend project errors won't cause major impact, then refactoring is fine. Otherwise, better to keep the status quo — if it runs, it runs. Don't take the initiative to change things on your own. After all, four frontend devs have touched it; you have no idea how many landmines are buried. If you must change it, don't touch the business logic (simple back-office projects excepted).
Got it! Thanks for the comment [rose]
The current project is Vue 2, and refactoring it is fraught with risk [smile]
[sob]
My goal is full automation. .claude/skills/vue2upgrade/ ├── SKILL.md # Main skill definition file ├── references/ │ ├── task-tracker.md # Task tracker │ └── tasks/ │ ├── A-vue-core/ # A. Vue core upgrade │ │ ├── 01-Environment-prep-and-dependency-upgrade.md │ │ ├── 02-Vue-core-upgrade.md │ │ ├── 03-VueRouter-upgrade.md │ │ ├── 04-Vuex-upgrade.md │ │ ├── 05-VueI18n-upgrade.md │ │ ├── 06-Deep-block-syntax-fix.md │ │ ├── 07-JSX-syntax-support-config.md │ │ └── 08-Remove-Vue2-filters.md │ ├── B-element-plus/ # B. Element Plus migration │ │ ├── 01-Element-UI-to-Element-Plus-migration.md │ │ ├── 02-SCSS-theme-and-size-prop-migration.md │ │ ├── 03-Component-import-and-prop-migration.md │ │ └── 04-ElementPlus-theme-CSS-variable-sync.md │ ├── C-syntax-adapt/ # C. Syntax adaptation │ │ ├── 01-Syntax-adaptation-and-compatibility.md │ │ ├── 02-v-if-and-v-for-conflict-fix.md │ │ ├── 04-Custom-directive-migration-fix.md │ │ ├── 05-Custom-directive-and-component-registration.md │ │ ├── 06-Slot-and-modifier-migration.md │ │ ├── 07-Vue2-API-removal-and-component-refactor.md │ │ ├── 08-sync-modifier-migration.md │ │ ├── 09-addEventListener-error-troubleshooting.md │ │ ├── 10-Vue-Router-duplicate-route-name-handling.md │ │ └── 11-Template-tag-and-compilation-error-fix.md │ ├── D-third-party/ # D. Third-party component migration │ │ ├── 01-Third-party-component-migration.md │ │ └── 02-vue-treeselect-to-el-tree-select-migration.md │ ├── F-verification/ # F. Testing and verification │ │ ├── 01-Testing-and-verification.md │ │ ├── 02-ESLint-error-fix.md │ │ └── 03-Issues-found-and-fixes-during-upgrade.md │ └── G-css/ # G. CSS style refactor │ └── 01-CSS-style-refactor.md
The boss finally has you on a leash now 😊
[cry-laugh]
When I was young, I was just like you — full of energy, wanting to refactor every project I saw [facepalm]
[rose][rose][rose]
.. So idle you actually have time to code on weekends
[wronged]
[sweat] Didn't QA thank you?
QA said: 'Change the cache time to 5 minutes? What took you so long?' 😂 But honestly, after the optimization, their regression testing got way easier — at least they don't have to wait two seconds every time.
Migrating Vue 2 to Vue 3 is inherently simple. Try migrating Vue 2 to Nuxt.js [rainbow-vomit][rainbow-vomit][rainbow-vomit]
True, Vue 2 to Vue 3 is just a warm-up 😂 We evaluated a Nuxt 3 migration — the SSR compatibility issues were a real headache [sob]
Piggybacking here to recommend a Vue component management tool I built myself, comp-hub — born from stepping on landmines. I wonder if anyone else has had this experience: when developing a new feature, you clearly remember writing a similar component in another project, but finding it, extracting it from that project, stripping out all the business coupling and redundant imports — the whole process is more exhausting than rewriting from scratch. In the short term you can get by with 'decoupling,' but over time, quality components end up scattered across projects and you can't even remember where they are. So I just built this tool: upload component source code together with preview configs, manage and preview them centrally through a web interface. When you need one, just search, preview the effect online, and download if it fits — no need to dig through source code. The core idea in one sentence: turn those 'written but unfindable' shared components in your team into reusable assets you can grab anytime. There's detailed documentation — check it out if you're interested 👇 https://docs.comphub.cn/zh/
Speaking of which, how do you complete TypeScript coverage? I refactored a project before and the API docs were completely lost — had to abandon TypeScript.
So boring. Giving yourself extra work. Better to write your own stuff.
The hardest part of a refactor isn't the code itself — it's pushing it forward without affecting the business. Finishing in three weekends shows good planning. Component-based splitting does improve maintainability a lot, but without matching unit test coverage, subsequent iterations will still easily bury landmines.
Been through two companies, and refactors always got abandoned halfway.
At the very least, QA should have done a full regression.
Two years ago I refactored both web and mini-program — that was genuinely difficult. Vue 2 to Vue 3, we also swapped the UI framework, and the coding style changed almost entirely. The early phase spent a lot of time on business components, then reading the original business logic code — that was brain-melting [petrified][petrified][petrified]
You dare touch a ball-of-mud codebase — you're truly something else.
Scab. Treating some crud app like a treasure. If you've got the skills, go contribute to open source communities!
Damn, hustling this hard?
All I can say is: bored out of your mind.
If you've really got nothing to do, go fishing.
Dumb luck.
Why was this feature working fine before, and now it's broken?
You need to make sure the old-timers can get their severance package before you pull this...
1
All I can say is you've got guts. Even upgrading Webpack to Rspack, I had to beg QA to do a full test run — and that's only because we're on good terms. If the relationship wasn't good, this is what you'd call 'looking for trouble.'
Was it because AI showed up that you decided to refactor on your own? [politely-smiling]
God-tier article.
Three weekends to refactor a frontend project — that efficiency is very real. AI-assisted refactoring really does speed things up a lot. The detail about the boss not noticing but colleagues coming to ask for the code is interesting — it shows the code quality genuinely improved.
Quietly refactoring and then letting the code speak for itself — that's a pretty clever strategy 😄 But now with AI-assisted refactoring, efficiency is much higher. What used to take three weekends might now be done in one. AI writes the boilerplate, and you focus on architectural decisions. Nice rhythm.
Why not have AI create a new project for the refactor instead of modifying the original one?