Merge branch 'chore/vite-3' into clean-urls-for-alpha

pull/869/head
Georges Gomes 3 years ago committed by GitHub
commit f3727d7cc2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -48,7 +48,7 @@ The easiest way to start testing out VitePress is to tweak the VitePress docs. Y
$ pnpm run docs $ pnpm run docs
``` ```
After executing the above command, visit http://localhost:3000 and try modifying the source code. You'll get live update. After executing the above command, visit http://localhost:5173 and try modifying the source code. You'll get live update.
If you don't need docs site up and running, you may start VitePress local dev environment with `pnpm run dev`. If you don't need docs site up and running, you may start VitePress local dev environment with `pnpm run dev`.

@ -1,17 +1,18 @@
name: Release
on: on:
push: push:
tags: tags:
- 'v*' # Push events to matching v*, i.e. v1.0, v20.15.10 - 'v*' # Push events to matching v*, i.e. v1.0, v20.15.10
name: Create Release
jobs: jobs:
build: release:
name: Create Release
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Checkout code - name: Checkout
uses: actions/checkout@master uses: actions/checkout@v3
- name: Create Release for Tag - name: Create Release for Tag
id: release_tag id: release_tag
uses: yyx990803/release-tag@master uses: yyx990803/release-tag@master

@ -5,17 +5,17 @@ on: [push]
jobs: jobs:
test: test:
runs-on: ubuntu-latest runs-on: ubuntu-latest
strategy: strategy:
matrix: matrix:
node-version: [14, 16] node-version: [14, 16, 18]
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v3 uses: actions/checkout@v3
- name: Install pnpm - name: Install pnpm
uses: pnpm/action-setup@v2.0.1 uses: pnpm/action-setup@v2
with:
version: 7.0.1
- name: Set node version to ${{ matrix.node_version }} - name: Set node version to ${{ matrix.node_version }}
uses: actions/setup-node@v3 uses: actions/setup-node@v3

2
.gitignore vendored

@ -10,3 +10,5 @@ dist
node_modules node_modules
pnpm-global pnpm-global
TODOs.md TODOs.md
.temp
*.tgz

@ -1,5 +1,3 @@
/docs
/examples
*.css *.css
*.md *.md
*.vue *.vue

@ -59,9 +59,9 @@ function nav() {
{ {
text: 'Contributing', text: 'Contributing',
link: 'https://github.com/vuejs/vitepress/blob/main/.github/contributing.md' link: 'https://github.com/vuejs/vitepress/blob/main/.github/contributing.md'
}, }
], ]
}, }
] ]
} }

@ -32,7 +32,7 @@ $ yarn docs:build
$ yarn docs:serve $ yarn docs:serve
``` ```
The `serve` command will boot up local static web server that serves the files from `.vitepress/dist` at `http://localhost:5000`. It's an easy way to check if the production build looks OK in your local environment. The `serve` command will boot up local static web server that serves the files from `.vitepress/dist` at `http://localhost:4173`. It's an easy way to check if the production build looks OK in your local environment.
You may configure the port of the server by passing `--port` flag as an argument. You may configure the port of the server by passing `--port` flag as an argument.

@ -31,26 +31,13 @@ $ yarn add --dev vitepress vue
::: details Getting missing peer deps warnings? ::: details Getting missing peer deps warnings?
`@docsearch/js` has certain issues with its peer dependencies. If you see some commands failing due to them, you can try this workaround for now: `@docsearch/js` has certain issues with its peer dependencies. If you see some commands failing due to them, you can try this workaround for now:
On Yarn v2/v3, add this inside your rc file (`.yarnrc.yml` by default): If using PNPM, add this in your `package.json`:
```yaml
packageExtensions:
'@docsearch/react@*':
peerDependenciesMeta:
'@types/react':
optional: true
'react':
optional: true
'react-dom':
optional: true
```
On PNPM, add this in your `package.json`:
```json ```json
"pnpm": { "pnpm": {
"peerDependencyRules": { "peerDependencyRules": {
"ignoreMissing": [ "ignoreMissing": [
"@algolia/client-search",
"@types/react", "@types/react",
"react", "react",
"react-dom" "react-dom"
@ -89,7 +76,7 @@ Serve the documentation site in the local server.
$ yarn docs:dev $ yarn docs:dev
``` ```
VitePress will start a hot-reloading development server at `http://localhost:3000`. VitePress will start a hot-reloading development server at `http://localhost:5173`.
## Step. 4: Add more pages ## Step. 4: Add more pages
@ -103,7 +90,7 @@ Let's add another page to the site. Create a file name `getting-started.md` alon
└─ package.json └─ package.json
``` ```
Then, try to access `http://localhost:3000/getting-started` and you should see the content of `getting-started` is shown. Then, try to access `http://localhost:5173/getting-started.html` and you should see the content of `getting-started` is shown.
This is how VitePress works basically. The directory structure corresponds with the URL path. You add files, and just try to access it. This is how VitePress works basically. The directory structure corresponds with the URL path. You add files, and just try to access it.

@ -38,6 +38,7 @@ interface Theme {
Layout: Component // Vue 3 component Layout: Component // Vue 3 component
NotFound?: Component NotFound?: Component
enhanceApp?: (ctx: EnhanceAppContext) => void enhanceApp?: (ctx: EnhanceAppContext) => void
setup?: () => void
} }
interface EnhanceAppContext { interface EnhanceAppContext {
@ -65,6 +66,11 @@ export default {
// router is VitePress' custom router. `siteData` is // router is VitePress' custom router. `siteData` is
// a `ref` of current site-level metadata. // a `ref` of current site-level metadata.
} }
setup() {
// this function will be executed inside VitePressApp's
// setup hook. all composition APIs are available here.
}
} }
``` ```

@ -3,7 +3,7 @@
"version": "1.0.0-alpha.4", "version": "1.0.0-alpha.4",
"description": "Vite & Vue powered static site generator", "description": "Vite & Vue powered static site generator",
"type": "module", "type": "module",
"packageManager": "pnpm@7.1.7", "packageManager": "pnpm@7.5.0",
"main": "dist/node/index.js", "main": "dist/node/index.js",
"types": "types/index.d.ts", "types": "types/index.d.ts",
"exports": { "exports": {
@ -51,7 +51,7 @@
"dev-watch": "node scripts/watchAndCopy", "dev-watch": "node scripts/watchAndCopy",
"build": "run-s build-prepare build-client build-node", "build": "run-s build-prepare build-client build-node",
"build-prepare": "rimraf dist && node scripts/copyShared", "build-prepare": "rimraf dist && node scripts/copyShared",
"build-client": "tsc -p src/client && node scripts/copyClient", "build-client": "vue-tsc --noEmit -p src/client && tsc -p src/client && node scripts/copyClient",
"build-node": "rollup --config rollup.config.ts --configPlugin esbuild", "build-node": "rollup --config rollup.config.ts --configPlugin esbuild",
"format": "prettier --check --write .", "format": "prettier --check --write .",
"format-fail": "prettier --check .", "format-fail": "prettier --check .",
@ -71,75 +71,75 @@
"ci-docs": "run-s docs-build" "ci-docs": "run-s docs-build"
}, },
"dependencies": { "dependencies": {
"@docsearch/css": "^3.0.0", "@docsearch/css": "^3.1.1",
"@docsearch/js": "^3.0.0", "@docsearch/js": "^3.1.1",
"@vitejs/plugin-vue": "^2.3.2", "@vitejs/plugin-vue": "^3.0.0-beta.0",
"@vue/devtools-api": "^6.1.4", "@vue/devtools-api": "^6.2.0",
"@vueuse/core": "^8.5.0", "@vueuse/core": "^8.7.5",
"body-scroll-lock": "^4.0.0-beta.0", "body-scroll-lock": "^4.0.0-beta.0",
"shiki": "^0.10.1", "shiki": "^0.10.1",
"vite": "^2.9.7", "vite": "^3.0.0-beta.0",
"vue": "^3.2.33" "vue": "^3.2.37"
}, },
"devDependencies": { "devDependencies": {
"@rollup/plugin-alias": "^3.1.5", "@rollup/plugin-alias": "^3.1.9",
"@rollup/plugin-commonjs": "^20.0.0", "@rollup/plugin-commonjs": "^22.0.1",
"@rollup/plugin-json": "^4.1.0", "@rollup/plugin-json": "^4.1.0",
"@rollup/plugin-node-resolve": "^13.0.4", "@rollup/plugin-node-resolve": "^13.3.0",
"@rollup/plugin-replace": "^4.0.0", "@rollup/plugin-replace": "^4.0.0",
"@types/body-scroll-lock": "^3.1.0", "@types/body-scroll-lock": "^3.1.0",
"@types/compression": "^1.7.0", "@types/compression": "^1.7.2",
"@types/cross-spawn": "^6.0.2", "@types/cross-spawn": "^6.0.2",
"@types/debug": "^4.1.7", "@types/debug": "^4.1.7",
"@types/fs-extra": "^9.0.11", "@types/fs-extra": "^9.0.13",
"@types/koa": "^2.13.1", "@types/koa": "^2.13.4",
"@types/koa-static": "^4.0.1", "@types/koa-static": "^4.0.2",
"@types/lru-cache": "^5.1.0", "@types/markdown-it": "^12.2.3",
"@types/markdown-it": "^12.0.1",
"@types/micromatch": "^4.0.2", "@types/micromatch": "^4.0.2",
"@types/minimist": "^1.2.2", "@types/minimist": "^1.2.2",
"@types/node": "^15.6.1", "@types/node": "^18.0.0",
"@types/polka": "^0.5.3", "@types/polka": "^0.5.4",
"@types/prompts": "^2.0.14", "@types/prompts": "^2.0.14",
"chokidar": "^3.5.1", "chokidar": "^3.5.3",
"compression": "^1.7.4", "compression": "^1.7.4",
"conventional-changelog-cli": "^2.1.1", "conventional-changelog-cli": "^2.2.2",
"cross-spawn": "^7.0.3", "cross-spawn": "^7.0.3",
"debug": "^4.3.2", "debug": "^4.3.4",
"diacritics": "^1.3.0", "diacritics": "^1.3.0",
"enquirer": "^2.3.6", "enquirer": "^2.3.6",
"esbuild": "^0.14.0", "esbuild": "^0.14.48",
"escape-html": "^1.0.3", "escape-html": "^1.0.3",
"execa": "^6.1.0", "execa": "^6.1.0",
"fast-glob": "^3.2.7", "fast-glob": "^3.2.11",
"fs-extra": "^10.0.0", "fs-extra": "^10.1.0",
"gray-matter": "^4.0.3", "gray-matter": "^4.0.3",
"lint-staged": "^11.0.0", "lint-staged": "^13.0.3",
"lru-cache": "^6.0.0", "lru-cache": "^7.12.0",
"markdown-it": "^12.3.2", "markdown-it": "^13.0.1",
"markdown-it-anchor": "^8.4.1", "markdown-it-anchor": "^8.6.4",
"markdown-it-attrs": "^4.1.3", "markdown-it-attrs": "^4.1.4",
"markdown-it-container": "^3.0.0", "markdown-it-container": "^3.0.0",
"markdown-it-emoji": "^2.0.0", "markdown-it-emoji": "^2.0.2",
"markdown-it-toc-done-right": "^4.2.0", "markdown-it-toc-done-right": "^4.2.0",
"micromatch": "^4.0.4", "micromatch": "^4.0.5",
"minimist": "^1.2.5", "minimist": "^1.2.6",
"npm-run-all": "^4.1.5", "npm-run-all": "^4.1.5",
"ora": "^5.4.0", "ora": "^5.4.1",
"picocolors": "^1.0.0", "picocolors": "^1.0.0",
"polka": "^0.5.2", "polka": "^0.5.2",
"prettier": "^2.3.0", "prettier": "^2.7.1",
"prompts": "^2.4.2", "prompts": "^2.4.2",
"rimraf": "^3.0.2", "rimraf": "^3.0.2",
"rollup": "^2.56.3", "rollup": "^2.75.7",
"rollup-plugin-dts": "^4.2.2", "rollup-plugin-dts": "^4.2.2",
"rollup-plugin-esbuild": "^4.8.2", "rollup-plugin-esbuild": "^4.9.1",
"semver": "^7.3.5", "semver": "^7.3.7",
"simple-git-hooks": "^2.7.0", "simple-git-hooks": "^2.8.0",
"sirv": "^1.0.12", "sirv": "^2.0.2",
"supports-color": "^9.2.2", "supports-color": "^9.2.2",
"typescript": "^4.7.2", "typescript": "^4.7.4",
"vitest": "^0.14.2" "vitest": "^0.16.0",
"vue-tsc": "^0.38.2"
}, },
"pnpm": { "pnpm": {
"peerDependencyRules": { "peerDependencyRules": {

File diff suppressed because it is too large Load Diff

@ -49,7 +49,7 @@ export function usePrefetch() {
return return
} }
const rIC = (window as any).requestIdleCallback || setTimeout const rIC = window.requestIdleCallback || setTimeout
let observer: IntersectionObserver | null = null let observer: IntersectionObserver | null = null
const observeLinks = () => { const observeLinks = () => {
@ -73,8 +73,8 @@ export function usePrefetch() {
}) })
rIC(() => { rIC(() => {
document.querySelectorAll('#app a').forEach((link) => { document.querySelectorAll<HTMLAnchorElement>('#app a').forEach((link) => {
const { target, hostname, pathname } = link as HTMLAnchorElement const { target, hostname, pathname } = link
const extMatch = pathname.match(/\.\w+$/) const extMatch = pathname.match(/\.\w+$/)
if (extMatch && extMatch[0] !== '.html') { if (extMatch && extMatch[0] !== '.html') {
return return

@ -2,11 +2,12 @@ import {
App, App,
createApp as createClientApp, createApp as createClientApp,
createSSRApp, createSSRApp,
defineComponent,
h, h,
onMounted, onMounted,
watch watch
} from 'vue' } from 'vue'
import Theme from '/@theme/index' import Theme from '../theme-default'
import { inBrowser, pathToFile } from './utils' import { inBrowser, pathToFile } from './utils'
import { Router, RouterSymbol, createRouter } from './router' import { Router, RouterSymbol, createRouter } from './router'
import { siteDataRef, useData } from './data' import { siteDataRef, useData } from './data'
@ -18,7 +19,7 @@ import { ClientOnly } from './components/ClientOnly'
const NotFound = Theme.NotFound || (() => '404 Not Found') const NotFound = Theme.NotFound || (() => '404 Not Found')
const VitePressApp = { const VitePressApp = defineComponent({
name: 'VitePressApp', name: 'VitePressApp',
setup() { setup() {
const { site } = useData() const { site } = useData()
@ -38,9 +39,11 @@ const VitePressApp = {
// in prod mode, enable intersectionObserver based pre-fetch // in prod mode, enable intersectionObserver based pre-fetch
usePrefetch() usePrefetch()
} }
if (Theme.setup) Theme.setup()
return () => h(Theme.Layout) return () => h(Theme.Layout)
} }
} })
export function createApp() { export function createApp() {
const router = newRouter() const router = newRouter()

@ -34,7 +34,7 @@ interface PageModule {
} }
export function createRouter( export function createRouter(
loadPageModule: (path: string) => PageModule | Promise<PageModule>, loadPageModule: (path: string) => Promise<PageModule>,
fallbackComponent?: Component fallbackComponent?: Component
): Router { ): Router {
const route = reactive(getDefaultRoute()) const route = reactive(getDefaultRoute())
@ -61,16 +61,11 @@ export function createRouter(
const targetLoc = new URL(href, fakeHost) const targetLoc = new URL(href, fakeHost)
const pendingPath = (latestPendingPath = targetLoc.pathname) const pendingPath = (latestPendingPath = targetLoc.pathname)
try { try {
let page = loadPageModule(pendingPath) let page = await loadPageModule(pendingPath)
// only await if it returns a Promise - this allows sync resolution
// on initial render in SSR.
if ('then' in page && typeof page.then === 'function') {
page = await page
}
if (latestPendingPath === pendingPath) { if (latestPendingPath === pendingPath) {
latestPendingPath = null latestPendingPath = null
const { default: comp, __pageData } = page as PageModule const { default: comp, __pageData } = page
if (!comp) { if (!comp) {
throw new Error(`Invalid route component: ${comp}`) throw new Error(`Invalid route component: ${comp}`)
} }
@ -88,7 +83,7 @@ export function createRouter(
try { try {
target = document.querySelector( target = document.querySelector(
decodeURIComponent(targetLoc.hash) decodeURIComponent(targetLoc.hash)
) as HTMLElement )
} catch (e) { } catch (e) {
console.warn(e) console.warn(e)
} }
@ -188,7 +183,6 @@ export function useRouter(): Router {
if (!router) { if (!router) {
throw new Error('useRouter() is called without provider.') throw new Error('useRouter() is called without provider.')
} }
// @ts-ignore
return router return router
} }
@ -197,7 +191,7 @@ export function useRoute(): Route {
} }
function scrollTo(el: HTMLElement, hash: string, smooth = false) { function scrollTo(el: HTMLElement, hash: string, smooth = false) {
let target: Element | null = null let target: HTMLElement | null = null
try { try {
target = el.classList.contains('header-anchor') target = el.classList.contains('header-anchor')
@ -214,12 +208,12 @@ function scrollTo(el: HTMLElement, hash: string, smooth = false) {
document.querySelector(offset)!.getBoundingClientRect().bottom + 24 document.querySelector(offset)!.getBoundingClientRect().bottom + 24
} }
const targetPadding = parseInt( const targetPadding = parseInt(
window.getComputedStyle(target as HTMLElement).paddingTop, window.getComputedStyle(target).paddingTop,
10 10
) )
const targetTop = const targetTop =
window.scrollY + window.scrollY +
(target as HTMLElement).getBoundingClientRect().top - target.getBoundingClientRect().top -
offset + offset +
targetPadding targetPadding
// only smooth scroll if distance is smaller than screen height. // only smooth scroll if distance is smaller than screen height.

@ -12,4 +12,5 @@ export interface Theme {
Layout: Component Layout: Component
NotFound?: Component NotFound?: Component
enhanceApp?: (ctx: EnhanceAppContext) => void enhanceApp?: (ctx: EnhanceAppContext) => void
setup?: () => void
} }

@ -35,7 +35,8 @@ export function pathToFile(path: string): string {
// /foo/bar.html -> ./foo_bar.md // /foo/bar.html -> ./foo_bar.md
if (inBrowser) { if (inBrowser) {
const base = import.meta.env.BASE_URL const base = import.meta.env.BASE_URL
pagePath = pagePath.slice(base.length).replace(/\//g, '_') + '.md' pagePath =
(pagePath.slice(base.length).replace(/\//g, '_') || 'index') + '.md'
// client production build needs to account for page hash, which is // client production build needs to account for page hash, which is
// injected directly in the page's html // injected directly in the page's html
const pageHash = __VP_HASH_MAP__[pagePath.toLowerCase()] const pageHash = __VP_HASH_MAP__[pagePath.toLowerCase()]

@ -14,9 +14,3 @@ declare module '@siteData' {
const data: SiteData const data: SiteData
export default data export default data
} }
// this module's typing is broken.
declare module '@docsearch/js' {
function docsearch<T = any>(props: T): void
export default docsearch
}

@ -29,14 +29,16 @@ function poll() {
}, 16) }, 16)
} }
type DocSearchProps = Parameters<typeof docsearch>[0]
function initialize(userOptions: DefaultTheme.AlgoliaSearchOptions) { function initialize(userOptions: DefaultTheme.AlgoliaSearchOptions) {
// note: multi-lang search support is removed since the theme // note: multi-lang search support is removed since the theme
// doesn't support multiple locales as of now. // doesn't support multiple locales as of now.
const options = Object.assign({}, userOptions, { const options = Object.assign<{}, {}, DocSearchProps>({}, userOptions, {
container: '#docsearch', container: '#docsearch',
navigator: { navigator: {
navigate({ itemUrl }: { itemUrl: string }) { navigate({ itemUrl }) {
const { pathname: hitPathname } = new URL( const { pathname: hitPathname } = new URL(
window.location.origin + itemUrl window.location.origin + itemUrl
) )
@ -51,7 +53,7 @@ function initialize(userOptions: DefaultTheme.AlgoliaSearchOptions) {
} }
}, },
transformItems(items: any[]) { transformItems(items) {
return items.map((item) => { return items.map((item) => {
return Object.assign({}, item, { return Object.assign({}, item, {
url: getRelativePath(item.url) url: getRelativePath(item.url)
@ -59,9 +61,10 @@ function initialize(userOptions: DefaultTheme.AlgoliaSearchOptions) {
}) })
}, },
hitComponent({ hit, children }: { hit: any; children: any }) { // @ts-ignore
hitComponent({ hit, children }) {
const relativeHit = hit.url.startsWith('http') const relativeHit = hit.url.startsWith('http')
? getRelativePath(hit.url as string) ? getRelativePath(hit.url)
: hit.url : hit.url
return { return {

@ -22,7 +22,7 @@ const resolvedHeaders = computed(() => {
function handleClick({ target: el }: Event) { function handleClick({ target: el }: Event) {
const id = '#' + (el as HTMLAnchorElement).href!.split('#')[1] const id = '#' + (el as HTMLAnchorElement).href!.split('#')[1]
const heading = document.querySelector(id) as HTMLAnchorElement const heading = document.querySelector<HTMLAnchorElement>(id)
heading?.focus() heading?.focus()
} }
</script> </script>

@ -1,18 +1,8 @@
<script setup lang="ts"> <script setup lang="ts">
import type { Sponsors } from './VPSponsors.vue'
import type { Sponsor } from './VPSponsorsGrid.vue'
import VPSponsors from './VPSponsors.vue' import VPSponsors from './VPSponsors.vue'
export interface Sponsors {
tier?: string
size?: 'xmini' | 'mini' | 'small'
items: Sponsor[]
}
export interface Sponsor {
name: string
img: string
url: string
}
defineProps<{ defineProps<{
tier?: string tier?: string
size?: 'xmini' | 'mini' | 'small' size?: 'xmini' | 'mini' | 'small'
@ -22,11 +12,6 @@ defineProps<{
<template> <template>
<div class="VPDocAsideSponsors"> <div class="VPDocAsideSponsors">
<VPSponsors <VPSponsors mode="aside" :tier="tier" :size="size" :data="data" />
mode="aside"
:tier="tier"
:size="size"
:data="data"
/>
</div> </div>
</template> </template>

@ -8,9 +8,9 @@ const backToTop = ref()
watch(() => route.path, () => backToTop.value.focus()) watch(() => route.path, () => backToTop.value.focus())
function focusOnTargetAnchor({ target }: Event) { function focusOnTargetAnchor({ target }: Event) {
const el = document.querySelector( const el = document.querySelector<HTMLAnchorElement>(
(target as HTMLAnchorElement).hash! (target as HTMLAnchorElement).hash
) as HTMLAnchorElement )
if (el) { if (el) {
const removeTabIndex = () => { const removeTabIndex = () => {

@ -1,40 +1,34 @@
<script setup lang="ts"> <script setup lang="ts">
import type { GridSize } from '../composables/sponsor-grid'
import type { Sponsor } from './VPSponsorsGrid.vue'
import { computed } from 'vue' import { computed } from 'vue'
import VPSponsorsGrid from './VPSponsorsGrid.vue' import VPSponsorsGrid from './VPSponsorsGrid.vue'
export interface Sponsors { export interface Sponsors {
tier?: string tier?: string
size?: 'small' | 'medium' | 'big' size?: GridSize
items: Sponsor[] items: Sponsor[]
} }
export interface Sponsor {
name: string
img: string
url: string
}
const props = defineProps<{ const props = defineProps<{
mode?: 'normal' | 'aside' mode?: 'normal' | 'aside'
tier?: string tier?: string
size?: 'xmini' | 'small' | 'medium' | 'big' size?: GridSize
data: Sponsors[] | Sponsor[] data: Sponsors[] | Sponsor[]
}>() }>()
const sponsors = computed(() => { const sponsors = computed(() => {
const isSponsors = props.data.some((s) => { const isSponsors = props.data.some((s) => {
return !!(s as Sponsors).items return 'items' in s
}) })
if (isSponsors) { if (isSponsors) {
return props.data return props.data as Sponsors[]
} }
return [{ return [
tier: props.tier, { tier: props.tier, size: props.size, items: props.data as Sponsor[] }
size: props.size, ]
items: props.data
}]
}) })
</script> </script>

@ -1,4 +1,5 @@
<script setup lang="ts"> <script setup lang="ts">
import type { GridSize } from '../composables/sponsor-grid'
import { ref } from 'vue' import { ref } from 'vue'
import { useSponsorsGrid } from '../composables/sponsor-grid' import { useSponsorsGrid } from '../composables/sponsor-grid'
@ -9,7 +10,7 @@ export interface Sponsor {
} }
const props = defineProps<{ const props = defineProps<{
size?: 'xmini' | 'mini' | 'small' | 'medium' | 'big' size?: GridSize
data: Sponsor[] data: Sponsor[]
}>() }>()
@ -19,12 +20,29 @@ useSponsorsGrid({ el, size: props.size })
</script> </script>
<template> <template>
<div class="VPSponsorsGrid vp-sponsor-grid" :class="[props.size ?? 'medium']" ref="el"> <div
<div v-for="sponsor in data" :key="sponsor.tier" class="vp-sponsor-grid-item"> class="VPSponsorsGrid vp-sponsor-grid"
<a class="vp-sponsor-grid-link" :href="sponsor.url" target="_blank" rel="sponsored noopener"> :class="[props.size ?? 'medium']"
ref="el"
>
<div
v-for="sponsor in data"
:key="sponsor.name"
class="vp-sponsor-grid-item"
>
<a
class="vp-sponsor-grid-link"
:href="sponsor.url"
target="_blank"
rel="sponsored noopener"
>
<article class="vp-sponsor-grid-box"> <article class="vp-sponsor-grid-box">
<h4 class="visually-hidden">{{ sponsor.name }}</h4> <h4 class="visually-hidden">{{ sponsor.name }}</h4>
<img class="vp-sponsor-grid-image" :src="sponsor.img" :alt="sponsor.name" /> <img
class="vp-sponsor-grid-image"
:src="sponsor.img"
:alt="sponsor.name"
/>
</article> </article>
</a> </a>
</div> </div>

@ -1,6 +1,6 @@
<script setup lang="ts"> <script setup lang="ts">
import type { DefaultTheme } from 'vitepress/theme'
import { computed } from 'vue' import { computed } from 'vue'
import type { DefaultTheme } from '..'
import VPTeamMembersItem from './VPTeamMembersItem.vue' import VPTeamMembersItem from './VPTeamMembersItem.vue'
const props = defineProps<{ const props = defineProps<{

@ -1,5 +1,5 @@
<script setup lang="ts"> <script setup lang="ts">
import type { DefaultTheme } from '..' import type { DefaultTheme } from 'vitepress/theme'
import VPIconHeart from './icons/VPIconHeart.vue' import VPIconHeart from './icons/VPIconHeart.vue'
import VPLink from './VPLink.vue' import VPLink from './VPLink.vue'
import VPSocialLinks from './VPSocialLinks.vue' import VPSocialLinks from './VPSocialLinks.vue'

@ -20,7 +20,7 @@ export function useFlyout(options: UseFlyoutOptions) {
listeners++ listeners++
const unwatch = watch(focusedElement, (el) => { const unwatch = watch(focusedElement, (el) => {
if (el === options.el.value || options.el.value?.contains(el as Node)) { if (el === options.el.value || options.el.value?.contains(el!)) {
focus.value = true focus.value = true
options.onFocus?.() options.onFocus?.()
} else { } else {

@ -135,7 +135,7 @@ export function useActiveAnchor(
if (hash !== null) { if (hash !== null) {
prevActiveLink = container.value.querySelector( prevActiveLink = container.value.querySelector(
`a[href="${decodeURIComponent(hash)}"]` `a[href="${decodeURIComponent(hash)}"]`
) as HTMLAnchorElement )
} }
const activeLink = prevActiveLink const activeLink = prevActiveLink

@ -11,7 +11,6 @@
"lib": ["ESNext", "DOM"], "lib": ["ESNext", "DOM"],
"types": ["vite/client"], "types": ["vite/client"],
"paths": { "paths": {
"/@theme/*": ["theme-default/*"],
"vitepress": ["index.ts"], "vitepress": ["index.ts"],
"vitepress/theme": ["../../types/default-theme.d"] "vitepress/theme": ["../../types/default-theme.d"]
} }

@ -1,9 +1,7 @@
import { createRequire } from 'module'
import { resolve, join } from 'path' import { resolve, join } from 'path'
import { fileURLToPath } from 'url' import { fileURLToPath } from 'url'
import { Alias, AliasOptions } from 'vite' import { Alias, AliasOptions } from 'vite'
const require = createRequire(import.meta.url)
const PKG_ROOT = resolve(fileURLToPath(import.meta.url), '../..') const PKG_ROOT = resolve(fileURLToPath(import.meta.url), '../..')
export const DIST_CLIENT_PATH = resolve(PKG_ROOT, 'client') export const DIST_CLIENT_PATH = resolve(PKG_ROOT, 'client')
@ -17,29 +15,12 @@ export const DEFAULT_THEME_PATH = join(DIST_CLIENT_PATH, 'theme-default')
export const SITE_DATA_ID = '@siteData' export const SITE_DATA_ID = '@siteData'
export const SITE_DATA_REQUEST_PATH = '/' + SITE_DATA_ID export const SITE_DATA_REQUEST_PATH = '/' + SITE_DATA_ID
const vueRuntimePath = 'vue/dist/vue.runtime.esm-bundler.js'
export function resolveAliases(root: string, themeDir: string): AliasOptions { export function resolveAliases(root: string, themeDir: string): AliasOptions {
const paths: Record<string, string> = {
'/@theme': themeDir,
'@theme': themeDir,
[SITE_DATA_ID]: SITE_DATA_REQUEST_PATH
}
// prioritize vue installed in project root and fallback to
// vue that comes with vitepress itself.
let vuePath
try {
vuePath = require.resolve(vueRuntimePath, { paths: [root] })
} catch (e) {
vuePath = require.resolve(vueRuntimePath)
}
const aliases: Alias[] = [ const aliases: Alias[] = [
...Object.keys(paths).map((p) => ({ {
find: p, find: SITE_DATA_ID,
replacement: paths[p] replacement: SITE_DATA_REQUEST_PATH
})), },
{ {
find: /^vitepress$/, find: /^vitepress$/,
replacement: join(DIST_CLIENT_PATH, '/index') replacement: join(DIST_CLIENT_PATH, '/index')
@ -52,12 +33,6 @@ export function resolveAliases(root: string, themeDir: string): AliasOptions {
{ {
find: /^vitepress\//, find: /^vitepress\//,
replacement: PKG_ROOT + '/' replacement: PKG_ROOT + '/'
},
// make sure it always use the same vue dependency that comes
// with vitepress itself
{
find: /^vue$/,
replacement: vuePath
} }
] ]

@ -84,7 +84,8 @@ export async function build(
pageToHashMap pageToHashMap
) )
} finally { } finally {
await fs.remove(siteConfig.tempDir) if (!process.env.DEBUG)
fs.rmSync(siteConfig.tempDir, { recursive: true, force: true })
} }
console.log(`build complete in ${((Date.now() - start) / 1000).toFixed(2)}s.`) console.log(`build complete in ${((Date.now() - start) / 1000).toFixed(2)}s.`)

@ -52,9 +52,8 @@ export async function bundle(
pageToHashMap, pageToHashMap,
clientJSMap clientJSMap
), ),
// @ts-ignore
ssr: { ssr: {
noExternal: ['vitepress'] noExternal: ['vitepress', '@docsearch/css']
}, },
build: { build: {
...options, ...options,
@ -71,7 +70,11 @@ export async function bundle(
output: { output: {
...rollupOptions?.output, ...rollupOptions?.output,
...(ssr ...(ssr
? {} ? {
entryFileNames: `[name].js`,
chunkFileNames: `[name].[hash].js`,
assetFileNames: `[name].[ext]`
}
: { : {
chunkFileNames(chunk) { chunkFileNames(chunk) {
// avoid ads chunk being intercepted by adblock // avoid ads chunk being intercepted by adblock
@ -95,9 +98,7 @@ export async function bundle(
} }
}) })
} }
}, }
// minify with esbuild in MPA mode (for CSS)
minify: ssr ? (config.mpa ? 'esbuild' : false) : !process.env.DEBUG
} }
}) })
@ -138,7 +139,7 @@ export async function bundle(
} }
// build <script client> bundle // build <script client> bundle
if (Object.keys(clientJSMap).length) { if (Object.keys(clientJSMap).length) {
clientResult = (await buildMPAClient(clientJSMap, config)) as RollupOutput clientResult = await buildMPAClient(clientJSMap, config)
} }
} }
@ -167,7 +168,7 @@ function staticImportedByEntry(
importStack: string[] = [] importStack: string[] = []
): boolean { ): boolean {
if (cache.has(id)) { if (cache.has(id)) {
return cache.get(id) as boolean return !!cache.get(id)
} }
if (importStack.includes(id)) { if (importStack.includes(id)) {
// circular deps! // circular deps!

@ -1,4 +1,3 @@
import { createRequire } from 'module'
import fs from 'fs-extra' import fs from 'fs-extra'
import path from 'path' import path from 'path'
import { pathToFileURL } from 'url' import { pathToFileURL } from 'url'
@ -9,8 +8,6 @@ import { HeadConfig, PageData, createTitle, notFoundPageData } from '../shared'
import { slash } from '../utils/slash' import { slash } from '../utils/slash'
import { SiteConfig, resolveSiteDataByRoute } from '../config' import { SiteConfig, resolveSiteDataByRoute } from '../config'
const require = createRequire(import.meta.url)
export async function renderPage( export async function renderPage(
config: SiteConfig, config: SiteConfig,
page: string, // foo.md page: string, // foo.md
@ -20,28 +17,16 @@ export async function renderPage(
pageToHashMap: Record<string, string>, pageToHashMap: Record<string, string>,
hashMapString: string hashMapString: string
) { ) {
const { createApp } = await import( const entryPath = path.join(config.tempDir, 'app.js')
pathToFileURL(path.join(config.tempDir, `app.js`)).toString() const { createApp } = await import(pathToFileURL(entryPath).toString())
)
const { app, router } = createApp() const { app, router } = createApp()
const routePath = `/${page.replace(/\.md$/, '')}` const routePath = `/${page.replace(/\.md$/, '')}`
const siteData = resolveSiteDataByRoute(config.site, routePath) const siteData = resolveSiteDataByRoute(config.site, routePath)
router.go(routePath) await router.go(routePath)
// lazy require server-renderer for production build
// prioritize project root over vitepress' own dep
let rendererPath
try {
rendererPath = require.resolve('vue/server-renderer', {
paths: [config.root]
})
} catch (e) {
rendererPath = require.resolve('vue/server-renderer')
}
// render page // render page
const content = await import(pathToFileURL(rendererPath).toString()).then( const content = await import('vue/server-renderer').then(
(r) => r.renderToString(app) ({ renderToString: r }) => r(app)
) )
const pageName = page.replace(/\//g, '_') const pageName = page.replace(/\//g, '_')

@ -199,7 +199,7 @@ async function resolveUserConfig(
} }
const userConfig: RawConfigExports = configPath const userConfig: RawConfigExports = configPath
? (( ? (
await loadConfigFromFile( await loadConfigFromFile(
{ {
command, command,
@ -208,7 +208,7 @@ async function resolveUserConfig(
configPath, configPath,
root root
) )
)?.config as any) )?.config!
: {} : {}
if (configPath) { if (configPath) {

@ -219,6 +219,14 @@ export async function createVitePressPlugin(
delete bundle[name] delete bundle[name]
} }
} }
if (config.ssr?.format === 'esm') {
this.emitFile({
type: 'asset',
fileName: 'package.json',
source: '{ "private": true, "type": "module" }'
})
}
} else { } else {
// client build: // client build:
// for each .md entry chunk, adjust its name to its correct path. // for each .md entry chunk, adjust its name to its correct path.

@ -22,7 +22,7 @@ export interface ServeOptions {
} }
export async function serve(options: ServeOptions = {}) { export async function serve(options: ServeOptions = {}) {
const port = options.port !== undefined ? options.port : 5000 const port = options.port !== undefined ? options.port : 4173
const site = await resolveConfig(options.root, 'serve', 'production') const site = await resolveConfig(options.root, 'serve', 'production')
const base = trimChar(options?.base ?? site?.site?.base ?? '', '/') const base = trimChar(options?.base ?? site?.site?.base ?? '', '/')

@ -1,3 +1,4 @@
import { setDefaultResultOrder } from 'node:dns'
import { createServer as createViteServer, ServerOptions } from 'vite' import { createServer as createViteServer, ServerOptions } from 'vite'
import { resolveConfig } from './config' import { resolveConfig } from './config'
import { createVitePressPlugin } from './plugin' import { createVitePressPlugin } from './plugin'
@ -13,6 +14,8 @@ export async function createServer(
delete serverOptions.base delete serverOptions.base
} }
setDefaultResultOrder('verbatim')
return createViteServer({ return createViteServer({
root: config.srcDir, root: config.srcDir,
base: config.site.base, base: config.site.base,

@ -13,7 +13,6 @@ export type {
export const EXTERNAL_URL_RE = /^https?:/i export const EXTERNAL_URL_RE = /^https?:/i
export const APPEARANCE_KEY = 'vitepress-theme-appearance' export const APPEARANCE_KEY = 'vitepress-theme-appearance'
// @ts-ignore
export const inBrowser = typeof window !== 'undefined' export const inBrowser = typeof window !== 'undefined'
export const notFoundPageData: PageData = { export const notFoundPageData: PageData = {

18
theme.d.ts vendored

@ -1,14 +1,14 @@
// so that users can do `import DefaultTheme from 'vitepress/theme'` // so that users can do `import DefaultTheme from 'vitepress/theme'`
import { ComponentOptions } from 'vue' import type { ComponentOptions } from 'vue'
export const VPHomeHero = ComponentOptions export const VPHomeHero: ComponentOptions
export const VPHomeFeatures = ComponentOptions export const VPHomeFeatures: ComponentOptions
export const VPHomeSponsors = ComponentOptions export const VPHomeSponsors: ComponentOptions
export const VPDocAsideSponsors = ComponentOptions export const VPDocAsideSponsors: ComponentOptions
export const VPTeamPage = ComponentOptions export const VPTeamPage: ComponentOptions
export const VPTeamPageTitle = ComponentOptions export const VPTeamPageTitle: ComponentOptions
export const VPTeamPageSection = ComponentOptions export const VPTeamPageSection: ComponentOptions
export const VPTeamMembers = ComponentOptions export const VPTeamMembers: ComponentOptions
declare const theme: { declare const theme: {
Layout: ComponentOptions Layout: ComponentOptions

Loading…
Cancel
Save