Skip to content

Commit 68499d4

Browse files
authored
chore: Fork client-side router decoupling it from Meteor APIs (RocketChat#36602)
1 parent 8f2cfa4 commit 68499d4

12 files changed

Lines changed: 591 additions & 413 deletions

File tree

apps/meteor/.meteor/packages

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,4 +69,3 @@ autoupdate@2.0.1
6969

7070
zodern:types
7171
zodern:standard-minifier-js
72-
ostrio:flow-router-extra

apps/meteor/.meteor/versions

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,6 @@ oauth1@1.5.2
6262
oauth2@1.3.3
6363
ordered-dict@1.2.0
6464
ostrio:cookies@2.7.2
65-
ostrio:flow-router-extra@3.11.0
6665
promise@1.0.0
6766
random@1.2.2
6867
rate-limit@1.1.2

apps/meteor/client/main.ts

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,6 @@
11
import './serviceWorker';
22
import './startup/accounts';
33

4-
import { FlowRouter } from 'meteor/ostrio:flow-router-extra';
5-
6-
FlowRouter.wait();
7-
8-
FlowRouter.notFound = {
9-
action: () => undefined,
10-
};
11-
124
import('@rocket.chat/fuselage-polyfills')
135
.then(() => import('./meteorOverrides'))
146
.then(() => import('./ecdh'))

apps/meteor/client/providers/RouterProvider.tsx

Lines changed: 4 additions & 203 deletions
Original file line numberDiff line numberDiff line change
@@ -1,210 +1,11 @@
1-
import type { RoomType, RoomRouteData } from '@rocket.chat/core-typings';
21
import { RouterContext } from '@rocket.chat/ui-contexts';
3-
import type {
4-
RouterContextValue,
5-
RouteName,
6-
LocationPathname,
7-
RouteParameters,
8-
SearchParameters,
9-
To,
10-
RouteObject,
11-
LocationSearch,
12-
} from '@rocket.chat/ui-contexts';
13-
import { FlowRouter } from 'meteor/ostrio:flow-router-extra';
14-
import { Tracker } from 'meteor/tracker';
2+
import type { RouterContextValue } from '@rocket.chat/ui-contexts';
153
import type { ReactNode } from 'react';
164

17-
import { appLayout } from '../lib/appLayout';
18-
import { roomCoordinator } from '../lib/rooms/roomCoordinator';
19-
import { queueMicrotask } from '../lib/utils/queueMicrotask';
5+
import { Router } from '../router';
206

21-
const subscribers = new Set<() => void>();
22-
23-
const listenToRouteChange = () => {
24-
FlowRouter.watchPathChange();
25-
subscribers.forEach((onRouteChange) => onRouteChange());
26-
};
27-
28-
let computation: Tracker.Computation | undefined;
29-
30-
queueMicrotask(() => {
31-
computation = Tracker.autorun(listenToRouteChange);
32-
});
33-
34-
const subscribeToRouteChange = (onRouteChange: () => void): (() => void) => {
35-
subscribers.add(onRouteChange);
36-
37-
computation?.invalidate();
38-
39-
return () => {
40-
subscribers.delete(onRouteChange);
41-
42-
if (subscribers.size === 0) {
43-
queueMicrotask(() => computation?.stop());
44-
}
45-
};
46-
};
47-
48-
const getLocationPathname = () => FlowRouter.current().path.replace(/\?.*/, '') as LocationPathname;
49-
50-
const getLocationSearch = () => location.search as LocationSearch;
51-
52-
const getRouteParameters = () => (FlowRouter.current().params ?? {}) as RouteParameters;
53-
54-
const getSearchParameters = () => (FlowRouter.current().queryParams ?? {}) as SearchParameters;
55-
56-
const getRouteName = () => FlowRouter.current().route?.name as RouteName | undefined;
57-
58-
const encodeSearchParameters = (searchParameters: SearchParameters) => {
59-
const search = new URLSearchParams();
60-
61-
for (const [key, value] of Object.entries(searchParameters)) {
62-
search.append(key, value);
63-
}
64-
65-
const searchString = search.toString();
66-
67-
return searchString ? `?${searchString}` : '';
68-
};
69-
70-
const buildRoutePath = (to: To): LocationPathname | `${LocationPathname}?${LocationSearch}` => {
71-
if (typeof to === 'string') {
72-
return to;
73-
}
74-
75-
if ('pathname' in to) {
76-
const { pathname, search = {} } = to;
77-
return (pathname + encodeSearchParameters(search)) as LocationPathname | `${LocationPathname}?${LocationSearch}`;
78-
}
79-
80-
if ('pattern' in to) {
81-
const { pattern, params = {}, search = {} } = to;
82-
return Tracker.nonreactive(() => FlowRouter.path(pattern, params, search)) as
83-
| LocationPathname
84-
| `${LocationPathname}?${LocationSearch}`;
85-
}
86-
87-
if ('name' in to) {
88-
const { name, params = {}, search = {} } = to;
89-
return Tracker.nonreactive(() => FlowRouter.path(name, params, search)) as LocationPathname | `${LocationPathname}?${LocationSearch}`;
90-
}
91-
92-
throw new Error('Invalid route');
93-
};
94-
95-
const navigate = (
96-
toOrDelta: To | number,
97-
options?: {
98-
replace?: boolean;
99-
},
100-
) => {
101-
if (typeof toOrDelta === 'number') {
102-
history.go(toOrDelta);
103-
return;
104-
}
105-
106-
const path = buildRoutePath(toOrDelta);
107-
const state = { path };
108-
109-
if (options?.replace) {
110-
history.replaceState(state, '', path);
111-
} else {
112-
history.pushState(state, '', path);
113-
}
114-
115-
dispatchEvent(new PopStateEvent('popstate', { state }));
116-
};
117-
118-
const routes: RouteObject[] = [];
119-
const routesSubscribers = new Set<() => void>();
120-
121-
const updateFlowRouter = () => {
122-
if (FlowRouter._initialized) {
123-
FlowRouter._updateCallbacks();
124-
FlowRouter._page.dispatch(new FlowRouter._page.Context(FlowRouter._current.path));
125-
return;
126-
}
127-
128-
FlowRouter.initialize({
129-
hashbang: false,
130-
page: {
131-
click: true,
132-
},
133-
});
134-
};
135-
136-
const defineRoutes = (routes: RouteObject[]) => {
137-
const flowRoutes = routes.map((route) => {
138-
if (route.path === '*') {
139-
FlowRouter.notFound = {
140-
action: () => appLayout.render(<>{route.element}</>),
141-
};
142-
143-
return FlowRouter.notFound;
144-
}
145-
146-
return FlowRouter.route(route.path, {
147-
name: route.id,
148-
action: () => appLayout.render(<>{route.element}</>),
149-
});
150-
});
151-
152-
routes.push(...routes);
153-
const index = routes.length - 1;
154-
155-
updateFlowRouter();
156-
routesSubscribers.forEach((onRoutesChange) => onRoutesChange());
157-
158-
return () => {
159-
flowRoutes.forEach((flowRoute) => {
160-
FlowRouter._routes = FlowRouter._routes.filter((r) => r !== flowRoute);
161-
if ('name' in flowRoute && flowRoute.name) {
162-
delete FlowRouter._routesMap[flowRoute.name];
163-
} else {
164-
FlowRouter.notFound = {
165-
action: () => appLayout.render(<></>),
166-
};
167-
}
168-
});
169-
170-
if (index !== -1) {
171-
routes.splice(index, 1);
172-
}
173-
174-
updateFlowRouter();
175-
routesSubscribers.forEach((onRoutesChange) => onRoutesChange());
176-
};
177-
};
178-
179-
const getRoutes = () => routes;
180-
181-
const subscribeToRoutesChange = (onRoutesChange: () => void): (() => void) => {
182-
routesSubscribers.add(onRoutesChange);
183-
184-
onRoutesChange();
185-
186-
return () => {
187-
routesSubscribers.delete(onRoutesChange);
188-
};
189-
};
190-
191-
/** @deprecated */
192-
export const router: RouterContextValue = {
193-
subscribeToRouteChange,
194-
getLocationPathname,
195-
getLocationSearch,
196-
getRouteParameters,
197-
getSearchParameters,
198-
getRouteName,
199-
buildRoutePath,
200-
navigate,
201-
defineRoutes,
202-
getRoutes,
203-
subscribeToRoutesChange,
204-
getRoomRoute(roomType: RoomType, routeData: RoomRouteData) {
205-
return { path: roomCoordinator.getRouteLink(roomType, routeData) || '/' };
206-
},
207-
};
7+
/** @deprecated consume it from the `RouterContext` instead */
8+
export const router: RouterContextValue = new Router();
2089

20910
type RouterProviderProps = {
21011
children?: ReactNode;

0 commit comments

Comments
 (0)