Skip to content

Commit 54890fc

Browse files
authored
fix(agora): migrate quasar and router (#917)
Upgrade the Agora frontend to the current Quasar app-vite toolchain and complete the Vue Router 5 migration in the same pass. Toolchain changes: - update @quasar/app-vite to 2.6.0 - update quasar to 2.19.3 and @quasar/extras to 1.18.0 - align the direct vite dependency with the new Quasar line on vite 8.0.5 - update @vitejs/plugin-basic-ssl to the Vite 8-compatible release - remove the direct vite Plugin type coupling from quasar.config.ts and dedupe the browser target list for the new rolldown-based build path Router changes: - remove unplugin-vue-router and migrate to vue-router 5 with the built-in vue-router/vite plugin - move generated route typing to src/route-map.d.ts and remove the old typed-router.d.ts wiring - add the recommended tsconfig settings for router file-based routing and Volar typed-route support - fix the app code that relied on the older route-name and route-param typing by normalizing single-value params and widening the route guard destination shape Install/build warnings: - remove the unplugin-vue-router deprecation by completing the router v5 migration - add core-js to Agora's ignoredBuiltDependencies list so the clean pnpm install path stays quiet without enabling extra scripts - leave the Sentry source-map upload report warnings unchanged Verified with: - cd services/agora && pnpm install --frozen-lockfile - cd services/agora && pnpm lint - cd services/agora && pnpm test - cd services/agora && pnpm build:production - cd services/agora && pnpm image:build:production Deploy: agora
1 parent d06abd2 commit 54890fc

23 files changed

Lines changed: 2626 additions & 1238 deletions

File tree

services/agora/package.json

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@
3737
"@parcnet-js/ticket-spec": "^1.1.9",
3838
"@pcd/gpc": "^0.4.0",
3939
"@primeuix/themes": "^2.0.3",
40-
"@quasar/extras": "^1.17.0",
40+
"@quasar/extras": "^1.18.0",
4141
"@sentry/vue": "^10.40.0",
4242
"@tanstack/vue-query": "^5.92.9",
4343
"@tiptap/core": "3.20.0",
@@ -69,25 +69,25 @@
6969
"primeicons": "^7.0.0",
7070
"primevue": "^4.5.3",
7171
"qrcode": "^1",
72-
"quasar": "^2.18.6",
72+
"quasar": "^2.19.3",
7373
"sanitize-html": "^2.17.1",
7474
"tweetnacl": "^1.0.3",
7575
"uint8arrays": "^5.1.0",
76-
"vue": "^3.5.29",
76+
"vue": "^3.5.32",
7777
"vue-i18n": "^11.1.12",
78-
"vue-router": "^4.6.4",
78+
"vue-router": "^5.0.4",
7979
"zod": "^4.3.6"
8080
},
8181
"devDependencies": {
8282
"@eslint/js": "^9.39.4",
8383
"@eslint/json": "^1.0.1",
8484
"@iconify/vue": "^5.0.0",
85-
"@quasar/app-vite": "2.4.1",
85+
"@quasar/app-vite": "2.6.0",
8686
"@sentry/vite-plugin": "^5.1.1",
8787
"@types/node": "^25.3.3",
8888
"@types/qrcode": "^1.5.6",
8989
"@types/sanitize-html": "^2.13.0",
90-
"@vitejs/plugin-basic-ssl": "^2.1.4",
90+
"@vitejs/plugin-basic-ssl": "^2.3.0",
9191
"@vue/eslint-config-prettier": "^10.2.0",
9292
"@vue/eslint-config-typescript": "^14.7.0",
9393
"autoprefixer": "^10.4.27",
@@ -103,8 +103,7 @@
103103
"serve": "^14.2.5",
104104
"terser": "^5.46.0",
105105
"typescript": "5.9.3",
106-
"unplugin-vue-router": "^0.19.2",
107-
"vite": "^7.3.1",
106+
"vite": "^8.0.5",
108107
"vite-plugin-checker": "^0.12.0",
109108
"vite-plugin-compression": "^0.5.1",
110109
"vitest": "^4.1.0",

services/agora/pnpm-lock.yaml

Lines changed: 1651 additions & 1139 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

services/agora/pnpm-workspace-docker.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,5 +4,6 @@ packages:
44
ignoredBuiltDependencies:
55
- '@parcel/watcher'
66
- '@sentry/cli'
7+
- core-js
78
- esbuild
89
- vue-demi

services/agora/pnpm-workspace.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
ignoredBuiltDependencies:
22
- '@parcel/watcher'
33
- '@sentry/cli'
4+
- core-js
45
- esbuild
56
- vue-demi

services/agora/quasar.config.ts

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ import { fileURLToPath } from "node:url";
77

88
import { sentryVitePlugin } from "@sentry/vite-plugin";
99
import { visualizer } from "rollup-plugin-visualizer";
10-
import type { Plugin } from "vite";
1110
import viteCompression from "vite-plugin-compression";
1211

1312
import { defineConfig } from "#q-app/wrappers";
@@ -73,7 +72,7 @@ export default defineConfig((ctx) => {
7372
sourcemap: "hidden", // generates .map files for Sentry but strips sourceMappingURL from bundles so browsers don't download them
7473
minify: "terser",
7574
target: {
76-
browser: ["es2020", "firefox115", "chrome115", "safari14", "chrome86"],
75+
browser: ["es2020", "firefox115", "chrome86", "safari14"],
7776
node: "node20",
7877
},
7978

@@ -171,7 +170,7 @@ export default defineConfig((ctx) => {
171170
// Note: config.env only contains VITE_* vars, so we use process.env
172171
validateEnv(process.env);
173172
},
174-
} satisfies Plugin,
173+
},
175174
viteCompression({
176175
algorithm: "gzip",
177176
ext: ".gz",
@@ -191,10 +190,10 @@ export default defineConfig((ctx) => {
191190
// TODO: add env variable to add TLS/SSL
192191
// basicSsl(),
193192
[
194-
"unplugin-vue-router/vite",
193+
"vue-router/vite",
195194
{
196195
// routesFolder: 'src/pages',
197-
dts: "./typed-router.d.ts",
196+
dts: "./src/route-map.d.ts",
198197
},
199198
],
200199
],
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
import type { RouteRecordRaw, Router } from "vue-router";
2+
3+
declare module "vue-router/auto-routes" {
4+
export const routes: RouteRecordRaw[];
5+
6+
export function handleHotUpdate(
7+
router: Router,
8+
hotUpdateCallback?: (newRoutes: RouteRecordRaw[]) => void,
9+
): void;
10+
}

services/agora/src/components/navigation/SideDrawer.vue

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -30,14 +30,14 @@
3030
<ZKHoverEffect enable-hover border-radius="15px">
3131
<div
3232
class="settingItemStyle"
33-
:class="{
34-
activeRoute: menuItem.matchRouteList.includes(route.name),
35-
}"
33+
:class="{
34+
activeRoute: matchesCurrentRoute(menuItem.matchRouteList),
35+
}"
3636
>
3737
<div class="iconItem">
3838
<ZKStyledIcon
3939
:svg-string="
40-
menuItem.matchRouteList.includes(route.name)
40+
matchesCurrentRoute(menuItem.matchRouteList)
4141
? menuItem.svgStringFilled
4242
: menuItem.svgStringStandard
4343
"
@@ -115,6 +115,13 @@ interface NavigationMenuItem {
115115
const navigationMenuItems = ref<NavigationMenuItem[]>([]);
116116
initializeMenu();
117117
118+
function matchesCurrentRoute(routeList: readonly (keyof RouteNamedMap)[]): boolean {
119+
return (
120+
typeof route.name === "string" &&
121+
routeList.some((routeName) => routeName === route.name)
122+
);
123+
}
124+
118125
watch(drawerBehavior, () => {
119126
initializeMenu();
120127
});

services/agora/src/components/newConversation/NewConversationRouteGuard.vue

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,11 @@
1111
<script setup lang="ts">
1212
import ExitRoutePrompt from "src/components/routeGuard/ExitRoutePrompt.vue";
1313
import { useComponentI18n } from "src/composables/ui/useComponentI18n";
14-
import { useRouteGuard } from "src/utils/component/routing/routeGuard";
14+
import {
15+
type RouteGuardDestination,
16+
useRouteGuard,
17+
} from "src/utils/component/routing/routeGuard";
1518
import { onMounted } from "vue";
16-
import { type RouteLocationNormalized } from "vue-router";
1719
1820
import {
1921
type NewConversationRouteGuardTranslations,
@@ -50,7 +52,7 @@ onMounted(() => {
5052
lockRoute();
5153
});
5254
53-
function onBeforeRouteLeaveCallback(to: RouteLocationNormalized): boolean {
55+
function onBeforeRouteLeaveCallback(to: RouteGuardDestination): boolean {
5456
if (props.allowedRoutes.some((route) => to.name === route)) {
5557
return true;
5658
}

services/agora/src/components/post/comments/CommentComposer.vue

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,10 @@ import { useNewOpinionDraftsStore } from "src/stores/newOpinionDrafts";
9797
import { useUserStore } from "src/stores/user";
9898
import { useBackendCommentApi } from "src/utils/api/comment/comment";
9999
import { useInvalidateConversationQuery } from "src/utils/api/post/useConversationQuery";
100-
import { useRouteGuard } from "src/utils/component/routing/routeGuard";
100+
import {
101+
type RouteGuardDestination,
102+
useRouteGuard,
103+
} from "src/utils/component/routing/routeGuard";
101104
import { useNotify } from "src/utils/ui/notify";
102105
import {
103106
computed,
@@ -108,7 +111,6 @@ import {
108111
useTemplateRef,
109112
watch,
110113
} from "vue";
111-
import type { RouteLocationNormalized } from "vue-router";
112114
113115
import {
114116
type CommentComposerTranslations,
@@ -348,7 +350,7 @@ async function onLoginCallback() {
348350
}
349351
}
350352
351-
function onBeforeRouteLeaveCallback(to: RouteLocationNormalized): boolean {
353+
function onBeforeRouteLeaveCallback(to: RouteGuardDestination): boolean {
352354
if (characterCount.value > 0 && isRouteLockedCheck()) {
353355
// Auto-save draft when navigating to login/verify pages
354356
// (triggered by voting on gated conversations via PollWrapper/CommentActionBar)

services/agora/src/composables/auth/useConversationLoginIntentions.ts

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import type { EventSlug } from "src/shared/types/zod";
22
import { useLoginIntentionStore } from "src/stores/loginIntention";
3+
import { getSingleRouteParam } from "src/utils/router/params";
34
import { useEmbedMode } from "src/utils/ui/embedMode";
45
import { useRoute } from "vue-router";
56

@@ -23,7 +24,10 @@ export function useConversationLoginIntentions() {
2324
route.name === "/conversation/[postSlugId].embed/analysis"
2425
) {
2526
const isEmbedView = isEmbeddedMode();
26-
const postSlugId = route.params.postSlugId;
27+
const postSlugId = getSingleRouteParam(route.params.postSlugId);
28+
if (!postSlugId) {
29+
return;
30+
}
2731
createVotingIntention(postSlugId, isEmbedView, eventSlug);
2832
setActiveUserIntention("voting");
2933
}
@@ -41,7 +45,10 @@ export function useConversationLoginIntentions() {
4145
route.name === "/conversation/[postSlugId].embed/analysis"
4246
) {
4347
const isEmbedView = isEmbeddedMode();
44-
const postSlugId = route.params.postSlugId;
48+
const postSlugId = getSingleRouteParam(route.params.postSlugId);
49+
if (!postSlugId) {
50+
return;
51+
}
4552
createOpinionAgreementIntention(
4653
postSlugId,
4754
opinionSlugId,
@@ -61,7 +68,10 @@ export function useConversationLoginIntentions() {
6168
route.name === "/conversation/[postSlugId].embed/analysis"
6269
) {
6370
const isEmbedView = isEmbeddedMode();
64-
const postSlugId = route.params.postSlugId;
71+
const postSlugId = getSingleRouteParam(route.params.postSlugId);
72+
if (!postSlugId) {
73+
return;
74+
}
6575
createReportUserContentIntention(
6676
postSlugId,
6777
opinionSlugId,

0 commit comments

Comments
 (0)