Skip to content

Commit

Permalink
optimize(packages): optimized simple-router code
Browse files Browse the repository at this point in the history
  • Loading branch information
mufeng889 committed Aug 17, 2024
1 parent 98a7117 commit edfb1f6
Show file tree
Hide file tree
Showing 4 changed files with 60 additions and 99 deletions.
66 changes: 23 additions & 43 deletions packages/simple-router/src/matcher/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import type { RouteLocationNamedRaw } from '../types';
import { stringifyQuery } from '../query';
import type { RouteRecordRaw } from './types';
import { createRouteRecordMatcher } from './pathMatcher';
import { generatePath, getQueryParams, mergeMetaFields, normalizeRouteRecord } from './shared';
import { cleanParams, generatePath, getQueryParams, mergeMetaFields, normalizeRouteRecord } from './shared';

class CreateRouterMatcher {
// Internal routes maintained for react-router
Expand Down Expand Up @@ -90,21 +90,20 @@ class CreateRouterMatcher {
* @param matcherRef - The route reference, which can be a name or a matcher object.
*/
removeRoute(matcherRef: string | RouteRecordRaw) {
if (typeof matcherRef === 'string') {
const matcher = this.matcherMap.get(matcherRef);
if (matcher) {
this.removeMatcherMapByName(matcherRef);
this.matchers.splice(this.matchers.indexOf(matcher), 1);
const matcher = typeof matcherRef === 'string' ? this.matcherMap.get(matcherRef) : matcherRef;

matcher.children.forEach(this.removeRoute);
}
} else {
const index = this.matchers.indexOf(matcherRef);
if (index > -1) {
this.matchers.splice(index, 1);
if (matcherRef.record.name) this.removeMatcherMapByName(matcherRef.record.name);
matcherRef.children.forEach(this.removeRoute);
}
if (!matcher) return;

// Recursively remove children
matcher.children.forEach(child => this.removeRoute(child));

const index = this.matchers.indexOf(matcher);
if (index !== -1) {
this.matchers.splice(index, 1);
}

if (matcher.record.name) {
this.removeMatcherMapByName(matcher.record.name);
}
}

Expand Down Expand Up @@ -132,35 +131,18 @@ class CreateRouterMatcher {
throw new Error('there is no such route');
}

name = matcher.record.name;
if ('params' in location) {
const params = location.params || {};
const cleanedParams: { [key: string]: string | number } = {};

Object.keys(params).forEach(key => {
const value = params[key];
if (typeof value === 'string' || typeof value === 'number') {
cleanedParams[key] = value;
} else if (Array.isArray(value)) {
cleanedParams[key] = value.join(',');
}
});

fullPath = generatePath(matcher.record.path, cleanedParams);
} else {
fullPath = matcher.record.path;
}
if ('query' in location) {
query = location.query || {};

const queryParams = stringifyQuery(query);
matcher = this.matcherMap.get(location.name);
if (!matcher) throw new Error('No such route');

fullPath += queryParams ? `?${queryParams}` : '';
}
// throws if cannot be stringified
name = matcher.record.name;
const params = cleanParams(location.params || {});
fullPath = generatePath(matcher.record.path, params);
query = location.query || {};
const queryParams = stringifyQuery(query);
fullPath += queryParams ? `?${queryParams}` : '';
path = matcher.record.path;
component = matcher.record.component;
} else if (location.pathname !== null) {
} else if (location.pathname) {
// no need to resolve the path with the matcher as it was provided
// this also allows the user to control the encoding
path = location.pathname;
Expand All @@ -169,8 +151,6 @@ class CreateRouterMatcher {
// matcher should have a value after the loop
query = getQueryParams(location.search);
if (matcher) {
// we know the matcher works because we tested the regexp

name = matcher.record.name;
fullPath = location.pathname + location.search;
component = matcher.record.component;
Expand Down
19 changes: 19 additions & 0 deletions packages/simple-router/src/matcher/shared.ts
Original file line number Diff line number Diff line change
Expand Up @@ -78,3 +78,22 @@ export function getQueryParams(search: string): LocationQuery {
export function mergeMetaFields(matched: RouteRecordNormalized[]) {
return matched.reduce((meta, record) => Object.assign(meta, record.meta), {});
}

/**
* Cleans and filters out null/undefined parameters.
*
* @param params - The raw parameters.
* @returns The cleaned parameters.
*/
export function cleanParams(params: Record<string, any>): Record<string, string | number> {
return Object.keys(params).reduce(
(acc, key) => {
const value = params[key];
if (value !== null && value !== undefined) {
acc[key] = Array.isArray(value) ? value.join(',') : value;
}
return acc;
},
{} as Record<string, string | number>
);
}
62 changes: 13 additions & 49 deletions packages/simple-router/src/router.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -165,24 +165,11 @@ class CreateRouter {
if ('pathname' in rawLocation) {
matcherLocation = rawLocation;
} else {
// remove any nullish param
const targetParams: Record<string, any> = {};
for (const key in rawLocation.params) {
if (rawLocation.params[key] !== null || rawLocation.params[key] !== undefined) {
targetParams[key] = rawLocation.params[key];
}
}
const targetQuery: Record<string, any> = {};
for (const key in rawLocation.query) {
if (rawLocation.query[key] !== null || rawLocation.query[key] !== undefined) {
targetQuery[key] = rawLocation.query[key];
}
}
// pass encoded values to the matcher, so it can produce encoded path and fullPath

matcherLocation = Object.assign(rawLocation, {
params: targetParams,
query: targetQuery
params: cleanParams(rawLocation.params),
query: cleanParams(rawLocation.query)
});
}

Expand All @@ -195,16 +182,9 @@ class CreateRouter {
}

CustomRouterProvider: (loading: React.ReactNode) => JSX.Element = loading => {
const reactiveRoute = {} as RouteLocationNormalizedLoaded;

for (const key in START_LOCATION_NORMALIZED) {
if (Object.hasOwn(START_LOCATION_NORMALIZED, key)) {
Object.defineProperty(reactiveRoute, key, {
get: () => this.currentRoute[key as keyof RouteLocationNormalizedLoaded],
enumerable: true
});
}
}
const reactiveRoute = new Proxy(this.currentRoute, {
get: (_, key) => this.currentRoute[key as keyof RouteLocationNormalizedLoaded]
});

return (
<RouterContext.Provider value={this}>
Expand All @@ -228,9 +208,7 @@ class CreateRouter {
* @param key Route key
*/
getRouteMetaByKey(key: string) {
const allRoutes = this.getRoutes();

return allRoutes.find(route => route.name === key)?.meta || null;
return this.getRoutes().find(route => route.name === key)?.meta || null;
}

afterRouteChange = (state: RouterState, afterEach: RouterOptions['afterEach']) => {
Expand Down Expand Up @@ -260,35 +238,21 @@ class CreateRouter {
* @returns The route record or false if not found.
*/
getRouteByName(name: string): RouteRecordNormalized | undefined {
const route = this?.matcher.getRecordMatcher(name);
return route?.record;
return this.matcher.getRecordMatcher(name)?.record;
}

push(to: RouteLocationNamedRaw | string) {
if (typeof to === 'string') {
this.reactRouter.navigate(to);
return;
}

const toLocation = this.resolve(to);
const target = typeof to === 'string' ? to : this.resolve(to).fullPath;

const finalRedirectName = getChildrenName(toLocation.matched[toLocation.matched.length - 1]);
if (finalRedirectName === this.currentRoute.name) {
return;
if (target !== this.currentRoute.fullPath) {
this.reactRouter.navigate(target);
}

this.reactRouter.navigate(toLocation.fullPath);
}
}

export default CreateRouter;

function getChildrenName(route: RouteRecordNormalized | ElegantConstRoute): string | undefined {
// If the route has children, recursively call this function for the first child route
if (route?.children) {
return getChildrenName(route.children[0]);
}

// If the route has no children, return the name of the route itself
return route?.name;
function cleanParams(params: Record<string, any> | undefined): Record<string, any> {
if (!params) return {};
return Object.fromEntries(Object.entries(params).filter(([_, value]) => value !== null));
}
12 changes: 5 additions & 7 deletions src/router/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,16 @@ import type { Router as RemixRouter } from '@remix-run/router';
import { localStg } from '@/utils/storage';
import { store } from '@/store';
import { initAuthRoute, initConstantRoute } from '@/store/slice/route';
import { initTabStore } from '@/store/slice/tab';
import { layouts, pages } from './elegant/imports';
import {initTabStore} from '@/store/slice/tab'
import { transformElegantRouteToReactRoute } from './elegant/transform';
import { createRouteGuard,afterEach } from './guard';
import { afterEach, createRouteGuard } from './guard';
import { builtinRoutes } from './routes/builtin';

const { VITE_ROUTER_HISTORY_MODE = 'history', VITE_BASE_URL } = import.meta.env;

/**
* Get auth vue routes
* Get auth react routes
*
* @param routes Elegant routes
*/
Expand All @@ -32,7 +32,7 @@ async function init(reactRouter: RemixRouter) {
}

function initBeforeRoute(allNames: string[]) {
store.dispatch(initTabStore(allNames))
store.dispatch(initTabStore(allNames));
}

export const router = new CreateRouter({
Expand All @@ -43,7 +43,5 @@ export const router = new CreateRouter({
init,
beforeEach: createRouteGuard,
afterEach,
firstInit:initBeforeRoute
firstInit: initBeforeRoute
});

// createRouterGuard(routers.beforeEach, routers.afterEach);

0 comments on commit edfb1f6

Please sign in to comment.