diff --git a/packages/frontend/src/_embed_boot_.ts b/packages/frontend/src/_embed_boot_.ts index f4fc6396e2..9011b4740d 100644 --- a/packages/frontend/src/_embed_boot_.ts +++ b/packages/frontend/src/_embed_boot_.ts @@ -15,8 +15,11 @@ import { setIframeId, postMessageToParentWindow } from '@/scripts/post-message.j import { parseEmbedParams } from '@/scripts/embed-page.js'; import { defaultStore } from '@/store.js'; import { useRouter } from '@/router/supplier.js'; +import { createEmbedRouter } from '@/router/definition.embed.js'; -const bootOptions: Partial = {}; +const bootOptions: Partial = { + routerFactory: createEmbedRouter, +}; const params = new URLSearchParams(location.search); const embedParams = parseEmbedParams(params); diff --git a/packages/frontend/src/boot/common.ts b/packages/frontend/src/boot/common.ts index 619d451192..c0db797b3f 100644 --- a/packages/frontend/src/boot/common.ts +++ b/packages/frontend/src/boot/common.ts @@ -15,6 +15,7 @@ import { updateI18n } from '@/i18n.js'; import { $i, refreshAccount, login } from '@/account.js'; import { defaultStore, ColdDeviceStorage } from '@/store.js'; import { fetchInstance, instance } from '@/instance.js'; +import type { IRouter } from '@/nirax.js'; import { deviceKind } from '@/scripts/device-kind.js'; import { reloadChannel } from '@/scripts/unison-reload.js'; import { getUrlWithoutLoginId } from '@/scripts/login-id.js'; @@ -22,14 +23,17 @@ import { getAccountFromId } from '@/scripts/get-account-from-id.js'; import { deckStore } from '@/ui/deck/deck-store.js'; import { miLocalStorage } from '@/local-storage.js'; import { fetchCustomEmojis } from '@/custom-emojis.js'; -import { setupRouter } from '@/router/definition.js'; +import { createMainRouter } from '@/router/definition.js'; +import { setupRouter } from '@/router/main.js'; export type CommonBootOptions = { forceColorMode: 'dark' | 'light' | 'auto'; + routerFactory: ((path: string) => IRouter); }; const defaultCommonBootOptions: CommonBootOptions = { forceColorMode: 'auto', + routerFactory: createMainRouter, }; export async function common(createVue: () => App, partialOptions?: Partial) { @@ -253,7 +257,7 @@ export async function common(createVue: () => App, partialOptions?: Par const app = createVue(); - setupRouter(app); + setupRouter(app, bootOptions.routerFactory); if (_DEV_) { app.config.performance = true; diff --git a/packages/frontend/src/router/definition.embed.ts b/packages/frontend/src/router/definition.embed.ts new file mode 100644 index 0000000000..bec9f776a3 --- /dev/null +++ b/packages/frontend/src/router/definition.embed.ts @@ -0,0 +1,30 @@ +/* + * SPDX-FileCopyrightText: syuilo and misskey-project + * SPDX-License-Identifier: AGPL-3.0-only + */ + +import type { IRouter, RouteDef } from '@/nirax.js'; +import { Router } from '@/nirax.js'; +import { page } from '@/router/definition.js'; +import { $i } from '@/account.js'; + +const routes: RouteDef[] = [{ + path: '/embed/notes/:noteId', + component: page(() => import('@/pages/embed/note.vue')), +}, { + path: '/embed/user-timeline/@:username', + component: page(() => import('@/pages/embed/user-timeline.vue')), +}, { + path: '/embed/clips/:clipId', + component: page(() => import('@/pages/embed/clip.vue')), +}, { + path: '/embed/tags/:tag', + component: page(() => import('@/pages/embed/tag.vue')), +}, { + path: '/:(*)', + component: page(() => import('@/pages/not-found.vue')), +}]; + +export function createEmbedRouter(path: string): IRouter { + return new Router(routes, path, !!$i, page(() => import('@/pages/not-found.vue'))); +} diff --git a/packages/frontend/src/router/definition.ts b/packages/frontend/src/router/definition.ts index cc820db867..8a29fd677e 100644 --- a/packages/frontend/src/router/definition.ts +++ b/packages/frontend/src/router/definition.ts @@ -3,15 +3,14 @@ * SPDX-License-Identifier: AGPL-3.0-only */ -import { App, AsyncComponentLoader, defineAsyncComponent, provide } from 'vue'; -import type { RouteDef } from '@/nirax.js'; -import { IRouter, Router } from '@/nirax.js'; +import { AsyncComponentLoader, defineAsyncComponent } from 'vue'; +import type { IRouter, RouteDef } from '@/nirax.js'; +import { Router } from '@/nirax.js'; import { $i, iAmModerator } from '@/account.js'; import MkLoading from '@/pages/_loading_.vue'; import MkError from '@/pages/_error_.vue'; -import { setMainRouter } from '@/router/main.js'; -const page = (loader: AsyncComponentLoader) => defineAsyncComponent({ +export const page = (loader: AsyncComponentLoader) => defineAsyncComponent({ loader: loader, loadingComponent: MkLoading, errorComponent: MkError, @@ -240,7 +239,7 @@ const routes: RouteDef[] = [{ origin: 'origin', }, }, { - // Legacy Compatibility + // Legacy Compatibility path: '/authorize-follow', redirect: '/lookup', loginRequired: true, @@ -579,18 +578,6 @@ const routes: RouteDef[] = [{ path: '/reversi/g/:gameId', component: page(() => import('@/pages/reversi/game.vue')), loginRequired: false, -}, { - path: '/embed/notes/:noteId', - component: page(() => import('@/pages/embed/note.vue')), -}, { - path: '/embed/user-timeline/@:username', - component: page(() => import('@/pages/embed/user-timeline.vue')), -}, { - path: '/embed/clips/:clipId', - component: page(() => import('@/pages/embed/clip.vue')), -}, { - path: '/embed/tags/:tag', - component: page(() => import('@/pages/embed/tag.vue')), }, { path: '/timeline', component: page(() => import('@/pages/timeline.vue')), @@ -609,32 +596,6 @@ const routes: RouteDef[] = [{ component: page(() => import('@/pages/not-found.vue')), }]; -function createRouterImpl(path: string): IRouter { +export function createMainRouter(path: string): IRouter { return new Router(routes, path, !!$i, page(() => import('@/pages/not-found.vue'))); } - -/** - * {@link Router}による画面遷移を可能とするために{@link mainRouter}をセットアップする。 - * また、{@link Router}のインスタンスを作成するためのファクトリも{@link provide}経由で公開する(`routerFactory`というキーで取得可能) - */ -export function setupRouter(app: App) { - app.provide('routerFactory', createRouterImpl); - - const mainRouter = createRouterImpl(location.pathname + location.search + location.hash); - - window.addEventListener('popstate', (event) => { - mainRouter.replace(location.pathname + location.search + location.hash, event.state?.key); - }); - - mainRouter.addListener('push', ctx => { - window.history.pushState({ key: ctx.key }, '', ctx.path); - }); - - mainRouter.addListener('replace', ctx => { - window.history.replaceState({ key: ctx.key }, '', ctx.path); - }); - - mainRouter.init(); - - setMainRouter(mainRouter); -} diff --git a/packages/frontend/src/router/main.ts b/packages/frontend/src/router/main.ts index 7a3fde131e..6ee967e6f4 100644 --- a/packages/frontend/src/router/main.ts +++ b/packages/frontend/src/router/main.ts @@ -3,10 +3,37 @@ * SPDX-License-Identifier: AGPL-3.0-only */ -import { ShallowRef } from 'vue'; import { EventEmitter } from 'eventemitter3'; import { IRouter, Resolved, RouteDef, RouterEvent } from '@/nirax.js'; +import type { App, ShallowRef } from 'vue'; + +/** + * {@link Router}による画面遷移を可能とするために{@link mainRouter}をセットアップする。 + * また、{@link Router}のインスタンスを作成するためのファクトリも{@link provide}経由で公開する(`routerFactory`というキーで取得可能) + */ +export function setupRouter(app: App, routerFactory: ((path: string) => IRouter)): void { + app.provide('routerFactory', routerFactory); + + const mainRouter = routerFactory(location.pathname + location.search + location.hash); + + window.addEventListener('popstate', (event) => { + mainRouter.replace(location.pathname + location.search + location.hash, event.state?.key); + }); + + mainRouter.addListener('push', ctx => { + window.history.pushState({ key: ctx.key }, '', ctx.path); + }); + + mainRouter.addListener('replace', ctx => { + window.history.replaceState({ key: ctx.key }, '', ctx.path); + }); + + mainRouter.init(); + + setMainRouter(mainRouter); +} + function getMainRouter(): IRouter { const router = mainRouterHolder; if (!router) {