From e5856ca65d49fdc51b28e5fb3014c0dd60ea2bd6 Mon Sep 17 00:00:00 2001 From: Divyansh Singh <40380293+brc-dd@users.noreply.github.com> Date: Thu, 7 Jul 2022 13:25:14 +0530 Subject: [PATCH] feat: add without subfolders option for clean urls --- docs/.vitepress/config.ts | 2 +- docs/config/app-configs.md | 26 +++-- docs/guide/migration-from-vitepress-0.md | 2 +- docs/guide/migration-from-vuepress.md | 4 +- docs/guide/theme-nav.md | 2 +- package.json | 4 +- pnpm-lock.yaml | 104 +++++++----------- src/client/app/router.ts | 13 +-- .../theme-default/components/VPDocFooter.vue | 6 +- .../theme-default/components/VPLink.vue | 5 +- src/client/theme-default/support/utils.ts | 11 +- src/node/build/render.ts | 22 +--- src/node/config.ts | 26 +++-- src/node/markdown/markdown.ts | 7 +- src/node/markdown/plugins/link.ts | 16 ++- src/node/markdownToVue.ts | 9 +- src/node/plugin.ts | 3 +- src/shared/shared.ts | 3 +- types/shared.d.ts | 7 +- 19 files changed, 118 insertions(+), 154 deletions(-) diff --git a/docs/.vitepress/config.ts b/docs/.vitepress/config.ts index fc9983a3..634faf87 100644 --- a/docs/.vitepress/config.ts +++ b/docs/.vitepress/config.ts @@ -8,7 +8,7 @@ export default defineConfig({ description: 'Vite & Vue powered static site generator.', lastUpdated: true, - cleanUrls: 'off', + cleanUrls: 'without-subfolders', themeConfig: { nav: nav(), diff --git a/docs/config/app-configs.md b/docs/config/app-configs.md index b065d48b..816fdfd2 100644 --- a/docs/config/app-configs.md +++ b/docs/config/app-configs.md @@ -115,7 +115,7 @@ Below shows the the full option you may define within this object. interface MarkdownOptions extends MarkdownIt.Options { // Syntax highlight theme for Shiki. // See: https://github.com/shikijs/shiki/blob/main/docs/themes.md#all-themes - theme?: Shiki.Theme | { light: Shiki.Theme, dark: Shiki.Theme } + theme?: Shiki.Theme | { light: Shiki.Theme; dark: Shiki.Theme } // Enable line numbers in code block. lineNumbers?: boolean @@ -173,19 +173,27 @@ export default { } ``` -## cleanUrls +## cleanUrls (Experimental) -- Type: `"off" | "with-subfolders"` -- Default: `"off"` +- Type: `'disabled' | 'without-subfolders' | 'with-subfolders'` +- Default: `'disabled'` -| Option | Page | Generated page | URL | Generated 404 | -|-------------------|---------------|---------------------|--------------|----------------| -| `off` | foo/bar.md | foo/bar.html | foo/bar.html | /404.html | -| `with-subfolders` | foo/bar.md | foo/bar/index.html | foo/bar | /404.html | +Allows removing trailing `.html` from URLs and, optionally, generating clean directory structure. Available modes: +| Mode | Page | Generated Page | URL | +| :--------------------: | :-------: | :---------------: | :---------: | +| `'disabled'` | `/foo.md` | `/foo.html` | `/foo.html` | +| `'without-subfolders'` | `/foo.md` | `/foo.html` | `/foo` | +| `'with-subfolders'` | `/foo.md` | `/foo/index.html` | `/foo` | + +::: warning + +Enabling this may require additional configuration on your hosting platform. For it to work, your server must serve the generated page on requesting the URL (see above table) **without a redirect**. + +::: ```ts export default { - cleanUrls: "with-subfolders" + cleanUrls: 'with-subfolders' } ``` diff --git a/docs/guide/migration-from-vitepress-0.md b/docs/guide/migration-from-vitepress-0.md index f7041dc8..ff5cf3df 100644 --- a/docs/guide/migration-from-vitepress-0.md +++ b/docs/guide/migration-from-vitepress-0.md @@ -12,7 +12,7 @@ If you're coming from VitePress 0.x version, there're several breaking changes d - `children` key is now named `items`. - Top level item may not contain `link` at the moment. We're planning to bring it back. - `repo`, `repoLabel`, `docsDir`, `docsBranch`, `editLinks`, `editLinkText` are removed in favor of more flexible api. - - For adding GitHub link with icon to the nav, use [Social Links](./theme-nav.html#navigation-links) feature. + - For adding GitHub link with icon to the nav, use [Social Links](./theme-nav#navigation-links) feature. - For adding "Edit this page" feature, use [Edit Link](./theme-edit-link) feature. - `lastUpdated` option is now split into `config.lastUpdated` and `themeConfig.lastUpdatedText`. - `carbonAds.carbon` is changed to `carbonAds.code`. diff --git a/docs/guide/migration-from-vuepress.md b/docs/guide/migration-from-vuepress.md index c18c754f..e646ae54 100644 --- a/docs/guide/migration-from-vuepress.md +++ b/docs/guide/migration-from-vuepress.md @@ -4,7 +4,7 @@ ### Images -Unlike VuePress, VitePress handles [`base`](/guide/asset-handling.html#base-url) of your config automatically when you use static image. +Unlike VuePress, VitePress handles [`base`](./asset-handling#base-url) of your config automatically when you use static image. Hence, now you can render images without `img` tag. @@ -14,7 +14,7 @@ Hence, now you can render images without `img` tag. ``` ::: warning -For dynamic images you still need `withBase` as shown in [Base URL guide](/guide/asset-handling.html#base-url). +For dynamic images you still need `withBase` as shown in [Base URL guide](./asset-handling#base-url). ::: Use `` regex to find and replace it with `![$2]($1)` to replace all the images with `![](...)` syntax. diff --git a/docs/guide/theme-nav.md b/docs/guide/theme-nav.md index 81575e9b..d361d3a0 100644 --- a/docs/guide/theme-nav.md +++ b/docs/guide/theme-nav.md @@ -4,7 +4,7 @@ The Nav is the navigation bar displayed on top of the page. It contains the site ## Site Title and Logo -By default, nav shows the title of the site refferencing [`config.title`](../config/app-configs.html#title) value. If you would like to change what's displayed on nav, you may define custom text in `themeConfig.siteTitle` option. +By default, nav shows the title of the site refferencing [`config.title`](../config/app-configs#title) value. If you would like to change what's displayed on nav, you may define custom text in `themeConfig.siteTitle` option. ```js export default { diff --git a/package.json b/package.json index 8bb30de8..90fbf0a2 100644 --- a/package.json +++ b/package.json @@ -73,12 +73,12 @@ "dependencies": { "@docsearch/css": "^3.1.1", "@docsearch/js": "^3.1.1", - "@vitejs/plugin-vue": "^3.0.0-beta.0", + "@vitejs/plugin-vue": "^3.0.0-beta.1", "@vue/devtools-api": "^6.2.0", "@vueuse/core": "^8.7.5", "body-scroll-lock": "^4.0.0-beta.0", "shiki": "^0.10.1", - "vite": "3.0.0-beta.5", + "vite": "^3.0.0-beta.7", "vue": "^3.2.37" }, "devDependencies": { diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 538fa0fa..512cbfff 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -24,7 +24,7 @@ importers: '@types/node': ^18.0.1 '@types/polka': ^0.5.4 '@types/prompts': ^2.0.14 - '@vitejs/plugin-vue': ^3.0.0-beta.0 + '@vitejs/plugin-vue': ^3.0.0-beta.1 '@vue/devtools-api': ^6.2.0 '@vueuse/core': ^8.7.5 body-scroll-lock: ^4.0.0-beta.0 @@ -67,19 +67,19 @@ importers: sirv: ^2.0.2 supports-color: ^9.2.2 typescript: ^4.7.4 - vite: 3.0.0-beta.5 + vite: ^3.0.0-beta.7 vitest: ^0.17.0 vue: ^3.2.37 vue-tsc: ^0.38.2 dependencies: '@docsearch/css': 3.1.1 '@docsearch/js': 3.1.1 - '@vitejs/plugin-vue': 3.0.0-beta.0_hrw2jqbpnmgiltw2su6c7ud5mq + '@vitejs/plugin-vue': 3.0.0-beta.1_gsdjzz3hbcro3set7v2rc2jro4 '@vue/devtools-api': 6.2.0 - '@vueuse/core': 8.7.5_vue@3.2.37 + '@vueuse/core': 8.8.0_vue@3.2.37 body-scroll-lock: 4.0.0-beta.0 shiki: 0.10.1 - vite: 3.0.0-beta.5 + vite: 3.0.0-beta.7 vue: 3.2.37 devDependencies: '@rollup/plugin-alias': 3.1.9_rollup@2.75.7 @@ -97,7 +97,7 @@ importers: '@types/markdown-it': 12.2.3 '@types/micromatch': 4.0.2 '@types/minimist': 1.2.2 - '@types/node': 18.0.1 + '@types/node': 18.0.3 '@types/polka': 0.5.4 '@types/prompts': 2.0.14 chokidar: 3.5.3 @@ -459,14 +459,14 @@ packages: /@types/accepts/1.3.5: resolution: {integrity: sha512-jOdnI/3qTpHABjM5cx1Hc0sKsPoYCp+DP/GJRGtDlPd7fiV9oXGGIcjW/ZOxLIvjGz8MA+uMZI9metHlgqbgwQ==} dependencies: - '@types/node': 18.0.1 + '@types/node': 18.0.3 dev: true /@types/body-parser/1.19.2: resolution: {integrity: sha512-ALYone6pm6QmwZoAgeyNksccT9Q4AWZQ6PvfwR37GT6r6FWUPguq6sUmNGSMV2Wr761oQoBxwGGa6DR5o1DC9g==} dependencies: '@types/connect': 3.4.35 - '@types/node': 18.0.1 + '@types/node': 18.0.3 dev: true /@types/body-scroll-lock/3.1.0: @@ -496,7 +496,7 @@ packages: /@types/connect/3.4.35: resolution: {integrity: sha512-cdeYyv4KWoEgpBISTxWvqYsVy444DOqehiF3fM3ne10AmJ62RSyNkUnxMJXHQWRQQX2eR94m5y1IZyDwBjV9FQ==} dependencies: - '@types/node': 18.0.1 + '@types/node': 18.0.3 dev: true /@types/content-disposition/0.5.5: @@ -509,13 +509,13 @@ packages: '@types/connect': 3.4.35 '@types/express': 4.17.13 '@types/keygrip': 1.0.2 - '@types/node': 18.0.1 + '@types/node': 18.0.3 dev: true /@types/cross-spawn/6.0.2: resolution: {integrity: sha512-KuwNhp3eza+Rhu8IFI5HUXRP0LIhqH5cAjubUvGXXthh4YYBuP2ntwEX+Cz8GJoZUHlKo247wPWOfA9LYEq4cw==} dependencies: - '@types/node': 18.0.1 + '@types/node': 18.0.3 dev: true /@types/debug/4.1.7: @@ -535,7 +535,7 @@ packages: /@types/express-serve-static-core/4.17.29: resolution: {integrity: sha512-uMd++6dMKS32EOuw1Uli3e3BPgdLIXmezcfHv7N4c1s3gkhikBplORPpMq3fuWkxncZN1reb16d5n8yhQ80x7Q==} dependencies: - '@types/node': 18.0.1 + '@types/node': 18.0.3 '@types/qs': 6.9.7 '@types/range-parser': 1.2.4 dev: true @@ -552,7 +552,7 @@ packages: /@types/fs-extra/9.0.13: resolution: {integrity: sha512-nEnwB++1u5lVDM2UI4c1+5R+FYaKfaAzS4OococimjVm3nQw3TuzH5UNsocrcTBbhnerblyHj4A49qXbIiZdpA==} dependencies: - '@types/node': 18.0.1 + '@types/node': 18.0.3 dev: true /@types/http-assert/1.5.3: @@ -596,7 +596,7 @@ packages: '@types/http-errors': 1.8.2 '@types/keygrip': 1.0.2 '@types/koa-compose': 3.2.5 - '@types/node': 18.0.1 + '@types/node': 18.0.3 dev: true /@types/linkify-it/3.0.2: @@ -632,8 +632,8 @@ packages: resolution: {integrity: sha512-iiUgKzV9AuaEkZqkOLDIvlQiL6ltuZd9tGcW3gwpnX8JbuiuhFlEGmmFXEXkN50Cvq7Os88IY2v0dkDqXYWVgA==} dev: true - /@types/node/18.0.1: - resolution: {integrity: sha512-CmR8+Tsy95hhwtZBKJBs0/FFq4XX7sDZHlGGf+0q+BRZfMbOTkzkj0AFAuTyXbObDIoanaBBW0+KEW+m3N16Wg==} + /@types/node/18.0.3: + resolution: {integrity: sha512-HzNRZtp4eepNitP+BD6k2L6DROIDG4Q0fm4x+dwfsr6LGmROENnok75VGw40628xf+iR24WeMFcHuuBDUAzzsQ==} dev: true /@types/normalize-package-data/2.4.1: @@ -645,14 +645,14 @@ packages: dependencies: '@types/express': 4.17.13 '@types/express-serve-static-core': 4.17.29 - '@types/node': 18.0.1 + '@types/node': 18.0.3 '@types/trouter': 3.1.1 dev: true /@types/prompts/2.0.14: resolution: {integrity: sha512-HZBd99fKxRWpYCErtm2/yxUZv6/PBI9J7N4TNFffl5JbrYMHBwF25DjQGTW3b3jmXq+9P6/8fCIb2ee57BFfYA==} dependencies: - '@types/node': 18.0.1 + '@types/node': 18.0.3 dev: true /@types/qs/6.9.7: @@ -666,14 +666,14 @@ packages: /@types/resolve/1.17.1: resolution: {integrity: sha512-yy7HuzQhj0dhGpD8RLXSZWEkLsV9ibvxvi6EiJ3bkqLAO1RGo0WbkWQiwpRlSFymTJRz0d3k5LM3kkx8ArDbLw==} dependencies: - '@types/node': 18.0.1 + '@types/node': 18.0.3 dev: true /@types/serve-static/1.13.10: resolution: {integrity: sha512-nCkHGI4w7ZgAdNkrEu0bv+4xNV/XDqW+DydknebMOQwkpDGx8G+HTlj7R7ABI8i8nKxVw0wtKPi1D+lPOkh4YQ==} dependencies: '@types/mime': 1.3.2 - '@types/node': 18.0.1 + '@types/node': 18.0.3 dev: true /@types/trouter/3.1.1: @@ -684,14 +684,14 @@ packages: resolution: {integrity: sha512-5d2RhCard1nQUC3aHcq/gHzWYO6K0WJmAbjO7mQJgCQKtZpgXxv1rOM6O/dBDhDYYVutk1sciOgNSe+5YyfM8A==} dev: false - /@vitejs/plugin-vue/3.0.0-beta.0_hrw2jqbpnmgiltw2su6c7ud5mq: - resolution: {integrity: sha512-t8os1QK1qpovpgYAJSOWYEu+Doy/DZRW1cNwMvUl0qo+Yv7D9a3cxo24oL01lbojcc9ABQhyvUP3BsvFNtriqg==} + /@vitejs/plugin-vue/3.0.0-beta.1_gsdjzz3hbcro3set7v2rc2jro4: + resolution: {integrity: sha512-cPVQHIKZkVEQ8qW7+BlbTrGJXNpP2aMKzVhQdTnWK9u6cSDmVdZOXHmKPO2KVvrNpFXXS8R7hHBXMsSApA+XOA==} engines: {node: '>=14.18.0'} peerDependencies: vite: ^3.0.0-alpha vue: ^3.2.25 dependencies: - vite: 3.0.0-beta.5 + vite: 3.0.0-beta.7 vue: 3.2.37 dev: false @@ -805,8 +805,8 @@ packages: /@vue/shared/3.2.37: resolution: {integrity: sha512-4rSJemR2NQIo9Klm1vabqWjD8rs/ZaJSzMxkMNeJS6lHiUjjUeYFbooN19NgFjztubEKh3WlZUeOLVdbbUWHsw==} - /@vueuse/core/8.7.5_vue@3.2.37: - resolution: {integrity: sha512-tqgzeZGoZcXzoit4kOGLWJibDMLp0vdm6ZO41SSUQhkhtrPhAg6dbIEPiahhUu6sZAmSYvVrZgEr5aKD51nrLA==} + /@vueuse/core/8.8.0_vue@3.2.37: + resolution: {integrity: sha512-TyvcNuA6O9WGkT8oQB4ERt8aBxe/e0fUs3SnibaxtLOr4eVXq42m3sLZgwgWOrJi4s9/8pTsMaJNn/6BUefwpQ==} peerDependencies: '@vue/composition-api': ^1.1.0 vue: ^2.6.0 || ^3.2.0 @@ -817,18 +817,18 @@ packages: optional: true dependencies: '@types/web-bluetooth': 0.0.14 - '@vueuse/metadata': 8.7.5 - '@vueuse/shared': 8.7.5_vue@3.2.37 + '@vueuse/metadata': 8.8.0 + '@vueuse/shared': 8.8.0_vue@3.2.37 vue: 3.2.37 vue-demi: 0.13.2_vue@3.2.37 dev: false - /@vueuse/metadata/8.7.5: - resolution: {integrity: sha512-emJZKRQSaEnVqmlu39NpNp8iaW+bPC2kWykWoWOZMSlO/0QVEmO/rt8A5VhOEJTKLX3vwTevqbiRy9WJRwVOQg==} + /@vueuse/metadata/8.8.0: + resolution: {integrity: sha512-bRF+QPrw/RtP0al3nT/DtJ7CN0a6y6tEEO6hQ4CuJcGuUqd15eCOF6WKqQnC5DRaGFhsq/YwnQYsLTdJsW8f1A==} dev: false - /@vueuse/shared/8.7.5_vue@3.2.37: - resolution: {integrity: sha512-THXPvMBFmg6Gf6AwRn/EdTh2mhqwjGsB2Yfp374LNQSQVKRHtnJ0I42bsZTn7nuEliBxqUrGQm/lN6qUHmhJLw==} + /@vueuse/shared/8.8.0_vue@3.2.37: + resolution: {integrity: sha512-DNZEs5Wy8hxxjAyWni6UK4BX/OGa8R7g0GX1tid5+AvmRbUwvUXL+0lVmGEuWPSQY4OZdYef1lvuFCi4Bfd59A==} peerDependencies: '@vue/composition-api': ^1.1.0 vue: ^2.6.0 || ^3.2.0 @@ -3430,8 +3430,8 @@ packages: readable-stream: 3.6.0 dev: true - /tinypool/0.2.1: - resolution: {integrity: sha512-HFU5ZYVq3wBfhSaf8qdqGsneaqXm0FgJQpoUlJbVdHpRLzm77IneKAD3RjzJWZvIv0YpPB9S7LUW53f6BE6ZSg==} + /tinypool/0.2.2: + resolution: {integrity: sha512-tp4n5OARNL3v8ntdJUyo5NsDfwvUtu8isB43USjrsQxQrADDKY6UGBkmFaw/2vNmEt8S/uSm2U5FhkiK1eAFGw==} engines: {node: '>=14.0.0'} dev: true @@ -3551,8 +3551,8 @@ packages: engines: {node: '>= 0.8'} dev: true - /vite/3.0.0-beta.5: - resolution: {integrity: sha512-SfesZuCME4fEmLy4hgsJAg55HRiTgDhH3oPM44XePrdKP5FqYvDkzpSWl6ldDOJYTskKWafGyyuYfXoxodv40Q==} + /vite/3.0.0-beta.7: + resolution: {integrity: sha512-yjw154hB229qq5Bl6+/CJSTxC/yIDmDJbaAjE/pdracz3jytNEd2ovk5BvxgZT6+qPiUc2rRH3FgGqiZnweIFw==} engines: {node: '>=14.18.0'} hasBin: true peerDependencies: @@ -3576,34 +3576,6 @@ packages: rollup: 2.75.7 optionalDependencies: fsevents: 2.3.2 - dev: false - - /vite/3.0.0-beta.6: - resolution: {integrity: sha512-jAxxCGXs6oIO3dFh7gwDEP9RqFzYY+ULDWawS1dd3HfM4FCr8rkOnLljDoBBIDdTNM8M7pDzdoYSmpPEOJqyZQ==} - engines: {node: '>=14.18.0'} - hasBin: true - peerDependencies: - less: '*' - sass: '*' - stylus: '*' - terser: ^5.4.0 - peerDependenciesMeta: - less: - optional: true - sass: - optional: true - stylus: - optional: true - terser: - optional: true - dependencies: - esbuild: 0.14.48 - postcss: 8.4.14 - resolve: 1.22.1 - rollup: 2.75.7 - optionalDependencies: - fsevents: 2.3.2 - dev: true /vitest/0.17.0_supports-color@9.2.2: resolution: {integrity: sha512-5YO9ubHo0Zg35mea3+zZAr4sCku32C3usvIH5COeJB48TZV/R0J9aGNtGOOqEWZYfOKP0pGZUvTokne3x/QEFg==} @@ -3629,13 +3601,13 @@ packages: dependencies: '@types/chai': 4.3.1 '@types/chai-subset': 1.3.3 - '@types/node': 18.0.1 + '@types/node': 18.0.3 chai: 4.3.6 debug: 4.3.4_supports-color@9.2.2 local-pkg: 0.4.1 - tinypool: 0.2.1 + tinypool: 0.2.2 tinyspy: 0.3.3 - vite: 3.0.0-beta.6 + vite: 3.0.0-beta.7 transitivePeerDependencies: - less - sass diff --git a/src/client/app/router.ts b/src/client/app/router.ts index 81f17c4f..cecdb198 100644 --- a/src/client/app/router.ts +++ b/src/client/app/router.ts @@ -40,17 +40,15 @@ export function createRouter( const route = reactive(getDefaultRoute()) function go(href: string = inBrowser ? location.href : '/') { - // ensure correct deep link so page refresh lands on correct files. const url = new URL(href, fakeHost) - if (siteDataRef.value.cleanUrls === 'off') { - // No clean URLs - // Let's add ".html" if missing + if (siteDataRef.value.cleanUrls === 'disabled') { + // ensure correct deep link so page refresh lands on correct files. + // if cleanUrls is enabled, the server should handle this if (!url.pathname.endsWith('/') && !url.pathname.endsWith('.html')) { url.pathname += '.html' href = url.pathname + url.search + url.hash } } - if (inBrowser) { // save scroll position before changing url history.replaceState({ scrollPosition: window.scrollY }, document.title) @@ -101,10 +99,7 @@ export function createRouter( } } } catch (err: any) { - if ( - !err.message.match(/fetch/) && - !/^[\\/]404[\\/]?(\.html)?$/.test(href) - ) { + if (!/fetch/.test(err.message) && !/^\/404(\.html|\/)?$/.test(href)) { console.error(err) } diff --git a/src/client/theme-default/components/VPDocFooter.vue b/src/client/theme-default/components/VPDocFooter.vue index b01cd414..48d01d68 100644 --- a/src/client/theme-default/components/VPDocFooter.vue +++ b/src/client/theme-default/components/VPDocFooter.vue @@ -8,7 +8,7 @@ import VPIconEdit from './icons/VPIconEdit.vue' import VPLink from './VPLink.vue' import VPDocFooterLastUpdated from './VPDocFooterLastUpdated.vue' -const { site, theme, page, frontmatter } = useData() +const { theme, page, frontmatter } = useData() const editLink = useEditLink() const control = usePrevNext() @@ -35,13 +35,13 @@ const hasLastUpdated = computed(() => {
- diff --git a/src/client/theme-default/components/VPLink.vue b/src/client/theme-default/components/VPLink.vue index 27b34e0a..bf29e4b5 100644 --- a/src/client/theme-default/components/VPLink.vue +++ b/src/client/theme-default/components/VPLink.vue @@ -1,11 +1,8 @@