From 9cdca77aa608502d92075723b37403834b6412d0 Mon Sep 17 00:00:00 2001 From: meteorlxy Date: Sat, 3 Feb 2024 03:16:47 +0800 Subject: [PATCH] feat: rename pagesMap to routes, revert page meta back to route meta --- e2e/docs/.vuepress/config.ts | 6 +- e2e/docs/404.md | 2 +- e2e/docs/page-data/{meta.md => route-meta.md} | 2 +- e2e/docs/router/resolve-page.md | 43 -------------- e2e/docs/router/resolve-route.md | 43 ++++++++++++++ e2e/tests/router/resolve-page.cy.ts | 59 ------------------- e2e/tests/router/resolve-route.cy.ts | 59 +++++++++++++++++++ .../cli/src/commands/dev/handlePageAdd.ts | 6 +- .../cli/src/commands/dev/handlePageChange.ts | 12 ++-- .../cli/src/commands/dev/handlePageUnlink.ts | 6 +- packages/client/package.json | 2 +- packages/client/src/components/Content.ts | 6 +- packages/client/src/components/VPLink.ts | 4 +- packages/client/src/composables/index.ts | 2 +- packages/client/src/composables/pagesMap.ts | 11 ---- packages/client/src/composables/routes.ts | 11 ++++ packages/client/src/createVueRouter.ts | 14 ++--- packages/client/src/router/index.ts | 6 +- packages/client/src/router/pagesMap.ts | 35 ----------- packages/client/src/router/resolvePage.ts | 24 -------- packages/client/src/router/resolvePagePath.ts | 18 ------ packages/client/src/router/resolveRoute.ts | 25 ++++++++ .../client/src/router/resolveRoutePath.ts | 18 ++++++ packages/client/src/router/routes.ts | 35 +++++++++++ packages/client/src/setupGlobalComputed.ts | 6 +- .../client/src/types/internal/pagesMap.d.ts | 24 -------- .../client/src/types/internal/routes.d.ts | 22 +++++++ packages/core/src/app/appPrepare.ts | 6 +- packages/core/src/app/prepare/index.ts | 2 +- .../{preparePagesMap.ts => prepareRoutes.ts} | 34 +++++------ packages/core/src/page/createPage.ts | 17 +----- packages/core/src/page/index.ts | 2 +- packages/core/src/page/resolvePageMeta.ts | 18 ------ .../core/src/page/resolvePageRouteMeta.ts | 10 ++++ packages/core/src/types/page.ts | 6 +- .../core/tests/page/resolvePageMeta.spec.ts | 26 -------- .../tests/page/resolvePageRouteMeta.spec.ts | 26 ++++++++ packages/shared/src/types/page.ts | 2 +- packages/shared/src/utils/index.ts | 2 +- ...normalizePath.ts => normalizeRoutePath.ts} | 5 +- ...ath.spec.ts => normalizeRoutePath.spec.ts} | 4 +- 41 files changed, 321 insertions(+), 340 deletions(-) rename e2e/docs/page-data/{meta.md => route-meta.md} (66%) delete mode 100644 e2e/docs/router/resolve-page.md create mode 100644 e2e/docs/router/resolve-route.md delete mode 100644 e2e/tests/router/resolve-page.cy.ts create mode 100644 e2e/tests/router/resolve-route.cy.ts delete mode 100644 packages/client/src/composables/pagesMap.ts create mode 100644 packages/client/src/composables/routes.ts delete mode 100644 packages/client/src/router/pagesMap.ts delete mode 100644 packages/client/src/router/resolvePage.ts delete mode 100644 packages/client/src/router/resolvePagePath.ts create mode 100644 packages/client/src/router/resolveRoute.ts create mode 100644 packages/client/src/router/resolveRoutePath.ts create mode 100644 packages/client/src/router/routes.ts delete mode 100644 packages/client/src/types/internal/pagesMap.d.ts create mode 100644 packages/client/src/types/internal/routes.d.ts rename packages/core/src/app/prepare/{preparePagesMap.ts => prepareRoutes.ts} (62%) delete mode 100644 packages/core/src/page/resolvePageMeta.ts create mode 100644 packages/core/src/page/resolvePageRouteMeta.ts delete mode 100644 packages/core/tests/page/resolvePageMeta.spec.ts create mode 100644 packages/core/tests/page/resolvePageRouteMeta.spec.ts rename packages/shared/src/utils/{normalizePath.ts => normalizeRoutePath.ts} (78%) rename packages/shared/tests/{normalizePath.spec.ts => normalizeRoutePath.spec.ts} (86%) diff --git a/e2e/docs/.vuepress/config.ts b/e2e/docs/.vuepress/config.ts index abb0237258..8419bae8f2 100644 --- a/e2e/docs/.vuepress/config.ts +++ b/e2e/docs/.vuepress/config.ts @@ -54,11 +54,11 @@ export default defineUserConfig({ theme: e2eTheme(), extendsPage: (page) => { - if (page.path === '/page-data/meta.html') { - page.meta = { + if (page.path === '/page-data/route-meta.html') { + page.routeMeta = { a: 1, b: 2, - ...page.meta, + ...page.routeMeta, } } }, diff --git a/e2e/docs/404.md b/e2e/docs/404.md index cf0aab5676..951515198d 100644 --- a/e2e/docs/404.md +++ b/e2e/docs/404.md @@ -1,4 +1,4 @@ --- -meta: +routeMeta: notFound: true --- diff --git a/e2e/docs/page-data/meta.md b/e2e/docs/page-data/route-meta.md similarity index 66% rename from e2e/docs/page-data/meta.md rename to e2e/docs/page-data/route-meta.md index 3e822a6928..b319753d1c 100644 --- a/e2e/docs/page-data/meta.md +++ b/e2e/docs/page-data/route-meta.md @@ -1,5 +1,5 @@ --- -meta: +routeMeta: a: 0 c: 3 --- diff --git a/e2e/docs/router/resolve-page.md b/e2e/docs/router/resolve-page.md deleted file mode 100644 index c5095c88cc..0000000000 --- a/e2e/docs/router/resolve-page.md +++ /dev/null @@ -1,43 +0,0 @@ -## resolve - -### Path - -#### Index - -- Clean URL: {{ JSON.stringify(resolvePage('/')) }} -- HTML: {{ JSON.stringify(resolvePage('/index.html')) }} -- Markdown: {{ JSON.stringify(resolvePage('/README.md')) }} - -#### Non-Index - -- Clean URL: {{ JSON.stringify(resolvePage('/router/resolve-page')) }} -- HTML: {{ JSON.stringify(resolvePage('/router/resolve-page.html')) }} -- Markdown: {{ JSON.stringify(resolvePage('/router/resolve-page.md')) }} - -#### Non-ASCII - -- Clean URL: {{ JSON.stringify(resolvePage('/routes/non-ascii-paths/中文目录名/中文文件名')) }} -- HTML: {{ JSON.stringify(resolvePage('/routes/non-ascii-paths/中文目录名/中文文件名.html')) }} -- Markdown: {{ JSON.stringify(resolvePage('/routes/non-ascii-paths/中文目录名/中文文件名.md')) }} - -#### Non-ASCII Encoded - -- Clean URL: {{ JSON.stringify(resolvePage(encodeURI('/routes/non-ascii-paths/中文目录名/中文文件名'))) }} -- HTML: {{ JSON.stringify(resolvePage(encodeURI('/routes/non-ascii-paths/中文目录名/中文文件名.html'))) }} -- Markdown: {{ JSON.stringify(resolvePage(encodeURI('/routes/non-ascii-paths/中文目录名/中文文件名.md'))) }} - -#### Non-Existent - -- Clean URL: {{ JSON.stringify(resolvePage('/non-existent')) }} -- HTML: {{ JSON.stringify(resolvePage('/non-existent.html')) }} -- Markdown: {{ JSON.stringify(resolvePage('/non-existent.md')) }} - -#### Meta - -- Clean URL: {{ JSON.stringify(resolvePage('/page-data/meta')) }} -- HTML: {{ JSON.stringify(resolvePage('/page-data/meta.html')) }} -- Markdown: {{ JSON.stringify(resolvePage('/page-data/meta.md')) }} - - diff --git a/e2e/docs/router/resolve-route.md b/e2e/docs/router/resolve-route.md new file mode 100644 index 0000000000..c556b6c66b --- /dev/null +++ b/e2e/docs/router/resolve-route.md @@ -0,0 +1,43 @@ +## resolve + +### Path + +#### Index + +- Clean URL: {{ JSON.stringify(resolveRoute('/')) }} +- HTML: {{ JSON.stringify(resolveRoute('/index.html')) }} +- Markdown: {{ JSON.stringify(resolveRoute('/README.md')) }} + +#### Non-Index + +- Clean URL: {{ JSON.stringify(resolveRoute('/router/resolve-route')) }} +- HTML: {{ JSON.stringify(resolveRoute('/router/resolve-route.html')) }} +- Markdown: {{ JSON.stringify(resolveRoute('/router/resolve-route.md')) }} + +#### Non-ASCII + +- Clean URL: {{ JSON.stringify(resolveRoute('/routes/non-ascii-paths/中文目录名/中文文件名')) }} +- HTML: {{ JSON.stringify(resolveRoute('/routes/non-ascii-paths/中文目录名/中文文件名.html')) }} +- Markdown: {{ JSON.stringify(resolveRoute('/routes/non-ascii-paths/中文目录名/中文文件名.md')) }} + +#### Non-ASCII Encoded + +- Clean URL: {{ JSON.stringify(resolveRoute(encodeURI('/routes/non-ascii-paths/中文目录名/中文文件名'))) }} +- HTML: {{ JSON.stringify(resolveRoute(encodeURI('/routes/non-ascii-paths/中文目录名/中文文件名.html'))) }} +- Markdown: {{ JSON.stringify(resolveRoute(encodeURI('/routes/non-ascii-paths/中文目录名/中文文件名.md'))) }} + +#### Non-Existent + +- Clean URL: {{ JSON.stringify(resolveRoute('/non-existent')) }} +- HTML: {{ JSON.stringify(resolveRoute('/non-existent.html')) }} +- Markdown: {{ JSON.stringify(resolveRoute('/non-existent.md')) }} + +#### Route Meta + +- Clean URL: {{ JSON.stringify(resolveRoute('/page-data/route-meta')) }} +- HTML: {{ JSON.stringify(resolveRoute('/page-data/route-meta.html')) }} +- Markdown: {{ JSON.stringify(resolveRoute('/page-data/route-meta.md')) }} + + diff --git a/e2e/tests/router/resolve-page.cy.ts b/e2e/tests/router/resolve-page.cy.ts deleted file mode 100644 index facda51bdc..0000000000 --- a/e2e/tests/router/resolve-page.cy.ts +++ /dev/null @@ -1,59 +0,0 @@ -const parseResolvedPageFromElement = (el: Cypress.JQueryWithSelector) => - JSON.parse(/: (\{.*\})\s*$/.exec(el.text())![1]) - -it('should resolve paths correctly', () => { - cy.visit('/router/resolve-page.html') - - const testCases = [ - { - selector: '#index', - expected: { - path: '/', - meta: {}, - }, - }, - { - selector: '#non-index', - expected: { - path: '/router/resolve-page.html', - meta: {}, - }, - }, - { - selector: '#non-ascii', - expected: { - path: encodeURI('/routes/non-ascii-paths/中文目录名/中文文件名.html'), - meta: {}, - }, - }, - { - selector: '#non-ascii-encoded', - expected: { - path: encodeURI('/routes/non-ascii-paths/中文目录名/中文文件名.html'), - meta: {}, - }, - }, - { - selector: '#non-existent', - expected: { - path: '/non-existent.html', - meta: { notFound: true }, - }, - }, - { - selector: '#meta', - expected: { - path: '/page-data/meta.html', - meta: { a: 0, b: 2, c: 3 }, - }, - }, - ] - - testCases.forEach(({ selector, expected }) => { - cy.get(`.e2e-theme-content ${selector} + ul > li`).each((el) => { - const resolvedPage = parseResolvedPageFromElement(el) - expect(resolvedPage.path).to.equal(expected.path) - expect(resolvedPage.meta).to.deep.equal(expected.meta) - }) - }) -}) diff --git a/e2e/tests/router/resolve-route.cy.ts b/e2e/tests/router/resolve-route.cy.ts new file mode 100644 index 0000000000..2f85ef0cf2 --- /dev/null +++ b/e2e/tests/router/resolve-route.cy.ts @@ -0,0 +1,59 @@ +const testCases = [ + { + selector: '#index', + expected: { + path: '/', + meta: {}, + }, + }, + { + selector: '#non-index', + expected: { + path: '/router/resolve-route.html', + meta: {}, + }, + }, + { + selector: '#non-ascii', + expected: { + path: encodeURI('/routes/non-ascii-paths/中文目录名/中文文件名.html'), + meta: {}, + }, + }, + { + selector: '#non-ascii-encoded', + expected: { + path: encodeURI('/routes/non-ascii-paths/中文目录名/中文文件名.html'), + meta: {}, + }, + }, + { + selector: '#non-existent', + expected: { + path: '/non-existent.html', + meta: { notFound: true }, + }, + }, + { + selector: '#route-meta', + expected: { + path: '/page-data/route-meta.html', + meta: { a: 0, b: 2, c: 3 }, + }, + }, +] + +const parseResolvedRouteFromElement = (el: Cypress.JQueryWithSelector) => + JSON.parse(/: (\{.*\})\s*$/.exec(el.text())![1]) + +it('should resolve routes correctly', () => { + cy.visit('/router/resolve-route.html') + + testCases.forEach(({ selector, expected }) => { + cy.get(`.e2e-theme-content ${selector} + ul > li`).each((el) => { + const resolvedRoute = parseResolvedRouteFromElement(el) + expect(resolvedRoute.path).to.equal(expected.path) + expect(resolvedRoute.meta).to.deep.equal(expected.meta) + }) + }) +}) diff --git a/packages/cli/src/commands/dev/handlePageAdd.ts b/packages/cli/src/commands/dev/handlePageAdd.ts index 7c4e730660..9390e1a96c 100644 --- a/packages/cli/src/commands/dev/handlePageAdd.ts +++ b/packages/cli/src/commands/dev/handlePageAdd.ts @@ -2,7 +2,7 @@ import { createPage, preparePage, preparePageComponent, - preparePagesMap, + prepareRoutes, } from '@vuepress/core' import type { App, Page } from '@vuepress/core' @@ -33,8 +33,8 @@ export const handlePageAdd = async ( await preparePageComponent(app, page) await preparePage(app, page) - // prepare pages entry - await preparePagesMap(app) + // prepare routes file + await prepareRoutes(app) return page } diff --git a/packages/cli/src/commands/dev/handlePageChange.ts b/packages/cli/src/commands/dev/handlePageChange.ts index 10330ed423..2a79b4f639 100644 --- a/packages/cli/src/commands/dev/handlePageChange.ts +++ b/packages/cli/src/commands/dev/handlePageChange.ts @@ -2,7 +2,7 @@ import { createPage, preparePage, preparePageComponent, - preparePagesMap, + prepareRoutes, } from '@vuepress/core' import type { App, Page } from '@vuepress/core' @@ -37,12 +37,12 @@ export const handlePageChange = async ( await preparePage(app, pageNew) const isPathChanged = pageOld.path !== pageNew.path - const isMetaChanged = - JSON.stringify(pageOld.meta) !== JSON.stringify(pageNew.meta) + const isRouteMetaChanged = + JSON.stringify(pageOld.routeMeta) !== JSON.stringify(pageNew.routeMeta) - // prepare pages map if the path or meta is changed - if (isPathChanged || isMetaChanged) { - await preparePagesMap(app) + // prepare routes file if the path or route meta is changed + if (isPathChanged || isRouteMetaChanged) { + await prepareRoutes(app) } return [pageOld, pageNew] diff --git a/packages/cli/src/commands/dev/handlePageUnlink.ts b/packages/cli/src/commands/dev/handlePageUnlink.ts index 5e56b8fb9a..1260480292 100644 --- a/packages/cli/src/commands/dev/handlePageUnlink.ts +++ b/packages/cli/src/commands/dev/handlePageUnlink.ts @@ -1,4 +1,4 @@ -import { preparePagesMap } from '@vuepress/core' +import { prepareRoutes } from '@vuepress/core' import type { App, Page } from '@vuepress/core' /** @@ -21,8 +21,8 @@ export const handlePageUnlink = async ( // remove the old page app.pages.splice(pageIndex, 1) - // re-prepare page files - await preparePagesMap(app) + // re-prepare routes file + await prepareRoutes(app) return page } diff --git a/packages/client/package.json b/packages/client/package.json index 0b5c0d94f2..9bbe205b20 100644 --- a/packages/client/package.json +++ b/packages/client/package.json @@ -59,7 +59,7 @@ "external": [ "@internal/clientConfigs", "@internal/layoutComponents", - "@internal/pagesMap", + "@internal/routes", "@internal/siteData" ], "format": [ diff --git a/packages/client/src/components/Content.ts b/packages/client/src/components/Content.ts index b1d405025e..ea35bf9793 100644 --- a/packages/client/src/components/Content.ts +++ b/packages/client/src/components/Content.ts @@ -1,6 +1,6 @@ import { computed, defineAsyncComponent, defineComponent, h } from 'vue' import { usePageData } from '../composables/index.js' -import { resolvePage } from '../router/index.js' +import { resolveRoute } from '../router/index.js' /** * Markdown rendered content @@ -20,8 +20,8 @@ export const Content = defineComponent({ setup(props) { const pageData = usePageData() const pageComponent = computed(() => { - const page = resolvePage(props.path || pageData.value.path) - return defineAsyncComponent(() => page.loader().then(({ comp }) => comp)) + const route = resolveRoute(props.path || pageData.value.path) + return defineAsyncComponent(() => route.loader().then(({ comp }) => comp)) }) return () => h(pageComponent.value) diff --git a/packages/client/src/components/VPLink.ts b/packages/client/src/components/VPLink.ts index 801e23b894..72e6677c3e 100644 --- a/packages/client/src/components/VPLink.ts +++ b/packages/client/src/components/VPLink.ts @@ -2,7 +2,7 @@ import { h } from 'vue' import type { FunctionalComponent, VNode } from 'vue' import { useRouter } from 'vue-router' import { withBase } from '../helpers/index.js' -import { resolvePagePath } from '../router/index.js' +import { resolveRoutePath } from '../router/index.js' /** * Forked from https://github.com/vuejs/router/blob/941b2131e80550009e5221d4db9f366b1fea3fd5/packages/router/src/RouterLink.ts#L293 @@ -35,7 +35,7 @@ export const VPLink: FunctionalComponent< } > = ({ to = '' }, { slots }) => { const router = useRouter() - const path = withBase(resolvePagePath(to)) + const path = withBase(resolveRoutePath(to)) return h( 'a', diff --git a/packages/client/src/composables/index.ts b/packages/client/src/composables/index.ts index 572a51bc03..f6c1751901 100644 --- a/packages/client/src/composables/index.ts +++ b/packages/client/src/composables/index.ts @@ -5,8 +5,8 @@ export * from './pageHead.js' export * from './pageHeadTitle.js' export * from './pageLang.js' export * from './pageLayout.js' -export * from './pagesMap.js' export * from './routeLocale.js' +export * from './routes.js' export * from './siteData.js' export * from './siteLocaleData.js' export * from './updateHead.js' diff --git a/packages/client/src/composables/pagesMap.ts b/packages/client/src/composables/pagesMap.ts deleted file mode 100644 index d474ab0dce..0000000000 --- a/packages/client/src/composables/pagesMap.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { pagesMap, redirectsMap } from '../router' - -/** - * Returns the ref of pages map - */ -export const usePagesMap = (): typeof pagesMap => pagesMap - -/** - * Returns the ref of pages map - */ -export const useRedirectsMap = (): typeof redirectsMap => redirectsMap diff --git a/packages/client/src/composables/routes.ts b/packages/client/src/composables/routes.ts new file mode 100644 index 0000000000..65a736eab2 --- /dev/null +++ b/packages/client/src/composables/routes.ts @@ -0,0 +1,11 @@ +import { redirects, routes } from '../router/index.js' + +/** + * Returns the ref of pages map + */ +export const useRedirects = (): typeof redirects => redirects + +/** + * Returns the ref of routes map + */ +export const useRoutes = (): typeof routes => routes diff --git a/packages/client/src/createVueRouter.ts b/packages/client/src/createVueRouter.ts index b0b95a3044..50f2078b53 100644 --- a/packages/client/src/createVueRouter.ts +++ b/packages/client/src/createVueRouter.ts @@ -8,7 +8,7 @@ import { } from 'vue-router' import { Vuepress } from './components/Vuepress.js' import type { PageData } from './composables/index.js' -import { resolvePage } from './router/index.js' +import { resolveRoute } from './router/index.js' /** * - use `createWebHistory` in dev mode and build mode client bundle @@ -41,16 +41,16 @@ export const createVueRouter = (): Router => { // and save page data to route meta router.beforeResolve(async (to, from): Promise => { if (to.path !== from.path || from === START_LOCATION) { - const page = resolvePage(to.path) + const route = resolveRoute(to.path) - if (page.path !== to.path) { - return page.path + if (route.path !== to.path) { + return route.path } - const pageChunk = await page.loader() + const pageChunk = await route.loader() to.meta = { - // attach page meta to route meta - ...page.meta, + // attach route meta + ...route.meta, // attach page data to route meta to trigger page data computed when route changes _data: pageChunk.data, } diff --git a/packages/client/src/router/index.ts b/packages/client/src/router/index.ts index 8b86265e30..84600902f1 100644 --- a/packages/client/src/router/index.ts +++ b/packages/client/src/router/index.ts @@ -1,3 +1,3 @@ -export * from './pagesMap.js' -export * from './resolvePage.js' -export * from './resolvePagePath.js' +export * from './resolveRoute.js' +export * from './resolveRoutePath.js' +export * from './routes.js' diff --git a/packages/client/src/router/pagesMap.ts b/packages/client/src/router/pagesMap.ts deleted file mode 100644 index 014d36ee1a..0000000000 --- a/packages/client/src/router/pagesMap.ts +++ /dev/null @@ -1,35 +0,0 @@ -import { - pagesMap as pagesMapRaw, - redirectsMap as redirectsMapRaw, -} from '@internal/pagesMap' -import type { - PageChunk, - PageMapItem, - PageMetaDefault, - PagesMap, - RedirectsMap, -} from '@internal/pagesMap' -import { shallowRef } from 'vue' -import type { Ref } from 'vue' - -export type { PagesMap, PageMapItem, PageMetaDefault, PageChunk, RedirectsMap } - -/** - * Global pages map ref - */ -export const pagesMap: Ref = shallowRef(pagesMapRaw) - -/** - * Global pages map ref - */ -export const redirectsMap: Ref = shallowRef(redirectsMapRaw) - -if (__VUEPRESS_DEV__ && (import.meta.webpackHot || import.meta.hot)) { - // reuse vue HMR runtime - __VUE_HMR_RUNTIME__.updatePagesMap = (data: PagesMap) => { - pagesMap.value = data - } - __VUE_HMR_RUNTIME__.updateRedirectsMap = (data: RedirectsMap) => { - redirectsMap.value = data - } -} diff --git a/packages/client/src/router/resolvePage.ts b/packages/client/src/router/resolvePage.ts deleted file mode 100644 index bdf03dca9e..0000000000 --- a/packages/client/src/router/resolvePage.ts +++ /dev/null @@ -1,24 +0,0 @@ -import type { PageMapItem, PageMetaDefault } from '@internal/pagesMap' -import { pagesMap } from './pagesMap.js' -import { resolvePagePath } from './resolvePagePath.js' - -interface ResolvedPage - extends PageMapItem { - path: string -} - -/** - * Resolve page with given raw path - */ -export const resolvePage = ( - path: string, -): ResolvedPage => { - const resolvedPath = resolvePagePath(path) - const pageMapItem = - pagesMap.value[resolvedPath] || pagesMap.value['/404.html'] - - return { - ...(pageMapItem as ResolvedPage), - path: resolvedPath, - } -} diff --git a/packages/client/src/router/resolvePagePath.ts b/packages/client/src/router/resolvePagePath.ts deleted file mode 100644 index f09087d957..0000000000 --- a/packages/client/src/router/resolvePagePath.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { normalizePath } from '@vuepress/shared' -import { pagesMap, redirectsMap } from './pagesMap.js' - -/** - * Resolve page path with given raw path - */ -export const resolvePagePath = (path: string): string => { - // normalized path - const normalizedPath = normalizePath(path) - if (pagesMap.value[normalizedPath]) return normalizedPath - - // encoded path - const encodedPath = encodeURI(normalizedPath) - if (pagesMap.value[encodedPath]) return encodedPath - - // redirected path or fallback to the normalized path - return redirectsMap.value[normalizedPath] || normalizedPath -} diff --git a/packages/client/src/router/resolveRoute.ts b/packages/client/src/router/resolveRoute.ts new file mode 100644 index 0000000000..f1891cc979 --- /dev/null +++ b/packages/client/src/router/resolveRoute.ts @@ -0,0 +1,25 @@ +import { resolveRoutePath } from './resolveRoutePath.js' +import type { PageMetaDefault, Route } from './routes.js' +import { routes } from './routes.js' + +interface ResolvedRoute + extends Route { + path: string +} + +/** + * Resolve route with given path + */ +export const resolveRoute = < + PageMeta extends PageMetaDefault = PageMetaDefault, +>( + path: string, +): ResolvedRoute => { + const routePath = resolveRoutePath(path) + const pageMapItem = routes.value[routePath] || routes.value['/404.html'] + + return { + ...(pageMapItem as ResolvedRoute), + path: routePath, + } +} diff --git a/packages/client/src/router/resolveRoutePath.ts b/packages/client/src/router/resolveRoutePath.ts new file mode 100644 index 0000000000..ca3ae57349 --- /dev/null +++ b/packages/client/src/router/resolveRoutePath.ts @@ -0,0 +1,18 @@ +import { normalizeRoutePath } from '@vuepress/shared' +import { redirects, routes } from './routes.js' + +/** + * Resolve route path with given raw path + */ +export const resolveRoutePath = (path: string): string => { + // normalized path + const normalizedPath = normalizeRoutePath(path) + if (routes.value[normalizedPath]) return normalizedPath + + // encoded path + const encodedPath = encodeURI(normalizedPath) + if (routes.value[encodedPath]) return encodedPath + + // redirected path or fallback to the normalized path + return redirects.value[normalizedPath] || normalizedPath +} diff --git a/packages/client/src/router/routes.ts b/packages/client/src/router/routes.ts new file mode 100644 index 0000000000..b523b9b5be --- /dev/null +++ b/packages/client/src/router/routes.ts @@ -0,0 +1,35 @@ +import { + redirects as redirectsRaw, + routes as routesRaw, +} from '@internal/routes' +import type { + PageChunk, + PageMetaDefault, + Redirects, + Route, + Routes, +} from '@internal/routes' +import { shallowRef } from 'vue' +import type { Ref } from 'vue' + +export type { PageMetaDefault, PageChunk, Redirects, Route, Routes } + +/** + * Global redirects ref + */ +export const redirects: Ref = shallowRef(redirectsRaw) + +/** + * Global routes ref + */ +export const routes: Ref = shallowRef(routesRaw) + +if (__VUEPRESS_DEV__ && (import.meta.webpackHot || import.meta.hot)) { + // reuse vue HMR runtime + __VUE_HMR_RUNTIME__.updateRoutes = (data: Routes) => { + routes.value = data + } + __VUE_HMR_RUNTIME__.updateRedirects = (data: Redirects) => { + redirects.value = data + } +} diff --git a/packages/client/src/setupGlobalComputed.ts b/packages/client/src/setupGlobalComputed.ts index 67b77947c1..7554a76cd9 100644 --- a/packages/client/src/setupGlobalComputed.ts +++ b/packages/client/src/setupGlobalComputed.ts @@ -36,7 +36,7 @@ import { } from './composables/index.js' import { withBase } from './helpers/index.js' import { resolvers } from './resolvers.js' -import { pagesMap } from './router/index.js' +import { routes } from './router/index.js' import type { ClientConfig } from './types/index.js' /** @@ -74,8 +74,8 @@ export const setupGlobalComputed = ( // handle page data HMR if (__VUEPRESS_DEV__ && (import.meta.webpackHot || import.meta.hot)) { __VUE_HMR_RUNTIME__.updatePageData = async (data: PageData) => { - const pageChunk = await pagesMap.value[data.path].loader() - pagesMap.value[data.path].loader = () => + const pageChunk = await routes.value[data.path].loader() + routes.value[data.path].loader = () => Promise.resolve({ comp: pageChunk.comp, data }) if (data.path === router.currentRoute.value.meta._data?.path) { router.currentRoute.value.meta._data = data diff --git a/packages/client/src/types/internal/pagesMap.d.ts b/packages/client/src/types/internal/pagesMap.d.ts deleted file mode 100644 index 79b3277f61..0000000000 --- a/packages/client/src/types/internal/pagesMap.d.ts +++ /dev/null @@ -1,24 +0,0 @@ -import type { PageData } from '@vuepress/shared' -import type { ComponentOptions } from 'vue' - -declare module '@internal/pagesMap' { - export interface PageChunk { - comp: ComponentOptions - data: PageData - } - - export type PageMetaDefault = Record - - export interface PageMapItem< - PageMeta extends PageMetaDefault = PageMetaDefault, - > { - loader: () => Promise - meta: PageMeta - } - - export type PagesMap = Record - export type RedirectsMap = Record - - export const pagesMap: PagesMap - export const redirectsMap: RedirectsMap -} diff --git a/packages/client/src/types/internal/routes.d.ts b/packages/client/src/types/internal/routes.d.ts new file mode 100644 index 0000000000..96d8109469 --- /dev/null +++ b/packages/client/src/types/internal/routes.d.ts @@ -0,0 +1,22 @@ +import type { PageData } from '@vuepress/shared' +import type { ComponentOptions } from 'vue' + +declare module '@internal/routes' { + export interface PageChunk { + comp: ComponentOptions + data: PageData + } + + export type PageMetaDefault = Record + + export interface Route { + loader: () => Promise + meta: PageMeta + } + + export type Redirects = Record + export type Routes = Record + + export const redirects: Redirects + export const routes: Routes +} diff --git a/packages/core/src/app/appPrepare.ts b/packages/core/src/app/appPrepare.ts index 0d01ca366d..13195ffed7 100644 --- a/packages/core/src/app/appPrepare.ts +++ b/packages/core/src/app/appPrepare.ts @@ -4,7 +4,7 @@ import { prepareClientConfigs, preparePage, preparePageComponent, - preparePagesMap, + prepareRoutes, prepareSiteData, } from './prepare/index.js' @@ -31,8 +31,8 @@ export const appPrepare = async (app: App): Promise => { await preparePage(app, page) } - // generate pages map - await preparePagesMap(app) + // generate routes file + await prepareRoutes(app) // generate site data file await prepareSiteData(app) diff --git a/packages/core/src/app/prepare/index.ts b/packages/core/src/app/prepare/index.ts index 22b147004f..c4e8d36228 100644 --- a/packages/core/src/app/prepare/index.ts +++ b/packages/core/src/app/prepare/index.ts @@ -1,5 +1,5 @@ export * from './prepareClientConfigs.js' export * from './preparePage.js' export * from './preparePageComponent.js' -export * from './preparePagesMap.js' +export * from './prepareRoutes.js' export * from './prepareSiteData.js' diff --git a/packages/core/src/app/prepare/preparePagesMap.ts b/packages/core/src/app/prepare/prepareRoutes.ts similarity index 62% rename from packages/core/src/app/prepare/preparePagesMap.ts rename to packages/core/src/app/prepare/prepareRoutes.ts index 9aaa6fcadf..c12f2d7dfe 100644 --- a/packages/core/src/app/prepare/preparePagesMap.ts +++ b/packages/core/src/app/prepare/prepareRoutes.ts @@ -1,27 +1,27 @@ -import { ensureLeadingSlash, normalizePath } from '@vuepress/shared' +import { ensureLeadingSlash, normalizeRoutePath } from '@vuepress/shared' import type { App, Page } from '../../types/index.js' const HMR_CODE = ` if (import.meta.webpackHot) { import.meta.webpackHot.accept() - if (__VUE_HMR_RUNTIME__.updatePagesMap) { - __VUE_HMR_RUNTIME__.updatePagesMap(pagesMap) + if (__VUE_HMR_RUNTIME__.updateRoutes) { + __VUE_HMR_RUNTIME__.updateRoutes(routes) } - if (__VUE_HMR_RUNTIME__.updateRedirectsMap) { - __VUE_HMR_RUNTIME__.updateRedirectsMap(redirectsMap) + if (__VUE_HMR_RUNTIME__.updateRedirects) { + __VUE_HMR_RUNTIME__.updateRedirects(redirects) } } if (import.meta.hot) { - import.meta.hot.accept(({ pagesMap, redirectsMap }) => { - __VUE_HMR_RUNTIME__.updatePagesMap(pagesMap) - __VUE_HMR_RUNTIME__.updateRedirectsMap(redirectsMap) + import.meta.hot.accept(({ routes, redirects }) => { + __VUE_HMR_RUNTIME__.updateRoutes(routes) + __VUE_HMR_RUNTIME__.updateRedirects(redirects) }) } ` /** - * Resolve page route item + * Resolve page redirects */ const resolvePageRedirects = ({ path, @@ -33,7 +33,7 @@ const resolvePageRedirects = ({ // add redirect to the set when the redirect could not be normalized & encoded to the page path const addRedirect = (redirect: string): void => { - const normalizedPath = normalizePath(redirect) + const normalizedPath = normalizeRoutePath(redirect) if (normalizedPath === path) return const encodedPath = encodeURI(normalizedPath) @@ -56,12 +56,12 @@ const resolvePageRedirects = ({ } /** - * Generate page map temp file + * Generate routes temp file */ -export const preparePagesMap = async (app: App): Promise => { +export const prepareRoutes = async (app: App): Promise => { // generate page component map file let content = `\ -export const redirectsMap = JSON.parse(${JSON.stringify( +export const redirects = JSON.parse(${JSON.stringify( JSON.stringify( Object.fromEntries( app.pages.flatMap((page) => @@ -71,11 +71,11 @@ export const redirectsMap = JSON.parse(${JSON.stringify( ), )}) -export const pagesMap = Object.fromEntries([ +export const routes = Object.fromEntries([ ${app.pages .map( - ({ meta, path, chunkFilePath, chunkName }) => - ` [${JSON.stringify(path)}, { loader: () => import(${chunkName ? `/* webpackChunkName: "${chunkName}" */` : ''}${JSON.stringify(chunkFilePath)}), meta: ${JSON.stringify(meta)} }],`, + ({ chunkFilePath, chunkName, path, routeMeta }) => + ` [${JSON.stringify(path)}, { loader: () => import(${chunkName ? `/* webpackChunkName: "${chunkName}" */` : ''}${JSON.stringify(chunkFilePath)}), meta: ${JSON.stringify(routeMeta)} }],`, ) .join('\n')} ]); @@ -86,5 +86,5 @@ ${app.pages content += HMR_CODE } - await app.writeTemp('internal/pagesMap.js', content) + await app.writeTemp('internal/routes.js', content) } diff --git a/packages/core/src/page/createPage.ts b/packages/core/src/page/createPage.ts index 32b6717eed..ab9b05deb6 100644 --- a/packages/core/src/page/createPage.ts +++ b/packages/core/src/page/createPage.ts @@ -8,9 +8,9 @@ import { resolvePageFileContent } from './resolvePageFileContent.js' import { resolvePageFilePath } from './resolvePageFilePath.js' import { resolvePageHtmlInfo } from './resolvePageHtmlInfo.js' import { resolvePageLang } from './resolvePageLang.js' -import { resolvePageMeta } from './resolvePageMeta.js' import { resolvePagePath } from './resolvePagePath.js' import { resolvePagePermalink } from './resolvePagePermalink.js' +import { resolvePageRouteMeta } from './resolvePageRouteMeta.js' import { resolvePageSlug } from './resolvePageSlug.js' export const createPage = async ( @@ -48,7 +48,7 @@ export const createPage = async ( }) // resolve route meta from frontmatter - const meta = resolvePageMeta({ frontmatter }) + const routeMeta = resolvePageRouteMeta({ frontmatter }) // resolve slug from file path const slug = resolvePageSlug({ filePathRelative }) @@ -118,7 +118,7 @@ export const createPage = async ( pathInferred, pathLocale, permalink, - meta, + routeMeta, sfcBlocks, slug, @@ -132,17 +132,6 @@ export const createPage = async ( chunkName, htmlFilePath, htmlFilePathRelative, - - // TODO: Added for backwards compatibility, remove in next major version - // @ts-expect-error use meta instead - routeMeta: new Proxy(meta, { - set: (obj, prop, value) => { - console.warn('routeMeta is deprecated, please use meta instead') - - obj[prop as string] = value - return true - }, - }), } // plugin hook: extendsPage diff --git a/packages/core/src/page/index.ts b/packages/core/src/page/index.ts index d7e4a9e522..179d9f4cc6 100644 --- a/packages/core/src/page/index.ts +++ b/packages/core/src/page/index.ts @@ -10,5 +10,5 @@ export * from './resolvePageHtmlInfo.js' export * from './resolvePageLang.js' export * from './resolvePagePath.js' export * from './resolvePagePermalink.js' -export * from './resolvePageMeta.js' +export * from './resolvePageRouteMeta.js' export * from './resolvePageSlug.js' diff --git a/packages/core/src/page/resolvePageMeta.ts b/packages/core/src/page/resolvePageMeta.ts deleted file mode 100644 index e532cabb09..0000000000 --- a/packages/core/src/page/resolvePageMeta.ts +++ /dev/null @@ -1,18 +0,0 @@ -import type { PageFrontmatter } from '../types/index.js' - -/** - * Resolve page route meta - */ -export const resolvePageMeta = ({ - frontmatter, -}: { - frontmatter: PageFrontmatter -}): Record => { - // TODO: Added for backwards compatibility, should be removed in stable - if (frontmatter.routeMeta) { - console.warn('routeMeta is deprecated, please use meta instead') - frontmatter.meta = { ...frontmatter.routeMeta, ...frontmatter.meta } - } - - return frontmatter.meta ?? {} -} diff --git a/packages/core/src/page/resolvePageRouteMeta.ts b/packages/core/src/page/resolvePageRouteMeta.ts new file mode 100644 index 0000000000..76e5030a91 --- /dev/null +++ b/packages/core/src/page/resolvePageRouteMeta.ts @@ -0,0 +1,10 @@ +import type { PageFrontmatter } from '../types/index.js' + +/** + * Resolve page route meta + */ +export const resolvePageRouteMeta = ({ + frontmatter, +}: { + frontmatter: PageFrontmatter +}): Record => frontmatter.routeMeta ?? {} diff --git a/packages/core/src/types/page.ts b/packages/core/src/types/page.ts index a26ef8c865..303a9d41cd 100644 --- a/packages/core/src/types/page.ts +++ b/packages/core/src/types/page.ts @@ -73,11 +73,9 @@ export type Page< permalink: string | null /** - * Custom data to be attached to page record - * - * @see https://router.vuejs.org/api/#meta + * Custom data to be attached to route record */ - meta: Record + routeMeta: Record /** * Extracted sfc blocks of the page diff --git a/packages/core/tests/page/resolvePageMeta.spec.ts b/packages/core/tests/page/resolvePageMeta.spec.ts deleted file mode 100644 index 3ee0728c0d..0000000000 --- a/packages/core/tests/page/resolvePageMeta.spec.ts +++ /dev/null @@ -1,26 +0,0 @@ -import { describe, expect, it } from 'vitest' -import { resolvePageMeta } from '../../src/index.js' - -describe('core > page > resolvePageMeta', () => { - it('should use frontmatter meta', () => { - const meta = resolvePageMeta({ - frontmatter: { - meta: { - foo: 'foo', - }, - }, - }) - - expect(meta).toEqual({ - foo: 'foo', - }) - }) - - it('should return default value', () => { - const meta = resolvePageMeta({ - frontmatter: {}, - }) - - expect(meta).toEqual({}) - }) -}) diff --git a/packages/core/tests/page/resolvePageRouteMeta.spec.ts b/packages/core/tests/page/resolvePageRouteMeta.spec.ts new file mode 100644 index 0000000000..033ebebac3 --- /dev/null +++ b/packages/core/tests/page/resolvePageRouteMeta.spec.ts @@ -0,0 +1,26 @@ +import { describe, expect, it } from 'vitest' +import { resolvePageRouteMeta } from '../../src/index.js' + +describe('core > page > resolvePageRouteMeta', () => { + it('should use frontmatter routeMeta', () => { + const routeMeta = resolvePageRouteMeta({ + frontmatter: { + routeMeta: { + foo: 'foo', + }, + }, + }) + + expect(routeMeta).toEqual({ + foo: 'foo', + }) + }) + + it('should return default value', () => { + const routeMeta = resolvePageRouteMeta({ + frontmatter: {}, + }) + + expect(routeMeta).toEqual({}) + }) +}) diff --git a/packages/shared/src/types/page.ts b/packages/shared/src/types/page.ts index 4c3d315a8f..f05a83ad2c 100644 --- a/packages/shared/src/types/page.ts +++ b/packages/shared/src/types/page.ts @@ -64,7 +64,7 @@ export type PageFrontmatter< layout?: string permalink?: string permalinkPattern?: string | null - meta?: Record + routeMeta?: Record title?: string } diff --git a/packages/shared/src/utils/index.ts b/packages/shared/src/utils/index.ts index 8427fc44c2..a14fe7c3d9 100644 --- a/packages/shared/src/utils/index.ts +++ b/packages/shared/src/utils/index.ts @@ -6,7 +6,7 @@ export * from './isLinkExternal.js' export * from './isLinkHttp.js' export * from './isLinkWithProtocol.js' export * from './isPlainObject.js' -export * from './normalizePath.js' +export * from './normalizeRoutePath.js' export * from './omit.js' export * from './removeEndingSlash.js' export * from './removeLeadingSlash.js' diff --git a/packages/shared/src/utils/normalizePath.ts b/packages/shared/src/utils/normalizeRoutePath.ts similarity index 78% rename from packages/shared/src/utils/normalizePath.ts rename to packages/shared/src/utils/normalizeRoutePath.ts index e7ec96ccbd..c3924ac90b 100644 --- a/packages/shared/src/utils/normalizePath.ts +++ b/packages/shared/src/utils/normalizeRoutePath.ts @@ -1,4 +1,7 @@ -export const normalizePath = (path: string): string => { +/** + * Normalize the given path to the final route path + */ +export const normalizeRoutePath = (path: string): string => { const convertedMdPath = path.endsWith('README.md') ? path.substring(0, path.length - 9) : path.endsWith('.md') diff --git a/packages/shared/tests/normalizePath.spec.ts b/packages/shared/tests/normalizeRoutePath.spec.ts similarity index 86% rename from packages/shared/tests/normalizePath.spec.ts rename to packages/shared/tests/normalizeRoutePath.spec.ts index 8c4c6f8f79..b448ffceeb 100644 --- a/packages/shared/tests/normalizePath.spec.ts +++ b/packages/shared/tests/normalizeRoutePath.spec.ts @@ -1,5 +1,5 @@ import { expect, it } from 'vitest' -import { normalizePath } from '../src/index.js' +import { normalizeRoutePath } from '../src/index.js' const testCases = [ ['/', '/'], @@ -23,6 +23,6 @@ const testCases = [ testCases.forEach(([path, expected]) => it(`should normalize "${path}" to "${expected}"`, () => { - expect(normalizePath(path)).toBe(expected) + expect(normalizeRoutePath(path)).toBe(expected) }), )