Merge branch 'main' into feat/user-configurable-outdir

pull/448/head
Evan You 4 years ago committed by GitHub
commit 29492472a9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -1,3 +1,9 @@
## [0.20.10](https://github.com/vuejs/vitepress/compare/v0.20.9...v0.20.10) (2021-12-25)
### Features
- minify head inline scripts ([e61db62](https://github.com/vuejs/vitepress/commit/e61db62a1c49cb5f368a152221bfa60737dbbc6a))
## [0.20.9](https://github.com/vuejs/vitepress/compare/v0.20.8...v0.20.9) (2021-12-15) ## [0.20.9](https://github.com/vuejs/vitepress/compare/v0.20.8...v0.20.9) (2021-12-15)
### Features ### Features

@ -1,8 +1,18 @@
export default { import { defineConfig } from '../../src/node'
export default defineConfig({
lang: 'en-US', lang: 'en-US',
title: 'VitePress', title: 'VitePress',
description: 'Vite & Vue powered static site generator.', description: 'Vite & Vue powered static site generator.',
head: [
[
'script',
{},
'(() => { const afsefe = window.foo;\n console.log(afsefe);})()'
]
],
themeConfig: { themeConfig: {
repo: 'vuejs/vitepress', repo: 'vuejs/vitepress',
docsDir: 'docs', docsDir: 'docs',
@ -42,7 +52,7 @@ export default {
'/': getGuideSidebar() '/': getGuideSidebar()
} }
} }
} })
function getGuideSidebar() { function getGuideSidebar() {
return [ return [

@ -1,5 +1,7 @@
# Configuration # 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, lets 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: Without any configuration, the page is pretty minimal, and the user has no way to navigate around the site. To customize your site, lets 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 ```bash
@ -21,3 +23,57 @@ module.exports = {
``` ```
Check out the [Config Reference](/config/basics) for a full list of options. 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:
```ts
import { defineConfig } from 'vitepress'
export default defineConfig({
themeConfig: {
// Type is `DefaultTheme.Config`
}
})
```
If you use a custom theme and want type checks for the theme config, you'll need to use `defineConfigWithTheme` instead, and pass the config type for your custom theme via a generic argument:
```ts
import { defineConfigWithTheme } from 'vitepress'
import { ThemeConfig } from 'your-theme'
export default defineConfigWithTheme<ThemeConfig>({
themeConfig: {
// Type is `ThemeConfig`
}
})
```

@ -1,6 +1,6 @@
{ {
"name": "vitepress", "name": "vitepress",
"version": "0.20.9", "version": "0.20.10",
"description": "Vite & Vue powered static site generator", "description": "Vite & Vue powered static site generator",
"main": "dist/node/index.js", "main": "dist/node/index.js",
"typings": "types/index.d.ts", "typings": "types/index.d.ts",

@ -25,8 +25,8 @@ const getDefaultRoute = (): Route => ({
component: null, component: null,
// this will be set upon initial page load, which is before // this will be set upon initial page load, which is before
// the app is mounted, so it's guaranteed to be available in // the app is mounted, so it's guaranteed to be available in
// components // components. We just need enough data for 404 pages to render.
data: null as any data: { frontmatter: {} } as any
}) })
interface PageModule { interface PageModule {

@ -24,6 +24,9 @@ const { site, theme, localePath } = useData()
font-size: 1.3rem; font-size: 1.3rem;
font-weight: 600; font-weight: 600;
color: var(--c-text); color: var(--c-text);
display: flex;
justify-content: center;
align-items: center;
} }
.nav-bar-title:hover { .nav-bar-title:hover {

@ -1,146 +1 @@
export namespace DefaultTheme { export { DefaultTheme } from '../shared'
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
}
}

@ -8,6 +8,7 @@ import { Theme } from 'vitepress'
import Layout from './Layout.vue' import Layout from './Layout.vue'
import NotFound from './NotFound.vue' import NotFound from './NotFound.vue'
export { DefaultTheme } from './config'
const theme: Theme = { const theme: Theme = {
Layout, Layout,
NotFound NotFound

@ -12,5 +12,5 @@
"vitepress": ["index.ts"] "vitepress": ["index.ts"]
} }
}, },
"include": [".", "../../types/shared.d.ts"] "include": ["."]
} }

@ -2,7 +2,7 @@ import path from 'path'
import fs from 'fs-extra' import fs from 'fs-extra'
import { SiteConfig, resolveSiteDataByRoute } from '../config' import { SiteConfig, resolveSiteDataByRoute } from '../config'
import { HeadConfig } from '../shared' import { HeadConfig } from '../shared'
import { normalizePath } from 'vite' import { normalizePath, transformWithEsbuild } from 'vite'
import { RollupOutput, OutputChunk, OutputAsset } from 'rollup' import { RollupOutput, OutputChunk, OutputAsset } from 'rollup'
import { slash } from '../utils/slash' import { slash } from '../utils/slash'
import escape from 'escape-html' import escape from 'escape-html'
@ -121,7 +121,7 @@ export async function renderPage(
${stylesheetLink} ${stylesheetLink}
${preloadLinksString} ${preloadLinksString}
${prefetchLinkString} ${prefetchLinkString}
${renderHead(head)} ${await renderHead(head)}
</head> </head>
<body> <body>
<div id="app">${content}</div> <div id="app">${content}</div>
@ -165,17 +165,24 @@ function resolvePageImports(
] ]
} }
function renderHead(head: HeadConfig[]) { function renderHead(head: HeadConfig[]): Promise<string> {
return head return Promise.all(
.map(([tag, attrs = {}, innerHTML = '']) => { head.map(async ([tag, attrs = {}, innerHTML = '']) => {
const openTag = `<${tag}${renderAttrs(attrs)}>` const openTag = `<${tag}${renderAttrs(attrs)}>`
if (tag !== 'link' && tag !== 'meta') { if (tag !== 'link' && tag !== 'meta') {
if (tag === 'script') {
innerHTML = (
await transformWithEsbuild(innerHTML, 'inline-script.js', {
minify: true
})
).code.trim()
}
return `${openTag}${innerHTML}</${tag}>` return `${openTag}${innerHTML}</${tag}>`
} else { } else {
return openTag return openTag
} }
}) })
.join('\n ') ).then((tags) => tags.join('\n '))
} }
function renderAttrs(attrs: Record<string, string>): string { function renderAttrs(attrs: Record<string, string>): string {

@ -14,9 +14,10 @@ import {
SiteData, SiteData,
HeadConfig, HeadConfig,
LocaleConfig, LocaleConfig,
createLangDictionary createLangDictionary,
DefaultTheme
} from './shared' } from './shared'
import { resolveAliases, APP_PATH, DEFAULT_THEME_PATH } from './alias' import { resolveAliases, DEFAULT_THEME_PATH } from './alias'
import { MarkdownOptions } from './markdown/markdown' import { MarkdownOptions } from './markdown/markdown'
import _debug from 'debug' import _debug from 'debug'
@ -27,7 +28,7 @@ const debug = _debug('vitepress:config')
export type { MarkdownOptions } export type { MarkdownOptions }
export interface UserConfig<ThemeConfig = any> { export interface UserConfig<ThemeConfig = any> {
extends?: RawConfigExports extends?: RawConfigExports<ThemeConfig>
lang?: string lang?: string
base?: string base?: string
title?: string title?: string
@ -57,10 +58,10 @@ export interface UserConfig<ThemeConfig = any> {
mpa?: boolean mpa?: boolean
} }
export type RawConfigExports = export type RawConfigExports<ThemeConfig = any> =
| UserConfig | UserConfig<ThemeConfig>
| Promise<UserConfig> | Promise<UserConfig<ThemeConfig>>
| (() => UserConfig | Promise<UserConfig>) | (() => UserConfig<ThemeConfig> | Promise<UserConfig<ThemeConfig>>)
export interface SiteConfig<ThemeConfig = any> export interface SiteConfig<ThemeConfig = any>
extends Pick< extends Pick<
@ -84,7 +85,16 @@ const resolve = (root: string, file: string) =>
/** /**
* Type config helper * Type config helper
*/ */
export function defineConfig(config: RawConfigExports) { export function defineConfig(config: UserConfig<DefaultTheme.Config>) {
return config
}
/**
* Type config helper for custom theme config
*/
export function defineConfigWithTheme<ThemeConfig>(
config: UserConfig<ThemeConfig>
) {
return config return config
} }
@ -125,7 +135,7 @@ export async function resolveConfig(
pages, pages,
configPath, configPath,
outDir, outDir,
tempDir: path.resolve(APP_PATH, 'temp'), tempDir: resolve(root, '.tmp'),
markdown: userConfig.markdown, markdown: userConfig.markdown,
alias: resolveAliases(themeDir), alias: resolveAliases(themeDir),
vue: userConfig.vue, vue: userConfig.vue,
@ -137,7 +147,7 @@ export async function resolveConfig(
return config return config
} }
const supportedConfigExtensions = ['js', 'ts', '.mjs', 'mts'] const supportedConfigExtensions = ['js', 'ts', 'mjs', 'mts']
async function resolveUserConfig( async function resolveUserConfig(
root: string, root: string,

@ -4,4 +4,4 @@ export * from './serve/serve'
export * from './config' export * from './config'
export * from './markdown/markdown' export * from './markdown/markdown'
export type { SiteData, HeadConfig, LocaleConfig } from '../../types/shared' export type { SiteData, HeadConfig, LocaleConfig, DefaultTheme } from '../../types/shared'

@ -89,10 +89,12 @@ export function createMarkdownToVueRenderFn(
for (let url of data.links) { for (let url of data.links) {
url = url.replace(/[?#].*$/, '').replace(/\.(html|md)$/, '') url = url.replace(/[?#].*$/, '').replace(/\.(html|md)$/, '')
if (url.endsWith('/')) url += `index` if (url.endsWith('/')) url += `index`
const resolved = slash( const resolved = decodeURIComponent(
url.startsWith('/') slash(
? url.slice(1) url.startsWith('/')
: path.relative(srcDir, path.resolve(dir, url)) ? url.slice(1)
: path.relative(srcDir, path.resolve(dir, url))
)
) )
if ( if (
!pages.includes(resolved) && !pages.includes(resolved) &&

@ -5,7 +5,8 @@ export type {
PageData, PageData,
HeadConfig, HeadConfig,
LocaleConfig, LocaleConfig,
Header Header,
DefaultTheme,
} from '../../types/shared' } from '../../types/shared'
export const EXTERNAL_URL_RE = /^https?:/i export const EXTERNAL_URL_RE = /^https?:/i

@ -3,5 +3,5 @@
"compilerOptions": { "compilerOptions": {
"baseUrl": "." "baseUrl": "."
}, },
"include": [".", "../../types/shared.d.ts"] "include": ["."]
} }

@ -0,0 +1,146 @@
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
}
}

2
types/index.d.ts vendored

@ -1,4 +1,4 @@
export * from './shared' export * from './shared'
export * from './default-theme'
export * from '../dist/node/index' export * from '../dist/node/index'
export * from '../dist/client/index' export * from '../dist/client/index'
export * from '../dist/client/theme-default/config'

2
types/shared.d.ts vendored

@ -1,5 +1,7 @@
// types shared between server and client // types shared between server and client
export { DefaultTheme } from './default-theme'
export interface LocaleConfig { export interface LocaleConfig {
lang: string lang: string
title?: string title?: string

Loading…
Cancel
Save