Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: client redirects at vue router level #336

Merged
merged 2 commits into from
Feb 3, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 25 additions & 0 deletions cypress/e2e/theme-yun/redirect.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
context('Client Redirect', {
baseUrl: Cypress.env('theme-yun'),
}, () => {
beforeEach(() => {
cy.visit('/')
})

it('/redirect/old1', () => {
cy.visit('/redirect/old1')

cy.url().should('eq', `${Cypress.env('theme-yun')}posts/redirect`)
})

it('/redirect/old2', () => {
cy.visit('/redirect/old2')

cy.url().should('eq', `${Cypress.env('theme-yun')}posts/redirect`)
})

it('/foo', () => {
cy.visit('/foo')

cy.url().should('eq', `${Cypress.env('theme-yun')}about`)
})
})
1 change: 1 addition & 0 deletions demo/yun/.valaxy/typed-router.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ declare module 'vue-router/auto/routes' {
'/posts/lots-of-images': RouteRecordInfo<'/posts/lots-of-images', '/posts/lots-of-images', Record<never, never>, Record<never, never>>,
'/posts/markdown': RouteRecordInfo<'/posts/markdown', '/posts/markdown', Record<never, never>, Record<never, never>>,
'/posts/post-updated': RouteRecordInfo<'/posts/post-updated', '/posts/post-updated', Record<never, never>, Record<never, never>>,
'/posts/redirect': RouteRecordInfo<'/posts/redirect', '/posts/redirect', Record<never, never>, Record<never, never>>,
'/posts/test': RouteRecordInfo<'/posts/test', '/posts/test', Record<never, never>, Record<never, never>>,
'/posts/test-images': RouteRecordInfo<'/posts/test-images', '/posts/test-images', Record<never, never>, Record<never, never>>,
'/posts/test-tags': RouteRecordInfo<'/posts/test-tags', '/posts/test-tags', Record<never, never>, Record<never, never>>,
Expand Down
6 changes: 6 additions & 0 deletions demo/yun/pages/posts/redirect.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
title: 重定向
from:
- /redirect/old1
- /redirect/old2
---
15 changes: 9 additions & 6 deletions demo/yun/site.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -145,11 +145,14 @@ export default defineSiteConfig({
enable: true,
},

redirects: [
{
from: '/foo',
to: '/about',
},
],
redirects: {
useVueRouter: true,
rules: [
{
from: '/foo',
to: '/about',
},
],
},

})
98 changes: 70 additions & 28 deletions docs/pages/guide/config/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -575,56 +575,98 @@ Examples can be found in [Partial Content Encryption](/examples/partial-content-

### Client Redirects {lang="en"}

```ts
interface Redirects {
// https://router.vuejs.org/guide/essentials/redirect-and-alias.html
// Whether to use VueRouter, default is true
useVueRouter?: boolean
rules?: RedirectRule[]
}
interface RedirectRule {
// Redirect original route
from: string | string[]
// Redirect target route
to: string
}
```

::: zh-CN
这会生成额外的 HTML 页面,用与跳转到 valaxy 中已有的页面。
示例:
:::

::: en
This will generate additional HTML pages, used to jump to the valaxy's existing pages.
For example:
:::

::: tip

<div lang="zh-CN">
客户端重定向只在 SSG build 时启用
</div>
```ts
// site.config.ts
export default defineSiteConfig({
redirects: {
useVueRouter: true,
rules: [
{
from: ['/foo', '/bar'],
to: '/about',
},
{
from: '/v1/about',
to: '/about',
},
]
},
})
```

<div lang="en">
Client redirects will only be enabled in SSG build
</div>
::: zh-CN
`/foo`, `/bar`, `/v1/about` 这些路由会被重定向到 `/about`。
:::

::: en
`/foo`, `/bar`, `/v1/about` these routes will be redirected to `/about`。
:::

::: zh-CN
例如
你也可以在 Front Matter 中配置
:::

::: en
For example:
You can also set it in the Front Matter:
:::

```ts
// site.config.ts
export default defineSiteConfig({
redirects: [
{
from: ['/foo', '/bar'],
to: '/about',
},
{
from: '/v1/about',
to: '/about',
},
],
})
```md
<!-- pages/posts/redirect.md -->
---
from:
- /redirect/old1
- /redirect/old2
---
```

```md
<!-- pages/posts/redirect.md -->
---
from: /v1/redirect
---
```

::: zh-CN
`/foo`, `/bar`, `/v1/about` 这些路由会被重定向到 `/about`。
`/redirect/old1`, `/redirect/old2`, `/v1/redirect` 这些路由会被重定向到 `/posts/redirect`。
:::

::: en
`/foo`, `/bar`, `/v1/about` these routes will be redirected to `/about`。
`/redirect/old1`, `/redirect/old2`, `/v1/redirect` these routes will be redirected to `/posts/redirect`。
:::

::: tip

<div lang="zh-CN">
在 SSG 构建时,如果 useVueRouter 为 false,则会为每一个源路由生成一个 html 文件
</div>

<div lang="en">
When building SSG, if useVueRouter is false, an html file will be generated for each original route
</div>

:::

### 图片预览(Medium Zoom) {lang="zh-CN"}
Expand Down
14 changes: 10 additions & 4 deletions packages/valaxy/client/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ import 'uno.css'

import setupMain from './setup/main'

const valaxyConfig = initValaxyConfig()

/**
* register global components
* @param ctx
Expand All @@ -29,9 +31,13 @@ export function registerComponents(ctx: ViteSSGContext) {
ctx.app.component('AppLink', AppLink)
}

const { redirectRoutes, useVueRouter } = valaxyConfig.value.runtimeConfig.redirects
if (useVueRouter)
routes.push(...redirectRoutes)

// fix chinese path
routes.forEach((i) => {
i.children?.forEach((j) => {
i?.children?.forEach((j) => {
j.path = encodeURI(j.path)
})
})
Expand Down Expand Up @@ -66,10 +72,10 @@ export const createApp = ViteSSG(
(ctx) => {
// app-level provide
const { app } = ctx
const config = initValaxyConfig()
app.provide(valaxyConfigSymbol, config)

app.provide(valaxyConfigSymbol, valaxyConfig)

registerComponents(ctx)
setupMain(ctx, config)
setupMain(ctx, valaxyConfig)
},
)
6 changes: 4 additions & 2 deletions packages/valaxy/node/build.ts
Original file line number Diff line number Diff line change
Expand Up @@ -76,12 +76,14 @@ export async function postProcessForSSG(options: ResolvedValaxyOptions) {
}
}

await generateClientRedirects(options)
if (!options.config.siteConfig.redirects?.useVueRouter)
await generateClientRedirects(options)
}

export async function generateClientRedirects(options: ResolvedValaxyOptions) {
consola.info('generate client redirects...')
const outputPath = resolve(options.userRoot, 'dist')
const redirectRules = collectRedirects(options.config.siteConfig?.redirects ?? [])
const redirectRules = collectRedirects(options.redirects)

const task = redirectRules.map(async (rule) => {
const fromPath = join(outputPath, `${rule.from}.html`)
Expand Down
5 changes: 5 additions & 0 deletions packages/valaxy/node/config/site.ts
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,11 @@ export const defaultSiteConfig: SiteConfig = {
salt: webcrypto.getRandomValues(new Uint8Array(16)),
iv: webcrypto.getRandomValues(new Uint8Array(16)),
},

redirects: {
useVueRouter: true,
rules: [],
},
}

/**
Expand Down
8 changes: 7 additions & 1 deletion packages/valaxy/node/config/valaxy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,13 @@ export const defaultValaxyConfig: ValaxyNodeConfig = {
// markdown: {
// excerpt: '<!-- more -->',
// },
runtimeConfig: { addons: {} },
runtimeConfig: {
addons: {},
redirects: {
useVueRouter: true,
redirectRoutes: [],
},
},

modules: {
rss: {
Expand Down
22 changes: 20 additions & 2 deletions packages/valaxy/node/options.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import { ensureSuffix, uniq } from '@antfu/utils'
import defu from 'defu'
import { blue, cyan, magenta, yellow } from 'picocolors'
import consola from 'consola'
import type { DefaultTheme, RuntimeConfig } from 'valaxy/types'
import type { DefaultTheme, RedirectItem, RuntimeConfig } from 'valaxy/types'
import { resolveImportPath } from './utils'
import {
defaultValaxyConfig,
Expand All @@ -23,6 +23,7 @@ import { parseAddons } from './utils/addons'
import { getThemeRoot } from './utils/theme'
import { resolveSiteConfig } from './config/site'
import { countPerformanceTime } from './utils/performance'
import { collectRedirects } from './utils/clientRedirects'

// for cli entry
export interface ValaxyEntryOptions {
Expand Down Expand Up @@ -88,6 +89,10 @@ export interface ResolvedValaxyOptions<ThemeConfig = DefaultTheme.Config> {
* Record<package-name, OptionResolver>
*/
addons: ValaxyAddonResolver[]
/**
* Collect redirect rule
*/
redirects: RedirectItem[]
}

export interface ValaxyServerOptions {
Expand Down Expand Up @@ -137,6 +142,10 @@ export async function processValaxyOptions(valaxyOptions: ResolvedValaxyOptions,
...config,
runtimeConfig: {
addons: {},
redirects: {
useVueRouter: true,
redirectRoutes: [],
},
},
}
valaxyOptions.addons = addons
Expand Down Expand Up @@ -190,6 +199,8 @@ export async function resolveOptions(

const { config: themeConfig, configFile: themeConfigFile } = resolvedTheme

const redirects = collectRedirects(siteConfig.redirects?.rules)

// merge with valaxy
userValaxyConfig = defu<ValaxyNodeConfig, any>({ siteConfig }, { themeConfig }, userValaxyConfig)

Expand All @@ -213,13 +224,20 @@ export async function resolveOptions(
theme,
config: {
...userValaxyConfig,
runtimeConfig: { addons: {} },
runtimeConfig: {
addons: {},
redirects: {
useVueRouter: true,
redirectRoutes: [],
},
},
},
configFile: configFile || '',
siteConfigFile: siteConfigFile || '',
themeConfigFile: themeConfigFile || '',
pages: pages.sort(),
addons: [],
redirects,
}
debug(valaxyOptions)

Expand Down
19 changes: 18 additions & 1 deletion packages/valaxy/node/plugins/valaxy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { defu } from 'defu'
import pascalCase from 'pascalcase'
import type { DefaultTheme, PageDataPayload, Pkg, SiteConfig } from 'valaxy/types'
import { dim, yellow } from 'picocolors'
import type { RouteRecordRaw } from 'vue-router'
import { defaultSiteConfig, mergeValaxyConfig, resolveSiteConfig, resolveUserThemeConfig } from '../config'
import type { ResolvedValaxyOptions, ValaxyServerOptions } from '../options'
import { processValaxyOptions, resolveOptions, resolveThemeValaxyConfig } from '../options'
Expand All @@ -19,6 +20,22 @@ import type { ValaxyNodeConfig } from '../types'
import { checkMd } from '../markdown/check'
import { vLogger } from '../logger'
import { countPerformanceTime } from '../utils/performance'
import { isProd } from '../utils/env'

function generateConfig(options: ResolvedValaxyOptions) {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For now, redirects is defined in siteConfig, so I wonder if we can get the configuration directly from the client without adding extra runtimeConfig.

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess we can save some code?
I am not directly debugging now, so you can tell me if i have any mistakes.

Copy link
Collaborator Author

@yixiaojiu yixiaojiu Feb 2, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When compiling, we need to collect redirect rules from frontmatter, whick are not user-defined. Is it a good idea to put these in siteconfig?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since I lack experience, if you think this is better, I will modify it.

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK, you are right, some configs collected from frontmatter.

const routes = options.redirects.map<RouteRecordRaw>((redirect) => {
return {
path: redirect.from,
redirect: redirect.to,
}
})
options.config.runtimeConfig.redirects = {
useVueRouter: isProd() ? options.config.siteConfig.redirects!.useVueRouter! : true,
redirectRoutes: routes,
}

return `export default ${JSON.stringify(JSON.stringify(options.config))}`
}

/**
* for /@valaxyjs/styles
Expand Down Expand Up @@ -164,7 +181,7 @@ export function createValaxyPlugin(options: ResolvedValaxyOptions, serverOptions
load(id) {
if (id === '/@valaxyjs/config')
// stringify twice for \"
return `export default ${JSON.stringify(JSON.stringify(valaxyConfig))}`
return generateConfig(options)

if (id === '/@valaxyjs/context') {
return `export default ${JSON.stringify(JSON.stringify({
Expand Down
Loading
Loading