How to Migrate Legacy Vue Links to a React Stack with Seamless Redirection
This article explains the challenges of migrating legacy Vue applications to a unified React stack, focusing on external link redirection, route parameter handling, and unified routing conventions, and provides a concrete implementation using Nginx, path-to-regexp, and a custom Redirector class.
Background
Currently the front‑end team at Guming uses a unified React stack for new projects, but many legacy Vue apps remain in production. To reduce cognitive load, align with infrastructure, and improve maintainability, these old projects need to be migrated and external links must be managed.
Current Situation and Goals
External link redirection issues
External links are time‑sensitive and static, so the team uses redirect logic in navigation guards to map old routes to new ones. After the old project is taken offline, those redirects disappear, making the links inaccessible.
Some external links are unknown to product teams, causing unexpected feedback when routes change.
Route parameter mental load
During migration, many routes pass numerous URL parameters without a unified convention, complicating maintenance.
Goals
Preserve legacy route redirects to keep old links functional.
Operational visibility – log accesses, detect 404s, and alert owners.
Unified stack and standards – adopt the new front‑end infrastructure and define a common routing specification.
Core Code Design and Implementation
Route Redirection
How to forward – Nginx, NodeJS or JavaScript?
Because hash routes (e.g., #) are not sent to the server, Nginx and Node cannot read them, so the redirect must be handled on the client. Nginx only forwards the base path ( /) to /college.
API design
A configuration‑driven API replaces scattered if‑else logic with a redirect table. Example registration:
const redirector = new Redirector()
.register('/knowledge/learnList', '/pages/material-list/index')
.register('/knowledge/detail/:id', '/pages/material-detail/index?id=:id');Calling redirector.run() executes the redirect based on the current hash.
Redirect table design
Parameter types
Two kinds of route parameters are handled: params (part of the path, e.g., /pending/list/1234567) and query (key‑value pairs after ?, e.g., /pages/list/index?id=1234567). The implementation maps params and preserves query to keep input and output signatures identical.
Regex‑based matching
The path-to-regexp library converts route patterns into regular expressions, enabling dynamic parameter extraction.
Redirector class
import { history } from '@tarojs/router';
import Taro from '@tarojs/taro';
import { match, MatchFunction } from 'path-to-regexp';
type RegisterPath = `/${string}`;
interface RouteObject {
matchFn: MatchFunction;
target: string;
}
class Redirector {
private routes: RouteObject[] = [];
register(oldPath: RegisterPath, newPath: RegisterPath): Redirector {
this.routes.push({ matchFn: match(oldPath), target: newPath });
return this;
}
redirect(path: string, query = ''): void {
this.routes.some(({ matchFn, target }) => {
const result = matchFn(path);
if (result) {
Object.entries(result.params).forEach(([key, value]) => {
target = target.replace(`:${key}`, value);
});
target = `${target}${target.includes('?') ? '&' : '?'}${query}`;
Taro.redirectTo({ url: target });
return true;
}
return false;
});
}
run(): void {
const [path, query] = location.hash.slice(1).split('?');
this.redirect(path, query);
}
}
const redirector = new Redirector()
.register('/knowledge/learnList', '/pages/material-list/index')
.register('/knowledge/detail/:id', '/pages/material-detail/index?id=:id');
export default redirector;Execution flow
The C‑end H5 micro‑app consists of the old Vue2 project (served at / ) and the new Taro React project (served at /college ). Nginx forwards requests to the appropriate base path, allowing shared localStorage and sessionStorage.
(1) User request and Nginx forwarding
Example old link: https://host/#/knowledge/learnList?rankId=aaa&ListName=bbb is first redirected by Nginx to
https://host/college/#/knowledge/learnList?rankId=aaa&ListName=bbb.
(2) Client‑side redirect
In app.tsx the redirector is invoked on mount:
// app.tsx
import redirector from '@/utils';
function App({ children }) {
useMount(() => {
redirector.run();
});
}Operation awareness
404 detection
If a redirect fails, a 404 is logged and the user is sent to a custom 404 page:
function App({ children }) {
usePageNotFound(e => {
const tag = 'PAGE_NOT_FOUND';
const log = `path=${e.path}`;
Slardar.logger()?.error(log, tag);
Taro.redirectTo({ url: `/pages/404/index?from=${e.path}` });
});
}Redirect logging
Each successful redirect records the source and target URLs for later analysis.
class Redirector {
// ... inside redirect()
const tag = 'PAGE_NOT_FOUND';
const log = `from=${path}&to=${target}`;
Slardar.logger()?.info(log, tag);
}Unified routing convention
To reduce parameter noise, the team enforces TypeScript definitions for page input types and provides shared utilities formatUrlParams and getUrlParams for consistent navigation and deserialization.
import { BaseAssignmentParams } from "@/pages/assignment/index/index";
const handleClick = (assignment: CourseAssignmentItem) => {
const baseQuery = formatUrlParams<AssignmentParams>({
trainingId: trainingDetail.id,
semesterId: trainingDetail.semesterId,
assignmentId: assignment.id,
});
Taro.navigateTo({ url: `/pages/assignment/index/index?${baseQuery}` });
};
export interface AssignmentParams {
trainingId: string;
semesterId: string;
assignmentId: string;
}
const { semesterId, trainingId, assignmentId } = getUrlParams<AssignmentParams>();Summary
The article presents a practical approach to handling external link migration, unified routing, and operational monitoring when moving legacy Vue projects to a modern React stack, offering reusable code and guidelines to reduce technical debt.
Goodme Frontend Team
Regularly sharing the team's insights and expertise in the frontend field
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
