Skip to content

Commit 8ca0cc6

Browse files
perf: implement custom routes (#1447)
BREAKING CHANGE: vue-router's route records have been replaced by custom route records to get better performance. It should not break common usage, but could be a potential breaking change for some themes. vue-router is suitable for SPAs, but not for static sites. It has a negative impact on the performance of vuepress sites, especially large-scale ones. In the long run we'll replace vue-router with a light-weighted custom router totally. -------- Co-authored-by: Xinyu Liu <[email protected]>
1 parent 5281a42 commit 8ca0cc6

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

65 files changed

+703
-543
lines changed

e2e/docs/.vuepress/config.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,4 +52,14 @@ export default defineUserConfig({
5252
bundler: E2E_BUNDLER === 'webpack' ? webpackBundler() : viteBundler(),
5353

5454
theme: e2eTheme(),
55+
56+
extendsPage: (page) => {
57+
if (page.path === '/page-data/route-meta.html') {
58+
page.routeMeta = {
59+
a: 1,
60+
b: 2,
61+
...page.routeMeta,
62+
}
63+
}
64+
},
5565
})

e2e/docs/404.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
---
2+
routeMeta:
3+
foo: bar
4+
---

e2e/docs/page-data/route-meta.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
routeMeta:
3+
a: 0
4+
c: 3
5+
---

e2e/docs/router/resolve-route.md

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
## resolve
2+
3+
### Path
4+
5+
#### Index
6+
7+
- Clean URL: {{ JSON.stringify(resolveRoute('/')) }}
8+
- HTML: {{ JSON.stringify(resolveRoute('/index.html')) }}
9+
- Markdown: {{ JSON.stringify(resolveRoute('/README.md')) }}
10+
11+
#### Non-Index
12+
13+
- Clean URL: {{ JSON.stringify(resolveRoute('/router/resolve-route')) }}
14+
- HTML: {{ JSON.stringify(resolveRoute('/router/resolve-route.html')) }}
15+
- Markdown: {{ JSON.stringify(resolveRoute('/router/resolve-route.md')) }}
16+
17+
#### Non-ASCII
18+
19+
- Clean URL: {{ JSON.stringify(resolveRoute('/routes/non-ascii-paths/中文目录名/中文文件名')) }}
20+
- HTML: {{ JSON.stringify(resolveRoute('/routes/non-ascii-paths/中文目录名/中文文件名.html')) }}
21+
- Markdown: {{ JSON.stringify(resolveRoute('/routes/non-ascii-paths/中文目录名/中文文件名.md')) }}
22+
23+
#### Non-ASCII Encoded
24+
25+
- Clean URL: {{ JSON.stringify(resolveRoute(encodeURI('/routes/non-ascii-paths/中文目录名/中文文件名'))) }}
26+
- HTML: {{ JSON.stringify(resolveRoute(encodeURI('/routes/non-ascii-paths/中文目录名/中文文件名.html'))) }}
27+
- Markdown: {{ JSON.stringify(resolveRoute(encodeURI('/routes/non-ascii-paths/中文目录名/中文文件名.md'))) }}
28+
29+
#### Non-Existent
30+
31+
- Clean URL: {{ JSON.stringify(resolveRoute('/non-existent')) }}
32+
- HTML: {{ JSON.stringify(resolveRoute('/non-existent.html')) }}
33+
- Markdown: {{ JSON.stringify(resolveRoute('/non-existent.md')) }}
34+
35+
#### Route Meta
36+
37+
- Clean URL: {{ JSON.stringify(resolveRoute('/page-data/route-meta')) }}
38+
- HTML: {{ JSON.stringify(resolveRoute('/page-data/route-meta.html')) }}
39+
- Markdown: {{ JSON.stringify(resolveRoute('/page-data/route-meta.md')) }}
40+
41+
<script setup>
42+
import { resolveRoute } from 'vuepress/client'
43+
</script>
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
const testCases = [
2+
{
3+
selector: '#index',
4+
expected: {
5+
path: '/',
6+
meta: {},
7+
notFound: false,
8+
},
9+
},
10+
{
11+
selector: '#non-index',
12+
expected: {
13+
path: '/router/resolve-route.html',
14+
meta: {},
15+
notFound: false,
16+
},
17+
},
18+
{
19+
selector: '#non-ascii',
20+
expected: {
21+
path: encodeURI('/routes/non-ascii-paths/中文目录名/中文文件名.html'),
22+
meta: {},
23+
notFound: false,
24+
},
25+
},
26+
{
27+
selector: '#non-ascii-encoded',
28+
expected: {
29+
path: encodeURI('/routes/non-ascii-paths/中文目录名/中文文件名.html'),
30+
meta: {},
31+
notFound: false,
32+
},
33+
},
34+
{
35+
selector: '#non-existent',
36+
expected: {
37+
path: '/non-existent.html',
38+
meta: { foo: 'bar' },
39+
notFound: true,
40+
},
41+
},
42+
{
43+
selector: '#route-meta',
44+
expected: {
45+
path: '/page-data/route-meta.html',
46+
meta: { a: 0, b: 2, c: 3 },
47+
notFound: false,
48+
},
49+
},
50+
]
51+
52+
const parseResolvedRouteFromElement = (el: Cypress.JQueryWithSelector) =>
53+
JSON.parse(/: (\{.*\})\s*$/.exec(el.text())![1])
54+
55+
it('should resolve routes correctly', () => {
56+
cy.visit('/router/resolve-route.html')
57+
58+
testCases.forEach(({ selector, expected }) => {
59+
cy.get(`.e2e-theme-content ${selector} + ul > li`).each((el) => {
60+
const resolvedRoute = parseResolvedRouteFromElement(el)
61+
expect(resolvedRoute.path).to.equal(expected.path)
62+
expect(resolvedRoute.meta).to.deep.equal(expected.meta)
63+
expect(resolvedRoute.notFound).to.equal(expected.notFound)
64+
})
65+
})
66+
})

packages/bundler-vite/src/build/resolvePageChunkFiles.ts

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,7 @@ export const resolvePageChunkFiles = ({
1111
output
1212
.filter(
1313
(item): item is OutputChunk =>
14-
item.type === 'chunk' &&
15-
(item.facadeModuleId === page.componentFilePath ||
16-
item.facadeModuleId === page.dataFilePath),
14+
item.type === 'chunk' && item.facadeModuleId === page.chunkFilePath,
1715
)
1816
.flatMap(({ fileName, imports, dynamicImports }) => [
1917
fileName,

packages/cli/src/commands/dev/handlePageAdd.ts

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,8 @@
11
import {
22
createPage,
3+
preparePageChunk,
34
preparePageComponent,
4-
preparePageData,
5-
preparePagesComponents,
6-
preparePagesData,
7-
preparePagesRoutes,
5+
prepareRoutes,
86
} from '@vuepress/core'
97
import type { App, Page } from '@vuepress/core'
108

@@ -33,12 +31,10 @@ export const handlePageAdd = async (
3331

3432
// prepare page files
3533
await preparePageComponent(app, page)
36-
await preparePageData(app, page)
34+
await preparePageChunk(app, page)
3735

38-
// prepare pages entry
39-
await preparePagesComponents(app)
40-
await preparePagesData(app)
41-
await preparePagesRoutes(app)
36+
// prepare routes file
37+
await prepareRoutes(app)
4238

4339
return page
4440
}

packages/cli/src/commands/dev/handlePageChange.ts

Lines changed: 5 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,8 @@
11
import {
22
createPage,
3+
preparePageChunk,
34
preparePageComponent,
4-
preparePageData,
5-
preparePagesComponents,
6-
preparePagesData,
7-
preparePagesRoutes,
5+
prepareRoutes,
86
} from '@vuepress/core'
97
import type { App, Page } from '@vuepress/core'
108

@@ -36,21 +34,15 @@ export const handlePageChange = async (
3634

3735
// prepare page files
3836
await preparePageComponent(app, pageNew)
39-
await preparePageData(app, pageNew)
37+
await preparePageChunk(app, pageNew)
4038

4139
const isPathChanged = pageOld.path !== pageNew.path
4240
const isRouteMetaChanged =
4341
JSON.stringify(pageOld.routeMeta) !== JSON.stringify(pageNew.routeMeta)
4442

45-
// prepare pages entry if the path is changed
46-
if (isPathChanged) {
47-
await preparePagesComponents(app)
48-
await preparePagesData(app)
49-
}
50-
51-
// prepare pages routes if the path or routeMeta is changed
43+
// prepare routes file if the path or route meta is changed
5244
if (isPathChanged || isRouteMetaChanged) {
53-
await preparePagesRoutes(app)
45+
await prepareRoutes(app)
5446
}
5547

5648
return [pageOld, pageNew]

packages/cli/src/commands/dev/handlePageUnlink.ts

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,4 @@
1-
import {
2-
preparePagesComponents,
3-
preparePagesData,
4-
preparePagesRoutes,
5-
} from '@vuepress/core'
1+
import { prepareRoutes } from '@vuepress/core'
62
import type { App, Page } from '@vuepress/core'
73

84
/**
@@ -25,10 +21,8 @@ export const handlePageUnlink = async (
2521
// remove the old page
2622
app.pages.splice(pageIndex, 1)
2723

28-
// re-prepare page files
29-
await preparePagesComponents(app)
30-
await preparePagesData(app)
31-
await preparePagesRoutes(app)
24+
// re-prepare routes file
25+
await prepareRoutes(app)
3226

3327
return page
3428
}

packages/client/package.json

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -59,9 +59,7 @@
5959
"external": [
6060
"@internal/clientConfigs",
6161
"@internal/layoutComponents",
62-
"@internal/pagesComponents",
63-
"@internal/pagesData",
64-
"@internal/pagesRoutes",
62+
"@internal/routes",
6563
"@internal/siteData"
6664
],
6765
"format": [

0 commit comments

Comments
 (0)