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

Wip: Additional theme files #3478

Draft
wants to merge 4 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
25 changes: 22 additions & 3 deletions __tests__/e2e/.vitepress/config.ts
Expand Up @@ -84,10 +84,29 @@ const sidebar: DefaultTheme.Config['sidebar'] = {
}

export default defineConfig({
title: 'Example',
description: 'An example app using VitePress.',
vite: {
plugins: [
{
name: 'example',
configResolved(config) {
console.dir(config, { depth: 10 })
}
}
]
},
extends: [
{
title: 'Example',
description: 'An example app using VitePress.',
additionalThemeFiles: ['./my-additional-theme-file.ts']
},
{
themeConfig: {
sidebar
}
}
],
themeConfig: {
sidebar,
search: {
provider: 'local',
options: {
Expand Down
7 changes: 7 additions & 0 deletions __tests__/e2e/.vitepress/my-additional-theme-file.ts
@@ -0,0 +1,7 @@
import type { Theme } from 'vitepress'

export default {
enhanceApp({ app }) {
console.log('enhanceApp from my-additional-theme-file.ts')
}
} satisfies Theme
31 changes: 21 additions & 10 deletions src/client/app/index.ts
@@ -1,4 +1,5 @@
import RawTheme from '@theme/index'
import SiteConfigThemes from '@site-config-themes'
import {
createApp as createClientApp,
createSSRApp,
Expand All @@ -17,23 +18,33 @@ import { usePrefetch } from './composables/preFetch'
import { dataSymbol, initData, siteDataRef, useData } from './data'
import { RouterSymbol, createRouter, scrollTo, type Router } from './router'
import { inBrowser, pathToFile } from './utils'
import type { Theme } from './theme'

function resolveThemeExtends(theme: typeof RawTheme): typeof RawTheme {
if (theme.extends) {
const base = resolveThemeExtends(theme.extends)
return {
...base,
...theme,
async enhanceApp(ctx) {
if (base.enhanceApp) await base.enhanceApp(ctx)
if (theme.enhanceApp) await theme.enhanceApp(ctx)
}
}
const extendsList = [theme.extends].flat()
const manyBases = extendsList.map((theme) => resolveThemeExtends(theme))
// or reduceRight() depending on which side gets priority
const singleBase = manyBases.reduce((base, theme) =>
mergeTheme(base, theme)
)
return mergeTheme(singleBase, theme)
}
return theme
}

const Theme = resolveThemeExtends(RawTheme)
export function mergeTheme(base: Theme, theme: Theme): Theme {
return {
...base,
...theme,
async enhanceApp(ctx) {
if (base.enhanceApp) await base.enhanceApp(ctx)
if (theme.enhanceApp) await theme.enhanceApp(ctx)
}
}
}

const Theme = resolveThemeExtends({ extends: [RawTheme, ...SiteConfigThemes] })

const VitePressApp = defineComponent({
name: 'VitePressApp',
Expand Down
2 changes: 1 addition & 1 deletion src/client/app/theme.ts
Expand Up @@ -11,7 +11,7 @@ export interface EnhanceAppContext {
export interface Theme {
Layout?: Component
enhanceApp?: (ctx: EnhanceAppContext) => Awaitable<void>
extends?: Theme
extends?: Theme | Theme[]

/**
* @deprecated can be replaced by wrapping layout component
Expand Down
6 changes: 6 additions & 0 deletions src/client/shim.d.ts
Expand Up @@ -23,6 +23,12 @@ declare module '@theme/index' {
export default theme
}

declare module '@site-config-themes' {
import type { Theme } from 'vitepress'
const themes: Theme[]
export default themes
}

declare module '@localSearchIndex' {
const data: Record<string, () => Promise<{ default: string }>>
export default data
Expand Down
15 changes: 14 additions & 1 deletion src/node/alias.ts
Expand Up @@ -3,6 +3,7 @@ import { resolve, join } from 'path'
import { fileURLToPath } from 'url'
import type { Alias, AliasOptions } from 'vite'
import type { SiteConfig } from './config'
import fs from 'fs-extra'

const require = createRequire(import.meta.url)
const PKG_ROOT = resolve(fileURLToPath(import.meta.url), '../..')
Expand All @@ -21,11 +22,23 @@ export const SITE_DATA_REQUEST_PATH = '/' + SITE_DATA_ID
const vueRuntimePath = 'vue/dist/vue.runtime.esm-bundler.js'

export function resolveAliases(
{ root, themeDir }: SiteConfig,
siteConfig: SiteConfig,
ssr: boolean
): AliasOptions {
const { root, themeDir } = siteConfig
const siteConfigThemesJS = `\
${siteConfig.additionalThemeFiles
.map((f, i) => `import $${i} from ${JSON.stringify(f)}`)
.join('\n')}
export default [${siteConfig.additionalThemeFiles
.map((f, i) => `$${i}`)
.join(', ')}]`
const tmpfile = join(siteConfig.cacheDir, 'site-config-themes.ts')
fs.writeFileSync(tmpfile, siteConfigThemesJS)

const paths: Record<string, string> = {
'@theme': themeDir,
'@site-config-themes': tmpfile,
[SITE_DATA_ID]: SITE_DATA_REQUEST_PATH
}

Expand Down
39 changes: 37 additions & 2 deletions src/node/config.ts
Expand Up @@ -113,6 +113,8 @@ export async function resolveConfig(
assetsDir,
site,
themeDir,
additionalThemeFiles:
userConfig.additionalThemeFiles?.map((f) => resolve(root, f)) ?? [],
pages,
dynamicRoutes,
configPath,
Expand Down Expand Up @@ -193,8 +195,13 @@ async function resolveConfigExtends(
): Promise<UserConfig> {
const resolved = await (typeof config === 'function' ? config() : config)
if (resolved.extends) {
const base = await resolveConfigExtends(resolved.extends)
return mergeConfig(base, resolved)
const extendsRaw = [resolved.extends].flat()
const manyBases = await Promise.all(
extendsRaw.map((config) => resolveConfigExtends(config))
)
// or reduceRight() depending on which side gets priority
const singleBase = manyBases.reduce((prev, curr) => mergeConfig(prev, curr))
return mergeConfig(singleBase, resolved)
}
return resolved
}
Expand Down Expand Up @@ -293,3 +300,31 @@ function resolveSiteDataHead(userConfig?: UserConfig): HeadConfig[] {

return head
}

// export function addThemeWrapper(
// config: ResolvedConfig,
// themeWrapperFile: fs.PathLike,
// find: string
// ) {
// const themeWrapperPath =
// themeWrapperFile instanceof URL
// ? url.fileURLToPath(themeWrapperFile)
// : themeWrapperFile.toString()

// let themeIndexAlias = config.resolve.alias.find(
// (x) => x.find === '@theme/index'
// )
// if (!themeIndexAlias) {
// const themeAlias = config.resolve.alias.find((x) => x.find === '@theme')!
// themeIndexAlias = {
// find: '@theme/index',
// replacement: path.join(themeAlias.replacement, 'index')
// }
// config.resolve.alias.unshift(themeIndexAlias)
// }
// config.resolve.alias.push({
// find: find,
// replacement: themeIndexAlias.replacement
// })
// themeIndexAlias.replacement = themeWrapperPath
// }
4 changes: 3 additions & 1 deletion src/node/siteConfig.ts
Expand Up @@ -56,14 +56,15 @@ export interface TransformPageContext {

export interface UserConfig<ThemeConfig = any>
extends LocaleSpecificConfig<ThemeConfig> {
extends?: RawConfigExports<ThemeConfig>
extends?: RawConfigExports<ThemeConfig> | RawConfigExports<ThemeConfig>[]

base?: string
srcDir?: string
srcExclude?: string[]
outDir?: string
assetsDir?: string
cacheDir?: string
additionalThemeFiles?: string[]

shouldPreload?: (link: string, page: string) => boolean

Expand Down Expand Up @@ -225,6 +226,7 @@ export interface SiteConfig<ThemeConfig = any>
configPath: string | undefined
configDeps: string[]
themeDir: string
additionalThemeFiles: string[]
outDir: string
assetsDir: string
cacheDir: string
Expand Down