Skip to content

Commit

Permalink
feat: improve typescript support for config file
Browse files Browse the repository at this point in the history
  • Loading branch information
ulivz committed Dec 11, 2021
1 parent 7072a24 commit 9d5d366
Show file tree
Hide file tree
Showing 12 changed files with 240 additions and 167 deletions.
4 changes: 3 additions & 1 deletion docs/.vitepress/config.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
export default {
import { defineConfig } from '../../src/node'

export default defineConfig({
lang: 'en-US',
title: 'VitePress',
description: 'Vite & Vue powered static site generator.',
Expand Down
58 changes: 58 additions & 0 deletions docs/guide/configuration.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
# Configuration

## Overview

Without any configuration, the page is pretty minimal, and the user has no way to navigate around the site. To customize your site, let’s first create a `.vitepress` directory inside your docs directory. This is where all VitePress-specific files will be placed. Your project structure is probably like this:

```bash
Expand All @@ -21,3 +23,59 @@ module.exports = {
```

Check out the [Config Reference](/config/basics) for a full list of options.


## Config Intellisense

Since VitePress ships with TypeScript typings, you can leverage your IDE's intellisense with jsdoc type hints:

```js
/**
* @type {import('vitepress').UserConfig}
*/
const config = {
// ...
}

export default config
```

Alternatively, you can use the `defineConfig` helper at which should provide intellisense without the need for jsdoc annotations:

```js
import { defineConfig } from 'vitepress'

export default defineConfig({
// ...
})
```

VitePress also directly supports TS config files. You can use `.vitepress/config.ts` with the `defineConfig` helper as well.


## Typed Theme Config

By default, `defineConfig` helper leverages the theme config type from default theme:

```js
import { defineConfig } from 'vitepress'

export default defineConfig({
themeConfig: {
// Type is `DefaultTheme.Config`
}
})
```

If you use a custom theme, you'll be able to pass the generics type for your custom theme, and you need overload it with the second parameter of `defineConfig` helper:

```js
import { defineConfig } from 'vitepress'
import { ThemeConfig } from 'your-theme'

export default defineConfig<ThemeConfig>({
themeConfig: {
// Type is `ThemeConfig`
}
}, true); // declare `usingCustomTheme` and discard usage of the default theme.
```
147 changes: 1 addition & 146 deletions src/client/theme-default/config.ts
Original file line number Diff line number Diff line change
@@ -1,146 +1 @@
export namespace DefaultTheme {
export interface Config {
logo?: string
nav?: NavItem[] | false
sidebar?: SideBarConfig | MultiSideBarConfig

/**
* GitHub repository following the format <user>/<project>.
*
* @example `"vuejs/vue-next"`
*/
repo?: string

/**
* Customize the header label. Defaults to GitHub/Gitlab/Bitbucket
* depending on the provided repo.
*
* @example `"Contribute!"`
*/
repoLabel?: string

/**
* If your docs are in a different repository from your main project.
*
* @example `"vuejs/docs-next"`
*/
docsRepo?: string

/**
* If your docs are not at the root of the repo.
*
* @example `"docs"`
*/
docsDir?: string

/**
* If your docs are in a different branch. Defaults to `master`.
*
* @example `"next"`
*/
docsBranch?: string

/**
* Enable links to edit pages at the bottom of the page.
*/
editLinks?: boolean

/**
* Custom text for edit link. Defaults to "Edit this page".
*/
editLinkText?: string

/**
* Show last updated time at the bottom of the page. Defaults to `false`.
* If given a string, it will be displayed as a prefix (default value:
* "Last Updated").
*/
lastUpdated?: string | boolean

prevLinks?: boolean
nextLinks?: boolean

locales?: Record<string, LocaleConfig & Omit<Config, 'locales'>>

algolia?: AlgoliaSearchOptions

carbonAds?: {
carbon: string
custom?: string
placement: string
}
}

// navbar --------------------------------------------------------------------

export type NavItem = NavItemWithLink | NavItemWithChildren

export interface NavItemBase {
text: string
target?: string
rel?: string
ariaLabel?: string
activeMatch?: string
}

export interface NavItemWithLink extends NavItemBase {
link: string
}

export interface NavItemWithChildren extends NavItemBase {
items: NavItemWithLink[]
}

// sidebar -------------------------------------------------------------------

export type SideBarConfig = SideBarItem[] | 'auto' | false

export interface MultiSideBarConfig {
[path: string]: SideBarConfig
}

export type SideBarItem = SideBarLink | SideBarGroup

export interface SideBarLink {
text: string
link: string
}

export interface SideBarGroup {
text: string
link?: string

/**
* @default false
*/
collapsable?: boolean

children: SideBarItem[]
}

// algolia ------------------------------------------------------------------
// partially copied from @docsearch/react/dist/esm/DocSearch.d.ts
export interface AlgoliaSearchOptions {
appId?: string
apiKey: string
indexName: string
placeholder?: string
searchParameters?: any
disableUserPersonalization?: boolean
initialQuery?: string
}

// locales -------------------------------------------------------------------

export interface LocaleConfig {
/**
* Text for the language dropdown.
*/
selectText?: string

/**
* Label for this locale in the language dropdown.
*/
label?: string
}
}
export { DefaultTheme } from '../shared'
1 change: 1 addition & 0 deletions src/client/theme-default/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { Theme } from 'vitepress'
import Layout from './Layout.vue'
import NotFound from './NotFound.vue'

export { DefaultTheme } from './config'
const theme: Theme = {
Layout,
NotFound
Expand Down
2 changes: 1 addition & 1 deletion src/client/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,5 +12,5 @@
"vitepress": ["index.ts"]
}
},
"include": [".", "../../types/shared.d.ts"]
"include": ["."]
}
34 changes: 21 additions & 13 deletions src/node/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@ import {
SiteData,
HeadConfig,
LocaleConfig,
createLangDictionary
createLangDictionary,
DefaultTheme,
} from './shared'
import { resolveAliases, APP_PATH, DEFAULT_THEME_PATH } from './alias'
import { MarkdownOptions } from './markdown/markdown'
Expand All @@ -26,14 +27,16 @@ const debug = _debug('vitepress:config')

export type { MarkdownOptions }

export interface UserConfig<ThemeConfig = any> {
extends?: RawConfigExports
export type ThemeConfig = any;

export interface UserConfig<T extends ThemeConfig = ThemeConfig> {
extends?: RawConfigExports<T>
lang?: string
base?: string
title?: string
description?: string
head?: HeadConfig[]
themeConfig?: ThemeConfig
themeConfig?: T
locales?: Record<string, LocaleConfig>
markdown?: MarkdownOptions
/**
Expand All @@ -55,15 +58,15 @@ export interface UserConfig<ThemeConfig = any> {
mpa?: boolean
}

export type RawConfigExports =
| UserConfig
| Promise<UserConfig>
| (() => UserConfig | Promise<UserConfig>)
export type RawConfigExports<T extends ThemeConfig = ThemeConfig> =
| UserConfig<T>
| Promise<UserConfig<T>>
| (() => UserConfig<T> | Promise<UserConfig<T>>)

export interface SiteConfig<ThemeConfig = any> {
export interface SiteConfig<T = ThemeConfig> {
root: string
srcDir: string
site: SiteData<ThemeConfig>
site: SiteData<T>
configPath: string | undefined
themeDir: string
outDir: string
Expand All @@ -82,7 +85,12 @@ const resolve = (root: string, file: string) =>
/**
* Type config helper
*/
export function defineConfig(config: RawConfigExports) {
export function defineConfig<T extends ThemeConfig = ThemeConfig>(
config: UserConfig<T>,
usingCustomTheme: true
): void
export function defineConfig(config: UserConfig<DefaultTheme.Config>): void
export function defineConfig(config: ThemeConfig) {
return config
}

Expand Down Expand Up @@ -150,7 +158,7 @@ async function resolveUserConfig(
}
}

const userConfig: RawConfigExports = configPath
const userConfig: RawConfigExports<ThemeConfig> = configPath
? ((
await loadConfigFromFile(
{
Expand All @@ -173,7 +181,7 @@ async function resolveUserConfig(
}

async function resolveConfigExtends(
config: RawConfigExports
config: RawConfigExports<ThemeConfig>
): Promise<UserConfig> {
const resolved = await (typeof config === 'function' ? config() : config)
if (resolved.extends) {
Expand Down
2 changes: 1 addition & 1 deletion src/node/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,4 @@ export * from './serve/serve'
export * from './config'
export * from './markdown/markdown'

export type { SiteData, HeadConfig, LocaleConfig } from '../../types/shared'
export type { SiteData, HeadConfig, LocaleConfig, DefaultTheme } from '../../types/shared'
3 changes: 2 additions & 1 deletion src/shared/shared.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@ export type {
PageData,
HeadConfig,
LocaleConfig,
Header
Header,
DefaultTheme,
} from '../../types/shared'

export const EXTERNAL_URL_RE = /^https?:/i
Expand Down
2 changes: 1 addition & 1 deletion src/shared/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,5 @@
"compilerOptions": {
"baseUrl": "."
},
"include": [".", "../../types/shared.d.ts"]
"include": ["."]
}
Loading

0 comments on commit 9d5d366

Please sign in to comment.