Skip to content

Commit 0aeebfb

Browse files
committed
fix(web): adds wc teardown for micro-frontend environments
1 parent db41862 commit 0aeebfb

18 files changed

+178
-60
lines changed

package.json

+2-2
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@
3939
"dev:web": "VITE_SOURCEMAP=true VITE_WEB=true VITE_BASE=/trakt-extension/ run-s dev",
4040
"build": "cross-env NODE_ENV=production run-s dist type:check 'vite:build {@}' --",
4141
"build:web": "VITE_WEB=true VITE_BASE=/trakt-extension/ pnpm run build",
42-
"serve:web": "VITE_SOURCEMAP=true VITE_WEB=true VITE_BASE=/web-extension-template/ run-s build vite:preview",
42+
"serve:web": "VITE_SOURCEMAP=true VITE_WEB=true VITE_BASE=/trakt-extension/ run-s build vite:preview",
4343
"analyse": "vite-bundle-visualizer",
4444
"test:unit": "vitest run --coverage --mode testing",
4545
"test:watch": "vitest --mode testing",
@@ -56,7 +56,7 @@
5656
"@dvcol/simkl-http-client": "^1.1.8",
5757
"@dvcol/tmdb-http-client": "^1.3.10",
5858
"@dvcol/trakt-http-client": "^1.4.16",
59-
"@dvcol/web-extension-utils": "^3.4.3",
59+
"@dvcol/web-extension-utils": "^3.4.4",
6060
"@vue/devtools": "^7.4.6",
6161
"naive-ui": "^2.40.1",
6262
"pinia": "^2.2.4",

pnpm-lock.yaml

+6-6
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/services/error.service.ts

+5
Original file line numberDiff line numberDiff line change
@@ -44,4 +44,9 @@ export class ErrorService {
4444
static since(date: Date) {
4545
return this._errors.filter(({ date: errorDate }) => errorDate > date);
4646
}
47+
48+
static clear() {
49+
this._errors = [];
50+
this._dictionaries = {};
51+
}
4752
}

src/services/loading-bar.service.ts

+7-1
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,18 @@ import type { useLoadingBar } from 'naive-ui';
55
import { Logger } from '~/services/logger.service';
66

77
export class LoadingBarService {
8-
private static instance: ReturnType<typeof useLoadingBar>;
8+
private static instance?: ReturnType<typeof useLoadingBar>;
99
private static counter = ref(0);
1010

1111
static init(instance: ReturnType<typeof useLoadingBar>) {
1212
this.instance = instance;
1313
}
1414

15+
static destroy() {
16+
this.instance = undefined;
17+
this.counter.value = 0;
18+
}
19+
1520
static get isLoading() {
1621
return this.counter.value > 0;
1722
}
@@ -30,6 +35,7 @@ export class LoadingBarService {
3035

3136
private static debounceStart(debounce: number) {
3237
return setTimeout(() => {
38+
if (!this.instance?.start) return Logger.warn('LoadingBarService instance is not initialized');
3339
if (this.isLoading) this.instance.start();
3440
}, debounce);
3541
}

src/services/navbar.service.ts

+9
Original file line numberDiff line numberDiff line change
@@ -12,4 +12,13 @@ export class NavbarService {
1212
NavbarService.ref.value?.blur();
1313
NavbarService.ref.value?.dispatchEvent(new Event('mouseleave'));
1414
}
15+
16+
static destroy() {
17+
this.ref.value = undefined;
18+
this.open.value = false;
19+
this.drawer.value = false;
20+
this.dropdown.value = false;
21+
this.isHover.value = false;
22+
this.isFocus.value = false;
23+
}
1524
}

src/services/notification.service.ts

+27-4
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,31 @@ type MessageApi = ReturnType<typeof useMessage>;
1818
const renderButton = (label: string, props: ButtonProps) => () => h(NButton, { tertiary: true, type: 'info', ...props }, { default: () => label });
1919

2020
export class NotificationService {
21-
static notification: NotificationApi;
22-
static message: MessageApi;
21+
static _notification?: NotificationApi;
22+
static _message?: MessageApi;
23+
24+
static get notification(): NotificationApi {
25+
if (!this._notification) throw new Error('NotificationService not initialized');
26+
return this._notification;
27+
}
28+
29+
static set notification(value: NotificationApi) {
30+
this._notification = value;
31+
}
32+
33+
static get message(): MessageApi {
34+
if (!this._message) throw new Error('NotificationService not initialized');
35+
return this._message;
36+
}
37+
38+
static set message(value: MessageApi) {
39+
this._message = value;
40+
}
41+
42+
static destroy() {
43+
this._notification = undefined;
44+
this._message = undefined;
45+
}
2346

2447
static error(title: string, error: Error | Response | unknown, duration = 5000) {
2548
const option: Mutable<NotificationOptions> = {
@@ -40,7 +63,7 @@ export class NotificationService {
4063

4164
static release(payload: MessagePayload<typeof MessageType.VersionUpdate>) {
4265
const i18n = useI18n('notification');
43-
const notification = NotificationService.notification.info({
66+
const notification = this.notification.info({
4467
title: i18n('release_title'),
4568
description: `From ${payload.previousVersion} to ${payload.nextVersion}`,
4669
content: i18n('release_content'),
@@ -58,7 +81,7 @@ export class NotificationService {
5881

5982
static userMismatch({ user, session }: { user: string; session: string }) {
6083
const i18n = useI18n('notification');
61-
const notification = NotificationService.notification.warning({
84+
const notification = this.notification.warning({
6285
title: 'Warning: user mismatch',
6386
description: `Displaying ${session} instead of ${user}`,
6487
content: 'Current user does not match the session. \nPlease log out and log in from trakt.tv.',

src/services/router.service.ts

+7-3
Original file line numberDiff line numberDiff line change
@@ -4,16 +4,20 @@ import type { RouterOptions } from '~/router';
44
import { createRouter } from '~/router';
55

66
export class RouterService {
7-
private static instance: Router;
7+
private static instance?: Router;
88

99
static get router() {
1010
if (!RouterService.instance) throw new Error('Router not initialized');
1111
return RouterService.instance;
1212
}
1313

14-
static init(options: RouterOptions) {
15-
if (RouterService.instance) return this.instance;
14+
static init(options: RouterOptions): Router {
15+
if (this.instance) return this.instance;
1616
RouterService.instance = createRouter(options);
1717
return RouterService.instance;
1818
}
19+
20+
static destroy() {
21+
RouterService.instance = undefined;
22+
}
1923
}

src/services/trakt.service.ts

+29-31
Original file line numberDiff line numberDiff line change
@@ -223,37 +223,35 @@ export class TraktService {
223223
}
224224
}
225225

226-
static listen() {
227-
this.traktClient.onAuthChange(async _auth => {
228-
Logger.debug('TraktClient.onAuthChange', { ..._auth });
229-
});
230-
231-
this.traktClient.onCall(async call => {
232-
Logger.debug('TraktClient.onCall', call);
233-
await this.loadingBar(call.query);
234-
});
235-
236-
this.simklClient.onAuthChange(async _auth => {
237-
Logger.debug('SimklClient.onAuthChange', { ..._auth });
238-
});
239-
240-
this.simklClient.onCall(async call => {
241-
Logger.debug('SimklClient.onCall', call);
242-
await this.loadingBar(call.query);
243-
});
244-
245-
this.tmdbClient.onAuthChange(async _auth => {
246-
Logger.debug('TmdbClient.onAuthChange', { ..._auth });
247-
});
248-
249-
this.tmdbClient.onCall(async call => {
250-
Logger.debug('TmdbClient.onCall', call);
251-
try {
252-
await call.query;
253-
} catch (error) {
254-
ErrorService.registerError(error);
255-
}
256-
});
226+
static listen(subs: (() => void)[] = []) {
227+
subs.push(
228+
this.traktClient.onAuthChange(async _auth => {
229+
Logger.debug('TraktClient.onAuthChange', { ..._auth });
230+
}),
231+
this.traktClient.onCall(async call => {
232+
Logger.debug('TraktClient.onCall', call);
233+
await this.loadingBar(call.query);
234+
}),
235+
this.simklClient.onAuthChange(async _auth => {
236+
Logger.debug('SimklClient.onAuthChange', { ..._auth });
237+
}),
238+
this.simklClient.onCall(async call => {
239+
Logger.debug('SimklClient.onCall', call);
240+
await this.loadingBar(call.query);
241+
}),
242+
this.tmdbClient.onAuthChange(async _auth => {
243+
Logger.debug('TmdbClient.onAuthChange', { ..._auth });
244+
}),
245+
this.tmdbClient.onCall(async call => {
246+
Logger.debug('TmdbClient.onCall', call);
247+
try {
248+
await call.query;
249+
} catch (error) {
250+
ErrorService.registerError(error);
251+
}
252+
}),
253+
);
254+
return () => subs.forEach(sub => sub());
257255
}
258256

259257
static async tmdbConfiguration() {

src/stores/app-state.store.ts

+7-2
Original file line numberDiff line numberDiff line change
@@ -23,11 +23,16 @@ export const useAppStateStore = defineStore('app.state', () => {
2323
const isWeb = ref(false);
2424
const root = ref<HTMLElement>();
2525

26-
const { waitReady, setReady } = useWaitReady();
26+
const { waitReady, setReady, resetReady } = useWaitReady();
2727

28-
const setAppReady = async (ready: boolean, { option, popup, web = !chromeRuntimeId }: { option?: boolean; popup?: boolean; web?: boolean }) => {
28+
const setAppReady = async (
29+
ready: boolean,
30+
{ option, popup, web = !chromeRuntimeId }: { option?: boolean; popup?: boolean; web?: boolean } = {},
31+
) => {
2932
isAppReady.value = ready;
3033

34+
if (!ready) return resetReady();
35+
3136
isOption.value = option ?? false;
3237
isPopup.value = popup ?? false;
3338
isWeb.value = web ?? false;

src/stores/data/activity.store.ts

+8-1
Original file line numberDiff line numberDiff line change
@@ -176,6 +176,7 @@ export const useActivityStore = defineStore(ActivityStoreConstants.Store, () =>
176176
return _evicted;
177177
};
178178

179+
let unsub: (() => void) | undefined;
179180
const initActivityStore = async () => {
180181
await restoreState();
181182

@@ -210,12 +211,17 @@ export const useActivityStore = defineStore(ActivityStoreConstants.Store, () =>
210211
await fetchActivity();
211212
});
212213

213-
useDocumentVisible({ onVisible: fetchActivity });
214+
unsub = useDocumentVisible({ onVisible: fetchActivity });
214215

215216
if (polling.value || !isAuthenticated.value) return;
216217
return fetchActivity();
217218
};
218219

220+
const destroyActivityStore = () => {
221+
if (interval.value) clearInterval(interval.value);
222+
unsub?.();
223+
};
224+
219225
return {
220226
activity,
221227
evicted,
@@ -233,6 +239,7 @@ export const useActivityStore = defineStore(ActivityStoreConstants.Store, () =>
233239
saveState,
234240
restoreState,
235241
initActivityStore,
242+
destroyActivityStore,
236243
};
237244
});
238245

src/stores/data/watching.store.ts

+8-1
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,7 @@ export const useWatchingStore = defineStore(WatchingStoreConstants.Store, () =>
146146
}
147147
};
148148

149+
let unsub: () => void | undefined;
149150
const interval = ref<ReturnType<typeof setInterval>>();
150151
const initWatchingStore = async () => {
151152
await restoreState();
@@ -172,7 +173,12 @@ export const useWatchingStore = defineStore(WatchingStoreConstants.Store, () =>
172173
await fetchWatching();
173174
});
174175

175-
useDocumentVisible({ onVisible: fetchWatching });
176+
unsub = useDocumentVisible({ onVisible: fetchWatching });
177+
};
178+
179+
const destroyWatchingStore = () => {
180+
if (interval.value) clearInterval(interval.value);
181+
if (unsub) unsub();
176182
};
177183

178184
return {
@@ -196,6 +202,7 @@ export const useWatchingStore = defineStore(WatchingStoreConstants.Store, () =>
196202
checkingIn: computed(() => loading.checkin),
197203
loading: computed(() => loading.cancel || loading.checkin),
198204
initWatchingStore,
205+
destroyWatchingStore,
199206
checkin,
200207
cancel,
201208
};

src/stores/settings/auth.store.ts

+9-2
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,7 @@ export const useAuthSettingsStore = defineStore(AuthStoreConstants.Store, () =>
131131
return syncSetAuth(auths[account], account);
132132
};
133133

134-
const { waitReady, setReady } = useWaitReady();
134+
const { waitReady, setReady, resetReady } = useWaitReady();
135135

136136
const { setRouteParam } = useRouterStore();
137137
const { routeParam } = useRouterStoreRefs();
@@ -175,6 +175,7 @@ export const useAuthSettingsStore = defineStore(AuthStoreConstants.Store, () =>
175175
}
176176
};
177177

178+
let unsub: (() => void) | undefined;
178179
const initAuthStore = async () => {
179180
await syncRestoreAuths();
180181

@@ -188,11 +189,16 @@ export const useAuthSettingsStore = defineStore(AuthStoreConstants.Store, () =>
188189
await syncRestoreUser();
189190
}
190191

191-
TraktService.listen();
192+
unsub = TraktService.listen();
192193

193194
setReady();
194195
};
195196

197+
const destroyAuthStore = () => {
198+
resetReady();
199+
unsub?.();
200+
};
201+
196202
return {
197203
user,
198204
auth,
@@ -202,6 +208,7 @@ export const useAuthSettingsStore = defineStore(AuthStoreConstants.Store, () =>
202208
isAuthenticated,
203209
isSimklAuthenticated,
204210
initAuthStore,
211+
destroyAuthStore,
205212
waitAuthReady: waitReady,
206213
loading,
207214
importAuth,

0 commit comments

Comments
 (0)