hmr for pageData

pull/1/head
Evan You 4 years ago
parent cc2174a3c0
commit 32244a99a8

@ -1,5 +1,6 @@
import { shallowReactive, provide, inject, nextTick } from 'vue' import { shallowReactive, provide, inject, nextTick } from 'vue'
import Theme from '/@theme/index' import Theme from '/@theme/index'
import { hot } from '@hmr'
const NotFound = Theme.NotFound || (() => '404 Not Found') const NotFound = Theme.NotFound || (() => '404 Not Found')
@ -29,6 +30,18 @@ export function useRouter() {
const loc = location const loc = location
const route = shallowReactive(getDefaultRoute()) const route = shallowReactive(getDefaultRoute())
if (__DEV__) {
// hot reload pageData
hot.on('vitepress:pageData', (data) => {
if (
data.path.replace(/\.md$/, '') ===
location.pathname.replace(/\.html$/, '')
) {
route.pageData = data.pageData
}
})
}
window.addEventListener( window.addEventListener(
'click', 'click',
/** /**

@ -16,6 +16,8 @@ export function useSiteData() {
} }
// hmr // hmr
if (__DEV__) {
hot.accept('/@siteData', (m) => { hot.accept('/@siteData', (m) => {
siteDataRef.value = parse(m.default) siteDataRef.value = parse(m.default)
}) })
}

@ -1,5 +1,6 @@
{ {
"compilerOptions": { "compilerOptions": {
"baseUrl": ".",
"lib": ["ESNext", "DOM"], "lib": ["ESNext", "DOM"],
"moduleResolution": "node", "moduleResolution": "node",
"checkJs": true, "checkJs": true,
@ -7,9 +8,9 @@
"strictNullChecks": true, "strictNullChecks": true,
"noImplicitAny": true, "noImplicitAny": true,
"paths": { "paths": {
"/@app/*": ["lib/app/*"], "/@app/*": ["app/*"],
"/@theme/*": ["lib/theme-default/*"], "/@theme/*": ["theme-default/*"],
"vitepress": ["lib/app/exports.js"] "vitepress": ["app/exports.js"]
} }
}, },
"include": ["."] "include": ["."]

1
lib/shim.d.ts vendored

@ -14,5 +14,6 @@ declare module "@siteData" {
declare module "@hmr" { declare module "@hmr" {
export declare const hot: { export declare const hot: {
accept(path: string, cb: (module: any) => void) accept(path: string, cb: (module: any) => void)
on(event: string, cb: (data: any) => void)
} }
} }

@ -6,7 +6,19 @@ import { Header } from './markdown/plugins/header'
import { deeplyParseHeader } from './utils/parseHeader' import { deeplyParseHeader } from './utils/parseHeader'
const debug = require('debug')('vitepress:md') const debug = require('debug')('vitepress:md')
const cache = new LRUCache<string, string>({ max: 1024 }) const cache = new LRUCache<string, MarkdownCompileResult>({ max: 1024 })
interface MarkdownCompileResult {
vueSrc: string
pageData: PageData
}
export interface PageData {
title: string
frontmatter: Record<string, any>
headers: Header[]
lastUpdated: number
}
export function createMarkdownToVueRenderFn( export function createMarkdownToVueRenderFn(
root: string, root: string,
@ -29,38 +41,36 @@ export function createMarkdownToVueRenderFn(
// TODO validate data.links? // TODO validate data.links?
// inject page data // inject page data
const additionalBlocks = injectPageData( const pageData: PageData = {
data.hoistedTags || [], title: inferTitle(frontmatter, content),
content,
frontmatter, frontmatter,
data.headers || [], headers: data.headers,
lastUpdated lastUpdated
}
const additionalBlocks = injectPageData(
data.hoistedTags || [],
pageData
) )
const vueSrc = const vueSrc =
`<template><div class="vitepress-content">${html}</div></template>\n` + `<template><div class="vitepress-content">${html}</div></template>\n` +
additionalBlocks.join('\n') additionalBlocks.join('\n')
debug(`[render] ${file} in ${Date.now() - start}ms.`) debug(`[render] ${file} in ${Date.now() - start}ms.`)
cache.set(src, vueSrc)
return vueSrc const result = { vueSrc, pageData }
cache.set(src, result)
return result
} }
} }
const scriptRE = /<\/script>/ const scriptRE = /<\/script>/
function injectPageData( function injectPageData(
tags: string[], tags: string[],
content: string, data: PageData
frontmatter: object,
headers: Header[],
lastUpdated: number
) { ) {
const code = `\nexport const __pageData = ${JSON.stringify({ const code = `\nexport const __pageData = ${JSON.stringify(data)}`
title: inferTitle(frontmatter, content),
frontmatter,
headers,
lastUpdated
})}`
const existingScriptIndex = tags.findIndex((tag) => scriptRE.test(tag)) const existingScriptIndex = tags.findIndex((tag) => scriptRE.test(tag))
if (existingScriptIndex > -1) { if (existingScriptIndex > -1) {
tags[existingScriptIndex] = tags[existingScriptIndex].replace( tags[existingScriptIndex] = tags[existingScriptIndex].replace(
@ -85,4 +95,5 @@ const inferTitle = (frontmatter: any, content: string) => {
if (match) { if (match) {
return deeplyParseHeader(match[1].trim()) return deeplyParseHeader(match[1].trim())
} }
return ''
} }

@ -44,11 +44,21 @@ function createVitePressPlugin(config: ResolvedConfig): Plugin {
debugHmr(`reloading ${file}`) debugHmr(`reloading ${file}`)
const content = await cachedRead(null, file) const content = await cachedRead(null, file)
const timestamp = Date.now() const timestamp = Date.now()
watcher.handleVueReload( const { pageData, vueSrc } = markdownToVue(content, file, timestamp)
file,
timestamp, // notify the client to update page data
markdownToVue(content, file, timestamp) watcher.send({
) type: 'custom',
id: 'vitepress:pageData',
customData: {
path: resolver.fileToRequest(file),
pageData
},
timestamp: Date.now()
})
// reload the content component
watcher.handleVueReload(file, timestamp, vueSrc)
} }
}) })
@ -90,7 +100,11 @@ function createVitePressPlugin(config: ResolvedConfig): Plugin {
await cachedRead(ctx, file) await cachedRead(ctx, file)
// let vite know this is supposed to be treated as vue file // let vite know this is supposed to be treated as vue file
ctx.vue = true ctx.vue = true
ctx.body = markdownToVue(ctx.body, file, ctx.lastModified.getTime()) ctx.body = markdownToVue(
ctx.body,
file,
ctx.lastModified.getTime()
).vueSrc
debug(ctx.url, ctx.status) debug(ctx.url, ctx.status)
return next() return next()
} }

Loading…
Cancel
Save