feat: add components from .components folder

pull/7/head
pikax 5 years ago
parent 49fc3cdb2b
commit a988223399

@ -1,4 +1,10 @@
import { createApp as createClientApp, createSSRApp, ref, readonly } from 'vue'
import {
createApp as createClientApp,
createSSRApp,
ref,
readonly,
defineAsyncComponent
} from 'vue'
import { createRouter, RouterSymbol } from './router'
import { useUpdateHead } from './composables/head'
import { siteDataRef } from './composables/siteData'
@ -6,6 +12,7 @@ import { pageDataSymbol } from './composables/pageData'
import { Content } from './components/Content'
import Debug from './components/Debug.vue'
import Theme from '/@theme/index'
import Components from '@components'
import { hot } from '@hmr'
const inBrowser = typeof window !== 'undefined'
@ -76,6 +83,13 @@ export function createApp() {
app.component('Content', Content)
app.component('Debug', __DEV__ ? Debug : () => null)
for (const [name, ext] of Components) {
app.component(
name,
defineAsyncComponent(() => import(`/@components/${name}.${ext}`))
)
}
Object.defineProperties(app.config.globalProperties, {
$site: {
get() {

@ -14,7 +14,7 @@ export async function bundle(
options: BuildOptions
): Promise<BuildResult[]> {
const root = config.root
const resolver = createResolver(config.themeDir)
const resolver = createResolver(config.themeDir, config.componentDir)
const markdownToVue = createMarkdownToVueRenderFn(root)
const { rollupInputOptions = {}, rollupOutputOptions = {} } = options

@ -26,6 +26,7 @@ export interface SiteConfig<ThemeConfig = any> {
site: SiteData<ThemeConfig>
configPath: string
themeDir: string
componentDir: string
publicDir: string
outDir: string
tempDir: string
@ -61,6 +62,7 @@ export async function resolveConfig(
const themeDir = (await exists(userThemeDir))
? userThemeDir
: path.join(__dirname, '../lib/theme-default')
const componentDir = resolve(root, 'components')
const config: SiteConfig = {
root,
@ -69,9 +71,10 @@ export async function resolveConfig(
pages: await globby(['**.md'], { cwd: root, ignore: ['node_modules'] }),
configPath: resolve(root, 'config.js'),
publicDir: resolve(root, 'public'),
componentDir: componentDir,
outDir: resolve(root, 'dist'),
tempDir: path.resolve(APP_PATH, 'temp'),
resolver: createResolver(themeDir)
resolver: createResolver(themeDir, componentDir)
}
return config

@ -7,13 +7,19 @@ import {
} from 'vite'
import { resolveConfig, SiteConfig, resolveSiteData } from './config'
import { createMarkdownToVueRenderFn } from './markdownToVue'
import { APP_PATH, SITE_DATA_REQUEST_PATH } from './utils/pathResolver'
import {
APP_PATH,
SITE_DATA_REQUEST_PATH,
COMPONENTS_DATA_REQUEST_PATH
} from './utils/pathResolver'
import { promises as fs, readdirSync } from 'fs'
const debug = require('debug')('vitepress:serve')
const debugHmr = require('debug')('vitepress:hmr')
function createVitePressPlugin({
themeDir,
componentDir,
configPath,
site: initialSiteData
}: SiteConfig): Plugin {
@ -64,6 +70,14 @@ function createVitePressPlugin({
}
})
// TODO watch if for dirChanges
let componentsFiles = readdirSync(componentDir).map((x) => [
path.basename(x, path.extname(x)),
path.extname(x).slice(1)
])
let componentsString = JSON.stringify(componentsFiles)
watcher.add(COMPONENTS_DATA_REQUEST_PATH)
// 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
@ -83,6 +97,9 @@ function createVitePressPlugin({
siteData = newData
watcher.handleJSReload(SITE_DATA_REQUEST_PATH)
}
if (file.startsWith(componentDir)) {
watcher.handleJSReload(resolver.fileToRequest(file))
}
})
// inject Koa middleware
@ -95,6 +112,12 @@ function createVitePressPlugin({
return
}
if (ctx.path === COMPONENTS_DATA_REQUEST_PATH) {
ctx.type = 'js'
ctx.body = `export default ${componentsString}`
return
}
// handle .md -> vue transforms
if (ctx.path.endsWith('.md')) {
const file = resolver.requestToFile(ctx.path)

@ -1,17 +1,21 @@
import path from 'path'
import { Resolver } from "vite"
import { Resolver } from 'vite'
// built ts files are placed into /dist
export const APP_PATH = path.join(__dirname, '../../lib/app')
// special virtual file
export const SITE_DATA_REQUEST_PATH = '/@siteData'
export const COMPONENTS_DATA_REQUEST_PATH = '/@components'
// this is a path resolver that is passed to vite
// so that we can resolve custom requests that start with /@app or /@theme
// so that we can resolve custom requests that start with /@app or /@theme or /@components
// we also need to map file paths back to their public served paths so that
// vite HMR can send the correct update notifications to the client.
export function createResolver(themeDir: string): Resolver {
export function createResolver(
themeDir: string,
componentDir: string
): Resolver {
return {
requestToFile(publicPath) {
if (publicPath.startsWith('/@app')) {
@ -20,6 +24,18 @@ export function createResolver(themeDir: string): Resolver {
if (publicPath.startsWith('/@theme')) {
return path.join(themeDir, publicPath.replace(/^\/@theme\/?/, ''))
}
if (publicPath.startsWith('/@components/index')) {
return path.join(
componentDir,
publicPath.replace(/^\/@components\/?/, '')
)
}
if (publicPath.startsWith('/@components')) {
return path.join(
componentDir,
publicPath.replace(/^\/@components\/?/, '')
)
}
if (publicPath === SITE_DATA_REQUEST_PATH) {
return SITE_DATA_REQUEST_PATH
}
@ -31,6 +47,9 @@ export function createResolver(themeDir: string): Resolver {
if (filePath.startsWith(themeDir)) {
return `/@theme/${path.relative(themeDir, filePath)}`
}
if (filePath.startsWith(componentDir)) {
return `/@components/${path.relative(componentDir, filePath)}`
}
if (filePath === SITE_DATA_REQUEST_PATH) {
return SITE_DATA_REQUEST_PATH
}

Loading…
Cancel
Save