diff --git a/lib/app/Content.js b/lib/app/components/Content.js similarity index 85% rename from lib/app/Content.js rename to lib/app/components/Content.js index 6d76ef4b..1b3909be 100644 --- a/lib/app/Content.js +++ b/lib/app/components/Content.js @@ -1,7 +1,8 @@ import { h, shallowRef, watchEffect, inject, nextTick } from 'vue' -import { RouteSymbol } from './router' +import { RouteSymbol } from '../composables/router' +import Theme from '/@theme/index' -const Default404 = () => '404 Not Found' +const NotFound = Theme.NotFound || (() => '404 Not Found') export const Content = { setup() { @@ -35,7 +36,7 @@ export const Content = { }) .catch((err) => { if (route.path === pendingPath) { - comp.value = Default404 + comp.value = NotFound } }) }) diff --git a/lib/app/composables/data.js b/lib/app/composables/data.js new file mode 100644 index 00000000..a2c575b9 --- /dev/null +++ b/lib/app/composables/data.js @@ -0,0 +1,11 @@ +export function useSiteData() { + return { + msg: 'this is site' + } +} + +export function usePageData() { + return { + msg: 'this is page' + } +} diff --git a/lib/app/router.js b/lib/app/composables/router.js similarity index 100% rename from lib/app/router.js rename to lib/app/composables/router.js diff --git a/lib/app/exports.js b/lib/app/exports.js new file mode 100644 index 00000000..b21a1942 --- /dev/null +++ b/lib/app/exports.js @@ -0,0 +1,3 @@ +// exports in this file are exposed to themes and md files via 'vitepress' +// so the user can do `import { usePageData } from 'vitepress'` +export { usePageData, useSiteData } from './composables/data' diff --git a/lib/app/index.js b/lib/app/index.js index 5267b384..83753d74 100644 --- a/lib/app/index.js +++ b/lib/app/index.js @@ -1,7 +1,8 @@ import { createApp, h } from 'vue' -import { Layout } from '/@theme/index' -import { Content } from './Content' -import { useRouter } from './router' +import { Content } from './components/Content' +import { useRouter } from './composables/router' +import { useSiteData } from './composables/data' +import Theme from '/@theme/index' const App = { setup() { @@ -10,12 +11,16 @@ const App = { } else { // TODO inject static route for SSR } - return () => h(Layout) + return () => h(Theme.Layout) } } const app = createApp(App) +Object.defineProperty(app.config.globalProperties, '$site', { + get: useSiteData +}) + app.component('Content', Content) app.mount('#app') diff --git a/lib/jsconfig.json b/lib/jsconfig.json index 6f38c88b..7176ac8c 100644 --- a/lib/jsconfig.json +++ b/lib/jsconfig.json @@ -1,5 +1,6 @@ { "compilerOptions": { + "baseUrl": "../", "lib": ["ESNext", "DOM"], "moduleResolution": "node", "checkJs": true, @@ -8,7 +9,8 @@ "noImplicitAny": true, "paths": { "/@app/*": ["lib/app/*"], - "/@theme/*": ["lib/theme-default/*"] + "/@theme/*": ["lib/theme-default/*"], + "vitepress": ["lib/app/exports.js"] } }, "include": ["."] diff --git a/lib/theme-default/Layout.vue b/lib/theme-default/Layout.vue index dc01f311..54dd80e1 100644 --- a/lib/theme-default/Layout.vue +++ b/lib/theme-default/Layout.vue @@ -1,13 +1,22 @@ diff --git a/lib/theme-default/index.js b/lib/theme-default/index.js index 4763bbc2..964ac493 100644 --- a/lib/theme-default/index.js +++ b/lib/theme-default/index.js @@ -1,3 +1,13 @@ import Layout from './Layout.vue' -export { Layout } +/** + * @type {{ + * Layout: import('vue').ComponentOptions + * NotFound?: import('vue').ComponentOptions + * }} + */ +const Theme = { + Layout +} + +export default Theme diff --git a/src/server.ts b/src/server.ts index 0b39e6c7..c3567d79 100644 --- a/src/server.ts +++ b/src/server.ts @@ -38,7 +38,7 @@ function createVitePressPlugin({ app.use(async (ctx, next) => { // handle .md -> vue transforms if (ctx.path.endsWith('.md')) { - const file = resolver.publicToFile(ctx.path) + const file = resolver.requestToFile(ctx.path) await cachedRead(ctx, file) // let vite know this is supposed to be treated as vue file ctx.vue = true @@ -48,7 +48,7 @@ function createVitePressPlugin({ } // detect and serve vitepress @app / @theme files - const file = vitepressResolver.publicToFile(ctx.path, root) + const file = vitepressResolver.requestToFile(ctx.path, root) if (file) { await cachedRead(ctx, file) debug(ctx.url, ctx.status) diff --git a/src/tsconfig.json b/src/tsconfig.json index a045e381..f87a6b82 100644 --- a/src/tsconfig.json +++ b/src/tsconfig.json @@ -1,6 +1,6 @@ { "compilerOptions": { - "baseUrl": ".", + "baseUrl": "../", "outDir": "../dist", "module": "commonjs", "lib": ["ESNext"], diff --git a/src/utils/pathResolver.ts b/src/utils/pathResolver.ts index 81cf023d..7b4ef089 100644 --- a/src/utils/pathResolver.ts +++ b/src/utils/pathResolver.ts @@ -10,7 +10,7 @@ export const APP_PATH = path.join(__dirname, '../../lib/app') // vite HMR can send the correct update notifications to the client. export function createResolver(themePath: string): Resolver { return { - publicToFile(publicPath) { + requestToFile(publicPath) { if (publicPath.startsWith('/@app')) { return path.join(APP_PATH, publicPath.replace(/^\/@app\/?/, '')) } @@ -18,13 +18,18 @@ export function createResolver(themePath: string): Resolver { return path.join(themePath, publicPath.replace(/^\/@theme\/?/, '')) } }, - fileToPublic(filePath) { + fileToRequest(filePath) { if (filePath.startsWith(APP_PATH)) { return `/@app/${path.relative(APP_PATH, filePath)}` } if (filePath.startsWith(themePath)) { return `/@theme/${path.relative(themePath, filePath)}` } + }, + idToRequest(id) { + if (id === 'vitepress') { + return '/@app/exports.js' + } } } }