diff --git a/e2e/fixtures/check-dead-link/doc/en/guide/basic/quick-start.mdx b/e2e/fixtures/check-dead-link/doc/en/guide/basic/quick-start.mdx index acd71afc0..7bb390448 100644 --- a/e2e/fixtures/check-dead-link/doc/en/guide/basic/quick-start.mdx +++ b/e2e/fixtures/check-dead-link/doc/en/guide/basic/quick-start.mdx @@ -25,3 +25,11 @@ [../../api/](../../api/) [../../api](../../api) + +## Corner cases + +[/en](/en) + +[/en/](/en/) + +[/](/) diff --git a/e2e/fixtures/check-dead-link/doc/zh/guide/basic/quick-start.mdx b/e2e/fixtures/check-dead-link/doc/zh/guide/basic/quick-start.mdx index 78164ba7c..b566105f7 100644 --- a/e2e/fixtures/check-dead-link/doc/zh/guide/basic/quick-start.mdx +++ b/e2e/fixtures/check-dead-link/doc/zh/guide/basic/quick-start.mdx @@ -8,7 +8,7 @@ [/guide/basic/install.mdx](/guide/basic/install.mdx) -[/en/guide/basic/install.mdx](/en/guide/basic/install.mdx) +[/zh/guide/basic/install.mdx](/zh/guide/basic/install.mdx) ## 相对路径 @@ -25,3 +25,11 @@ [../../api/](../../api/) [../../api](../../api) + +## Corner cases + +[/zh](/zh) + +[/zh/](/zh/) + +[/](/) diff --git a/e2e/fixtures/check-dead-link/index.test.ts b/e2e/fixtures/check-dead-link/index.test.ts index dad15956b..ad481b1fb 100644 --- a/e2e/fixtures/check-dead-link/index.test.ts +++ b/e2e/fixtures/check-dead-link/index.test.ts @@ -21,30 +21,64 @@ test.describe('check dead links', async () => { await runBuildCommand(appDir); app = await runPreviewCommand(appDir, appPort); - await page.goto( - `http://localhost:${appPort}/base/guide/basic/quick-start`, - { - waitUntil: 'networkidle', - }, - ); - // Get all the element - const linkDoms = await page.$$('.rspress-doc a'); + { + await page.goto( + `http://localhost:${appPort}/base/guide/basic/quick-start`, + { + waitUntil: 'networkidle', + }, + ); + // Get all the element + const linkDoms = await page.$$('.rspress-doc a'); - const links = ( - await Promise.all(linkDoms.map(linkDom => linkDom.getAttribute('href'))) - ).filter(i => !i?.startsWith('#')); - expect(links).toEqual([ - '/base/guide/basic/install.html', - '/base/guide/basic/install.html', - '/base/guide/basic/install.html', - '/base/guide/basic/install.html', - '/base/guide/basic/install.html', - '/base/guide/basic/install.html', - '/base/guide/basic/install.html', - '/base/api/index.html', - '/base/api.html', - '/base/api.html', - ]); + const links = ( + await Promise.all(linkDoms.map(linkDom => linkDom.getAttribute('href'))) + ).filter(i => !i?.startsWith('#')); + expect(links).toEqual([ + '/base/guide/basic/install.html', + '/base/guide/basic/install.html', + '/base/guide/basic/install.html', + '/base/guide/basic/install.html', + '/base/guide/basic/install.html', + '/base/guide/basic/install.html', + '/base/guide/basic/install.html', + '/base/api/index.html', + '/base/api.html', // FIXME: should be /base/api/index.html + '/base/api.html', + '/base/index.html', + '/base/index.html', + '/base/index.html', + ]); + } + { + await page.goto( + `http://localhost:${appPort}/base/en/guide/basic/quick-start`, + { + waitUntil: 'networkidle', + }, + ); + // Get all the element + const linkDoms = await page.$$('.rspress-doc a'); + + const links = ( + await Promise.all(linkDoms.map(linkDom => linkDom.getAttribute('href'))) + ).filter(i => !i?.startsWith('#')); + expect(links).toEqual([ + '/base/en/guide/basic/install.html', + '/base/en/guide/basic/install.html', + '/base/en/guide/basic/install.html', + '/base/en/guide/basic/install.html', + '/base/en/guide/basic/install.html', + '/base/en/guide/basic/install.html', + '/base/en/guide/basic/install.html', + '/base/en/api/index.html', + '/base/en/api.html', + '/base/en/api.html', + '/base/en/index.html', + '/base/en/index.html', + '/base/en/index.html', + ]); + } }); test('should link the correct page - cleanUrl', async ({ page }) => { @@ -53,29 +87,64 @@ test.describe('check dead links', async () => { await runBuildCommand(appDir, 'rspress-clean.config.ts'); app = await runPreviewCommand(appDir, appPort); - await page.goto( - `http://localhost:${appPort}/base/guide/basic/quick-start`, - { - waitUntil: 'networkidle', - }, - ); - // Get all the element - const linkDoms = await page.$$('.rspress-doc a'); + { + await page.goto( + `http://localhost:${appPort}/base/guide/basic/quick-start`, + { + waitUntil: 'networkidle', + }, + ); + // Get all the element + const linkDoms = await page.$$('.rspress-doc a'); - const links = ( - await Promise.all(linkDoms.map(linkDom => linkDom.getAttribute('href'))) - ).filter(i => !i?.startsWith('#')); - expect(links).toEqual([ - '/base/guide/basic/install', - '/base/guide/basic/install', - '/base/guide/basic/install', - '/base/guide/basic/install', - '/base/guide/basic/install', - '/base/guide/basic/install', - '/base/guide/basic/install', - '/base/api', - '/base/api', - '/base/api', - ]); + const links = ( + await Promise.all(linkDoms.map(linkDom => linkDom.getAttribute('href'))) + ).filter(i => !i?.startsWith('#')); + expect(links).toEqual([ + '/base/guide/basic/install', + '/base/guide/basic/install', + '/base/guide/basic/install', + '/base/guide/basic/install', + '/base/guide/basic/install', + '/base/guide/basic/install', + '/base/guide/basic/install', + '/base/api', + '/base/api', + '/base/api', + '/base/', + '/base/', + '/base/', + ]); + } + + { + await page.goto( + `http://localhost:${appPort}/base/en/guide/basic/quick-start`, + { + waitUntil: 'networkidle', + }, + ); + // Get all the element + const linkDoms = await page.$$('.rspress-doc a'); + + const links = ( + await Promise.all(linkDoms.map(linkDom => linkDom.getAttribute('href'))) + ).filter(i => !i?.startsWith('#')); + expect(links).toEqual([ + '/base/en/guide/basic/install', + '/base/en/guide/basic/install', + '/base/en/guide/basic/install', + '/base/en/guide/basic/install', + '/base/en/guide/basic/install', + '/base/en/guide/basic/install', + '/base/en/guide/basic/install', + '/base/en/api', + '/base/en/api', + '/base/en/api', + '/base/en', + '/base/en', + '/base/en', + ]); + } }); }); diff --git a/e2e/fixtures/markdown-link/doc/guide/index.mdx b/e2e/fixtures/markdown-link/doc/guide/index.mdx index 743539c5d..0c81a0f12 100644 --- a/e2e/fixtures/markdown-link/doc/guide/index.mdx +++ b/e2e/fixtures/markdown-link/doc/guide/index.mdx @@ -14,56 +14,56 @@ ## RelativeLinks - [./installation](./installation) -- [installation(TODO)](installation) +- [installation](installation) - [./installation.mdx](./installation.mdx) -- [installation.mdx(TODO)](installation.mdx). +- [installation.mdx](installation.mdx). - [Definition: ./installation] -- [Definition: installation(TODO)] +- [Definition: installation] - [Definition: ./installation.mdx] -- [Definition: installation.mdx(TODO)] +- [Definition: installation.mdx] [Definition: ./installation]: ./installation -[Definition: installation(TODO)]: installation +[Definition: installation]: installation [Definition: ./installation.mdx]: ./installation.mdx -[Definition: installation.mdx(TODO)]: installation.mdx +[Definition: installation.mdx]: installation.mdx ## RelativeLinks with subfolders - [./subfolder/foo](./subfolder/foo) -- [subfolder/foo(TODO)](subfolder/foo) +- [subfolder/foo](subfolder/foo) - [./subfolder/foo.mdx](./subfolder/foo.mdx) -- [subfolder/foo.mdx(TODO)](subfolder/foo.mdx). +- [subfolder/foo.mdx](subfolder/foo.mdx). - [Definition2: ./subfolder/foo] -- [Definition2: subfolder/foo(TODO)] +- [Definition2: subfolder/foo] - [Definition2: ./subfolder/foo.mdx] -- [Definition2: subfolder/foo.mdx(TODO)] +- [Definition2: subfolder/foo.mdx] [Definition2: ./subfolder/foo]: ./subfolder/foo -[Definition2: subfolder/foo(TODO)]: subfolder/foo +[Definition2: subfolder/foo]: subfolder/foo [Definition2: ./subfolder/foo.mdx]: ./subfolder/foo.mdx -[Definition2: subfolder/foo.mdx(TODO)]: subfolder/foo.mdx +[Definition2: subfolder/foo.mdx]: subfolder/foo.mdx ## RelativeLinks to subfolders index - [./subfolder](./subfolder) -- [subfolder(TODO)](subfolder) +- [subfolder](subfolder) - [./subfolder/index.mdx](./subfolder/index.mdx) -- [subfolder/index.mdx(TODO)](subfolder/index.mdx). +- [subfolder/index.mdx](subfolder/index.mdx). - [Definition3: ./subfolder] -- [Definition3: subfolder(TODO)] +- [Definition3: subfolder] - [Definition3: ./subfolder/index.mdx] -- [Definition3: subfolder/index.mdx(TODO)] +- [Definition3: subfolder/index.mdx] [Definition3: ./subfolder]: ./subfolder -[Definition3: subfolder(TODO)]: subfolder +[Definition3: subfolder]: subfolder [Definition3: ./subfolder/index.mdx]: ./subfolder/index.mdx -[Definition3: subfolder/index.mdx(TODO)]: subfolder/index.mdx +[Definition3: subfolder/index.mdx]: subfolder/index.mdx diff --git a/e2e/fixtures/markdown-link/index.test.ts b/e2e/fixtures/markdown-link/index.test.ts index 49570a935..d0d5dc8b2 100644 --- a/e2e/fixtures/markdown-link/index.test.ts +++ b/e2e/fixtures/markdown-link/index.test.ts @@ -18,7 +18,7 @@ test.describe('basic test', async () => { }); test('all links should be normalized', async ({ page }) => { - await page.goto(`http://localhost:${appPort}/guide`); + await page.goto(`http://localhost:${appPort}/base/guide`); const links = await page.$$('.rspress-doc ul li a'); const urls = await Promise.all( links.map(async link => { @@ -27,35 +27,38 @@ test.describe('basic test', async () => { }), ); - const snapshot = urls.join('\n'); - - expect(snapshot).toEqual(`/guide/installation.html -/guide/installation.html -/guide/installation.html -/guide/installation.html -/guide/installation.html -/installation.html -/guide/installation.html -/installation.html -/guide/installation.html -/installation.html -/guide/installation.html -/installation.html -/guide/subfolder/foo.html -/subfolder/foo.html -/guide/subfolder/foo.html -/subfolder/foo.html -/guide/subfolder/foo.html -/subfolder/foo.html -/guide/subfolder/foo.html -/subfolder/foo.html -/guide/subfolder.html -/subfolder.html -/guide/subfolder/index.html -/subfolder/index.html -/guide/subfolder.html -/subfolder.html -/guide/subfolder/index.html -/subfolder/index.html`); + expect(urls).toEqual([ + '/base/guide/installation.html', + '/base/guide/installation.html', + '/base/guide/installation.html', + '/base/guide/installation.html', + // + '/base/guide/installation.html', + '/base/guide/installation.html', + '/base/guide/installation.html', + '/base/guide/installation.html', + '/base/guide/installation.html', + '/base/guide/installation.html', + '/base/guide/installation.html', + '/base/guide/installation.html', + // + '/base/guide/subfolder/foo.html', + '/base/guide/subfolder/foo.html', + '/base/guide/subfolder/foo.html', + '/base/guide/subfolder/foo.html', + '/base/guide/subfolder/foo.html', + '/base/guide/subfolder/foo.html', + '/base/guide/subfolder/foo.html', + '/base/guide/subfolder/foo.html', + // + '/base/guide/subfolder.html', + '/base/guide/subfolder.html', + '/base/guide/subfolder/index.html', + '/base/guide/subfolder/index.html', + '/base/guide/subfolder.html', + '/base/guide/subfolder.html', + '/base/guide/subfolder/index.html', + '/base/guide/subfolder/index.html', + ]); }); }); diff --git a/e2e/fixtures/markdown-link/rspress.config.ts b/e2e/fixtures/markdown-link/rspress.config.ts index 0731c0907..39540b9bc 100644 --- a/e2e/fixtures/markdown-link/rspress.config.ts +++ b/e2e/fixtures/markdown-link/rspress.config.ts @@ -2,5 +2,6 @@ import * as path from 'node:path'; import { defineConfig } from 'rspress/config'; export default defineConfig({ + base: '/base/', root: path.join(__dirname, 'doc'), }); diff --git a/packages/core/src/node/mdx/remarkPlugins/normalizeLink.ts b/packages/core/src/node/mdx/remarkPlugins/normalizeLink.ts index 482cb2f10..7799688e6 100644 --- a/packages/core/src/node/mdx/remarkPlugins/normalizeLink.ts +++ b/packages/core/src/node/mdx/remarkPlugins/normalizeLink.ts @@ -5,11 +5,9 @@ import { isProduction, normalizeHref, parseUrl, - removeLeadingSlash, removeTrailingSlash, withBase, } from '@rspress/shared'; -import { DEFAULT_PAGE_EXTENSIONS } from '@rspress/shared/constants'; import { getNodeAttribute } from '@rspress/shared/node-utils'; import type { Root } from 'mdast'; import type { MdxjsEsm } from 'mdast-util-mdxjs-esm'; @@ -20,8 +18,6 @@ import { logger } from '@rspress/shared/logger'; import type { RouteService } from '../../route/RouteService'; import { getASTNodeImport } from '../../utils'; -// TODO: support relative path [subfolder](subfolder) equal to [subfolder](./subfolder) - function checkDeadLinks( internalLinks: Map, filePath: string, @@ -35,6 +31,7 @@ function checkDeadLinks( } // allow fuzzy matching, e.g: /guide/ and /guide is equal + // This is a simple judgment, the performance will be better than "matchPath" in react-router-dom if ( !routeService.isExistRoute(removeTrailingSlash(cleanLinkPath)) && !routeService.isExistRoute(addTrailingSlash(cleanLinkPath)) @@ -85,26 +82,14 @@ function normalizeLink( return nodeUrl; } - const extname = path.extname(url); - - if ((routeService?.extensions ?? DEFAULT_PAGE_EXTENSIONS).includes(extname)) { - url = url.replace(new RegExp(`\\${extname}$`), ''); - } - - if (url.startsWith('.')) { + // 1. [](/api/getting-started)) or [](/en/api/getting-started)) + if (url.startsWith('/')) { + const { routePath } = routeService.normalizeRoutePath(url); + url = routePath; + } else { + // 2. [getting-started](getting-started) or [getting-started](./getting-started) or [getting-started](../getting-started) const anotherFileAbsolutePath = path.join(path.dirname(filePath), url); url = routeService.absolutePathToRoutePath(anotherFileAbsolutePath); - } else { - url = url.replace(/\/index\.html$/, '/'); - url = url.replace(/\/index$/, '/'); - const [pathVersion, pathLang] = routeService.getRoutePathParts( - routeService.absolutePathToRelativePath(filePath), - ); - - const [_, __, urlPath] = routeService.getRoutePathParts(url); - - url = removeLeadingSlash(urlPath); - url = [pathVersion, pathLang, url].filter(Boolean).join('/'); } if (typeof cleanUrls === 'boolean') { diff --git a/packages/core/src/node/route/RouteService.test.ts b/packages/core/src/node/route/RouteService.test.ts index 2a36a26e8..d129073bc 100644 --- a/packages/core/src/node/route/RouteService.test.ts +++ b/packages/core/src/node/route/RouteService.test.ts @@ -2,16 +2,19 @@ import path from 'node:path'; import type { UserConfig } from '@rspress/shared'; import { describe, expect, it } from 'vitest'; import { PluginDriver } from '../PluginDriver'; -import { normalizePath } from '../utils'; import { RouteService } from './RouteService'; -async function initRouteService(config: UserConfig) { - const testDir = normalizePath(path.join(__dirname, 'fixtures', 'basic')); +const BASIC_DIR = path.join(__dirname, 'fixtures', 'basic'); + +async function initRouteService( + config: UserConfig, + fixtureDir: string = BASIC_DIR, +) { const routeService = await RouteService.create({ config, pluginDriver: new PluginDriver(config, false), runtimeTempDir: '.rsbuild', - scanDir: testDir, + scanDir: fixtureDir, }); const { routeData } = routeService; @@ -277,3 +280,112 @@ describe('RouteService', async () => { `); }); }); + +describe('RouteService with i18n', async () => { + it('basic', async () => { + const BASIC_DIR = path.join(__dirname, 'fixtures', 'locales'); + + const { routeData } = await initRouteService( + { + lang: 'en', + themeConfig: { + locales: [ + { + lang: 'en', + label: 'English', + }, + { + lang: 'zh', + label: '中文', + }, + ], + }, + }, + BASIC_DIR, + ); + expect(routeData).toMatchInlineSnapshot(` + Map { + "/guide/basic/install" => RoutePage { + "routeMeta": { + "absolutePath": "/packages/core/src/node/route/fixtures/locales/en/guide/basic/install.mdx", + "lang": "en", + "pageName": "en_guide_basic_install", + "relativePath": "en/guide/basic/install.mdx", + "routePath": "/guide/basic/install", + "version": "", + }, + }, + "/guide/basic/quick-start" => RoutePage { + "routeMeta": { + "absolutePath": "/packages/core/src/node/route/fixtures/locales/en/guide/basic/quick-start.mdx", + "lang": "en", + "pageName": "en_guide_basic_quick-start", + "relativePath": "en/guide/basic/quick-start.mdx", + "routePath": "/guide/basic/quick-start", + "version": "", + }, + }, + "/guide/" => RoutePage { + "routeMeta": { + "absolutePath": "/packages/core/src/node/route/fixtures/locales/en/guide/index.mdx", + "lang": "en", + "pageName": "en_guide_index", + "relativePath": "en/guide/index.mdx", + "routePath": "/guide/", + "version": "", + }, + }, + "/" => RoutePage { + "routeMeta": { + "absolutePath": "/packages/core/src/node/route/fixtures/locales/en/index.mdx", + "lang": "en", + "pageName": "en_index", + "relativePath": "en/index.mdx", + "routePath": "/", + "version": "", + }, + }, + "/zh/guide/basic/install" => RoutePage { + "routeMeta": { + "absolutePath": "/packages/core/src/node/route/fixtures/locales/zh/guide/basic/install.mdx", + "lang": "zh", + "pageName": "zh_guide_basic_install", + "relativePath": "zh/guide/basic/install.mdx", + "routePath": "/zh/guide/basic/install", + "version": "", + }, + }, + "/zh/guide/basic/quick-start" => RoutePage { + "routeMeta": { + "absolutePath": "/packages/core/src/node/route/fixtures/locales/zh/guide/basic/quick-start.mdx", + "lang": "zh", + "pageName": "zh_guide_basic_quick-start", + "relativePath": "zh/guide/basic/quick-start.mdx", + "routePath": "/zh/guide/basic/quick-start", + "version": "", + }, + }, + "/zh/guide/" => RoutePage { + "routeMeta": { + "absolutePath": "/packages/core/src/node/route/fixtures/locales/zh/guide/index.mdx", + "lang": "zh", + "pageName": "zh_guide_index", + "relativePath": "zh/guide/index.mdx", + "routePath": "/zh/guide/", + "version": "", + }, + }, + "/zh/" => RoutePage { + "routeMeta": { + "absolutePath": "/packages/core/src/node/route/fixtures/locales/zh/index.mdx", + "lang": "zh", + "pageName": "zh_index", + "relativePath": "zh/index.mdx", + "routePath": "/zh/", + "version": "", + }, + }, + } + `); + }); +}); diff --git a/packages/core/src/node/route/fixtures/locales/en/guide/basic/install.mdx b/packages/core/src/node/route/fixtures/locales/en/guide/basic/install.mdx new file mode 100644 index 000000000..55af1c56e --- /dev/null +++ b/packages/core/src/node/route/fixtures/locales/en/guide/basic/install.mdx @@ -0,0 +1 @@ +# Install diff --git a/packages/core/src/node/route/fixtures/locales/en/guide/basic/quick-start.mdx b/packages/core/src/node/route/fixtures/locales/en/guide/basic/quick-start.mdx new file mode 100644 index 000000000..754bef8a6 --- /dev/null +++ b/packages/core/src/node/route/fixtures/locales/en/guide/basic/quick-start.mdx @@ -0,0 +1 @@ +# Quick start diff --git a/packages/core/src/node/route/fixtures/locales/en/guide/index.mdx b/packages/core/src/node/route/fixtures/locales/en/guide/index.mdx new file mode 100644 index 000000000..8c0d02fad --- /dev/null +++ b/packages/core/src/node/route/fixtures/locales/en/guide/index.mdx @@ -0,0 +1 @@ +# Guide diff --git a/packages/core/src/node/route/fixtures/locales/en/index.mdx b/packages/core/src/node/route/fixtures/locales/en/index.mdx new file mode 100644 index 000000000..f13970f5c --- /dev/null +++ b/packages/core/src/node/route/fixtures/locales/en/index.mdx @@ -0,0 +1 @@ +# homePage diff --git a/packages/core/src/node/route/fixtures/locales/zh/guide/basic/install.mdx b/packages/core/src/node/route/fixtures/locales/zh/guide/basic/install.mdx new file mode 100644 index 000000000..7144b3c74 --- /dev/null +++ b/packages/core/src/node/route/fixtures/locales/zh/guide/basic/install.mdx @@ -0,0 +1 @@ +# 安装 diff --git a/packages/core/src/node/route/fixtures/locales/zh/guide/basic/quick-start.mdx b/packages/core/src/node/route/fixtures/locales/zh/guide/basic/quick-start.mdx new file mode 100644 index 000000000..5d58acf6f --- /dev/null +++ b/packages/core/src/node/route/fixtures/locales/zh/guide/basic/quick-start.mdx @@ -0,0 +1 @@ +# 快速开始 diff --git a/packages/core/src/node/route/fixtures/locales/zh/guide/index.mdx b/packages/core/src/node/route/fixtures/locales/zh/guide/index.mdx new file mode 100644 index 000000000..80357a5be --- /dev/null +++ b/packages/core/src/node/route/fixtures/locales/zh/guide/index.mdx @@ -0,0 +1 @@ +# Guide 页面 diff --git a/packages/core/src/node/route/fixtures/locales/zh/index.mdx b/packages/core/src/node/route/fixtures/locales/zh/index.mdx new file mode 100644 index 000000000..911f777b8 --- /dev/null +++ b/packages/core/src/node/route/fixtures/locales/zh/index.mdx @@ -0,0 +1 @@ +# 首页 diff --git a/packages/core/src/node/route/normalizeRoutePath.ts b/packages/core/src/node/route/normalizeRoutePath.ts index 07015b410..5521a3f95 100644 --- a/packages/core/src/node/route/normalizeRoutePath.ts +++ b/packages/core/src/node/route/normalizeRoutePath.ts @@ -1,8 +1,4 @@ -import { - addLeadingSlash, - addTrailingSlash, - removeLeadingSlash, -} from '@rspress/shared'; +import { addLeadingSlash, addTrailingSlash } from '@rspress/shared'; import { DEFAULT_PAGE_EXTENSIONS } from '@rspress/shared/constants'; export const getRoutePathParts = ( @@ -50,6 +46,11 @@ export const getRoutePathParts = ( ] as const; }; +/** + * + * @param relativePath "/v3/en/guide/getting-started.mdx" or "/v3/guide/getting-started.mdx" or "/en/guide/getting-started.mdx" or "/guide/getting-started.mdx" + * @returns + */ export const normalizeRoutePath = ( relativePath: string, lang: string, @@ -58,23 +59,18 @@ export const normalizeRoutePath = ( versions: string[], extensions: string[] = DEFAULT_PAGE_EXTENSIONS, ) => { - // /v3/en/guide/getting-started.html - let routePath = relativePath; - // 1. remove extension const extensionsWithoutDot = extensions.map(i => i.slice(1)); const cleanExtensionPattern = new RegExp( `\\.(${extensionsWithoutDot.join('|')})$`, 'i', ); - routePath = routePath + + let routePath = relativePath .replace(cleanExtensionPattern, '') .replace(/\.html$/, ''); - // 2. remove /index - routePath = routePath.replace(/\/index$/, '/'); - - // 3. remove /v3/en + // 2. remove /v3/en const [versionPart, langPart, purePathPart] = getRoutePathParts( routePath, lang, @@ -83,14 +79,14 @@ export const normalizeRoutePath = ( versions, ); - routePath = removeLeadingSlash(purePathPart); - + // 3. remove index + routePath = purePathPart.replace(/\/index$/, '/'); if (routePath === 'index') { routePath = ''; } const normalizedRoutePath = addLeadingSlash( - [versionPart, langPart, routePath].filter(Boolean).join('/'), + [...[versionPart, langPart].filter(Boolean), routePath].join('/'), ); return { diff --git a/packages/document/docs/en/api/config/config-basic.mdx b/packages/document/docs/en/api/config/config-basic.mdx index 2991b17cf..68c75c539 100644 --- a/packages/document/docs/en/api/config/config-basic.mdx +++ b/packages/document/docs/en/api/config/config-basic.mdx @@ -409,7 +409,7 @@ export default defineConfig({ :::note -We recommend using [addPages hook](plugin/system/plugin-api.html#addpages) in a custom Rspress plugin to add some additional files to the route, so that the page route and file path/content can be specified more flexibly and reasonably. +We recommend using [addPages hook](/plugin/system/plugin-api.html#addpages) in a custom Rspress plugin to add some additional files to the route, so that the page route and file path/content can be specified more flexibly and reasonably. ::: diff --git a/packages/document/docs/zh/api/config/config-basic.mdx b/packages/document/docs/zh/api/config/config-basic.mdx index ba8d7be03..6f14a83d2 100644 --- a/packages/document/docs/zh/api/config/config-basic.mdx +++ b/packages/document/docs/zh/api/config/config-basic.mdx @@ -408,7 +408,7 @@ export default defineConfig({ :::note -我们更加推荐在自定义 Rspress 插件中使用 [addPages hook](plugin/system/plugin-api.html#addpages) 来在路由中添加一些额外的文件,这样可以更灵活且更合理地指定页面路由和文件路径/内容。 +我们更加推荐在自定义 Rspress 插件中使用 [addPages hook](/plugin/system/plugin-api.html#addpages) 来在路由中添加一些额外的文件,这样可以更灵活且更合理地指定页面路由和文件路径/内容。 :::