Skip to content

Commit

Permalink
load config + provide siteData
Browse files Browse the repository at this point in the history
  • Loading branch information
yyx990803 committed Apr 28, 2020
1 parent d02ec5e commit c4002a8
Show file tree
Hide file tree
Showing 9 changed files with 125 additions and 41 deletions.
4 changes: 1 addition & 3 deletions lib/app/composables/pageData.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
export function usePageData() {
return {
msg: 'this is page'
}

}
22 changes: 19 additions & 3 deletions lib/app/composables/siteData.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,21 @@
import serialized from '@siteData'
import { hot } from '@hmr'
import { shallowRef, readonly } from 'vue'

/**
* @param {string} data
*/
const parse = (data) =>
__DEV__ ? readonly(JSON.parse(data)) : JSON.parse(data)

// site data
export const siteDataRef = shallowRef(parse(serialized))

export function useSiteData() {
return {
msg: 'this is site'
}
return siteDataRef
}

// hmr
hot.accept('/@siteData', (m) => {
siteDataRef.value = parse(m.default)
})
1 change: 1 addition & 0 deletions lib/app/index-dev.html
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
<div id="app"></div>
<script>window.__DEV__ = true</script>
<script type="module" src="/@app/index.js"></script>
4 changes: 2 additions & 2 deletions lib/app/index.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { createApp, h } from 'vue'
import { Content } from './components/Content'
import { useRouter } from './composables/router'
import { useSiteData } from './composables/siteData'
import { siteDataRef } from './composables/siteData'
import Theme from '/@theme/index'

const App = {
Expand All @@ -18,7 +18,7 @@ const App = {
const app = createApp(App)

Object.defineProperty(app.config.globalProperties, '$site', {
get: useSiteData
get: () => siteDataRef.value
})

app.component('Content', Content)
Expand Down
13 changes: 13 additions & 0 deletions lib/shim.d.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,18 @@
declare const __DEV__: boolean

declare module "*.vue" {
import { ComponentOptions } from 'vue'
const comp: ComponentOptions
export default comp
}

declare module "@siteData" {
const data: string
export default data
}

declare module "@hmr" {
export declare const hot: {
accept(path: string, cb: (module: any) => void)
}
}
10 changes: 6 additions & 4 deletions lib/theme-default/Layout.vue
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,12 @@
import { useSiteData, usePageData } from 'vitepress'
export default {
data: () => ({
site: useSiteData(),
page: usePageData()
})
setup() {
return {
site: useSiteData(),
page: usePageData()
}
}
}
</script>

Expand Down
56 changes: 33 additions & 23 deletions src/resolveConfig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { Resolver } from 'vite'

const debug = require('debug')('vitepress:config')

export interface UserConfig<ThemeConfig = Record<string, any>> {
export interface UserConfig<ThemeConfig = any> {
base?: string
title?: string
description?: string
Expand All @@ -16,7 +16,7 @@ export interface UserConfig<ThemeConfig = Record<string, any>> {
// TODO locales support etc.
}

export interface SiteData<ThemeConfig = Record<string, any>> {
export interface SiteData<ThemeConfig = any> {
title: string
description: string
base: string
Expand All @@ -28,22 +28,49 @@ export interface PageData {
path: string
}

export interface ResolvedConfig<ThemeConfig = Record<string, any>> {
export interface ResolvedConfig<ThemeConfig = any> {
site: SiteData<ThemeConfig>
root: string // project root on file system
themePath: string
resolver: Resolver
}

export const getConfigPath = (root: string) =>
path.join(root, '.vitepress/config.js')

export async function resolveConfig(root: string): Promise<ResolvedConfig> {
const site = await resolveSiteData(root)

// resolve theme path
const userThemePath = path.join(root, '.vitepress/theme')
let themePath: string
try {
await fs.stat(userThemePath)
themePath = userThemePath
} catch (e) {
themePath = path.join(__dirname, '../lib/theme-default')
}

const config: ResolvedConfig = {
site,
themePath,
resolver: createResolver(themePath)
}

return config
}

export async function resolveSiteData(root: string): Promise<SiteData> {
// 1. load user config
const configPath = path.join(root, '.vitepress/config.js')
const configPath = getConfigPath(root)
let hasUserConfig = false
try {
await fs.stat(configPath)
hasUserConfig = true
debug(`loading user config at ${configPath}`)
} catch (e) {}

// always delete cache first before loading config
delete require.cache[configPath]
const userConfig: UserConfig = hasUserConfig ? require(configPath) : {}

// 2. TODO scan pages data
Expand All @@ -57,22 +84,5 @@ export async function resolveConfig(root: string): Promise<ResolvedConfig> {
pages: []
}

// 4. resolve theme path
const userThemePath = path.join(root, '.vitepress/theme')
let themePath: string
try {
await fs.stat(userThemePath)
themePath = userThemePath
} catch (e) {
themePath = path.join(__dirname, '../lib/theme-default')
}

const config: ResolvedConfig = {
root,
site,
themePath,
resolver: createResolver(themePath)
}

return config
return site
}
50 changes: 44 additions & 6 deletions src/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,25 @@ import {
Plugin,
ServerConfig
} from 'vite'
import { resolveConfig, ResolvedConfig } from './resolveConfig'
import {
resolveConfig,
ResolvedConfig,
getConfigPath,
resolveSiteData
} from './resolveConfig'
import { createMarkdownToVueRenderFn } from './markdown/markdownToVue'
import { APP_PATH } from './utils/pathResolver'
import { APP_PATH, SITE_DATA_REQUEST_PATH } from './utils/pathResolver'

const debug = require('debug')('vitepress:serve')
const debugHmr = require('debug')('vitepress:hmr')

function createVitePressPlugin({
themePath,
resolver: vitepressResolver
}: ResolvedConfig): Plugin {
function createVitePressPlugin(config: ResolvedConfig): Plugin {
const {
themePath,
site: initialSiteData,
resolver: vitepressResolver
} = config

return ({ app, root, watcher, resolver }) => {
const markdownToVue = createMarkdownToVueRenderFn(root)

Expand All @@ -39,8 +47,38 @@ function createVitePressPlugin({
}
})

// hot reload handling for siteData
// the data is stringified twice so it is sent to the client as a string
// it is then parsed on the client via JSON.parse() which is faster than
// parsing the object literal as JavaScript.
let siteData = initialSiteData
let stringifiedData = JSON.stringify(JSON.stringify(initialSiteData))
const configPath = getConfigPath(root)
watcher.add(configPath)
watcher.on('change', async (file) => {
if (file === configPath) {
const newData = await resolveSiteData(root)
stringifiedData = JSON.stringify(JSON.stringify(newData))
if (newData.base !== siteData.base) {
console.warn(
`[vitepress]: config.base has changed. Please restart the dev server.`
)
}
siteData = newData
watcher.handleJSReload(SITE_DATA_REQUEST_PATH)
}
})

// inject Koa middleware
app.use(async (ctx, next) => {
// serve siteData (which is a virtual file)
if (ctx.path === SITE_DATA_REQUEST_PATH) {
ctx.type = 'js'
ctx.body = `export default ${stringifiedData}`
debug(ctx.url)
return
}

// handle .md -> vue transforms
if (ctx.path.endsWith('.md')) {
const file = resolver.requestToFile(ctx.path)
Expand Down
6 changes: 6 additions & 0 deletions src/utils/pathResolver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@ import { Resolver } from "vite"
// built ts files are placed into /dist
export const APP_PATH = path.join(__dirname, '../../lib/app')

// speical virtual file
export const SITE_DATA_REQUEST_PATH = '/@siteData'

// this is a path resolver that is passed to vite
// so that we can resolve custom requests that start with /@app or /@theme
// we also need to map file paths back to their public served paths so that
Expand All @@ -25,6 +28,9 @@ export function createResolver(themePath: string): Resolver {
if (filePath.startsWith(themePath)) {
return `/@theme/${path.relative(themePath, filePath)}`
}
if (filePath === SITE_DATA_REQUEST_PATH) {
return SITE_DATA_REQUEST_PATH
}
},
idToRequest(id) {
if (id === 'vitepress') {
Expand Down

0 comments on commit c4002a8

Please sign in to comment.