Skip to content

Commit 084cf43

Browse files
committed
fix(hmr): no need for server restart on theme change
1 parent 9fc8462 commit 084cf43

File tree

5 files changed

+46
-61
lines changed

5 files changed

+46
-61
lines changed

src/client/app/data.ts

Lines changed: 1 addition & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -57,18 +57,9 @@ export interface VitePressData<T = any> {
5757

5858
// site data is a singleton
5959
export const siteDataRef: Ref<SiteData> = shallowRef(
60-
(import.meta.env.PROD ? siteData : readonly(siteData)) as SiteData
60+
readonly(siteData) as SiteData
6161
)
6262

63-
// hmr
64-
if (import.meta.hot) {
65-
import.meta.hot.accept('@siteData', (m) => {
66-
if (m) {
67-
siteDataRef.value = m.default
68-
}
69-
})
70-
}
71-
7263
// per-app data
7364
export function initData(route: Route): VitePressData {
7465
const site = computed(() =>

src/node/alias.ts

Lines changed: 1 addition & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ import { createRequire } from 'node:module'
22
import { join, resolve } from 'node:path'
33
import { fileURLToPath } from 'node:url'
44
import type { Alias, AliasOptions } from 'vite'
5-
import type { SiteConfig } from './config'
65

76
const require = createRequire(import.meta.url)
87
const PKG_ROOT = resolve(fileURLToPath(import.meta.url), '../..')
@@ -20,20 +19,8 @@ export const SITE_DATA_REQUEST_PATH = '/' + SITE_DATA_ID
2019

2120
const vueRuntimePath = 'vue/dist/vue.runtime.esm-bundler.js'
2221

23-
export function resolveAliases(
24-
{ root, themeDir }: SiteConfig,
25-
ssr: boolean
26-
): AliasOptions {
27-
const paths: Record<string, string> = {
28-
'@theme': themeDir,
29-
[SITE_DATA_ID]: SITE_DATA_REQUEST_PATH
30-
}
31-
22+
export function resolveAliases(root: string, ssr: boolean): AliasOptions {
3223
const aliases: Alias[] = [
33-
...Object.keys(paths).map((p) => ({
34-
find: p,
35-
replacement: paths[p]
36-
})),
3724
{
3825
find: /^vitepress$/,
3926
replacement: join(DIST_CLIENT_PATH, '/index.js')

src/node/config.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -233,7 +233,7 @@ export async function resolveUserConfig(
233233
root: string,
234234
command: 'serve' | 'build',
235235
mode: string
236-
): Promise<[UserConfig, string | undefined, string[]]> {
236+
): Promise<[UserConfig, configPath: string | undefined, configDeps: string[]]> {
237237
// load user config
238238
const configPath = supportedConfigExtensions
239239
.flatMap((ext) => [

src/node/plugin.ts

Lines changed: 41 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import {
1414
APP_PATH,
1515
DEFAULT_THEME_PATH,
1616
DIST_CLIENT_PATH,
17+
SITE_DATA_ID,
1718
SITE_DATA_REQUEST_PATH,
1819
resolveAliases
1920
} from './alias'
@@ -43,7 +44,8 @@ declare module 'vite' {
4344
}
4445
}
4546

46-
const themeRE = /\/\.vitepress\/theme\/index\.(m|c)?(j|t)s$/
47+
const themeRE = /(?:^|\/)\.vitepress\/theme\/index\.(m|c)?(j|t)s$/
48+
const startsWithThemeRE = /^@theme(?:\/|$)/
4749
const docsearchRE = /\/@docsearch\/css\/dist\/style.css(?:$|\?)/
4850

4951
const hashRE = /\.([-\w]+)\.js$/
@@ -131,7 +133,7 @@ export async function createVitePressPlugin(
131133
config() {
132134
const baseConfig: UserConfig = {
133135
resolve: {
134-
alias: resolveAliases(siteConfig, ssr)
136+
alias: resolveAliases(siteConfig.root, ssr)
135137
},
136138
define: {
137139
__VP_LOCAL_SEARCH__: site.themeConfig?.search?.provider === 'local',
@@ -147,10 +149,7 @@ export async function createVitePressPlugin(
147149
include: [
148150
'vue',
149151
'vitepress > @vue/devtools-api',
150-
'vitepress > @vueuse/core',
151-
siteConfig.themeDir === DEFAULT_THEME_PATH
152-
? '@theme/index'
153-
: undefined
152+
'vitepress > @vueuse/core'
154153
].filter((d) => d != null),
155154
exclude: ['@docsearch/js', 'vitepress']
156155
},
@@ -170,10 +169,17 @@ export async function createVitePressPlugin(
170169
: baseConfig
171170
},
172171

173-
resolveId(id) {
174-
if (id === SITE_DATA_REQUEST_PATH) {
172+
resolveId(id, importer, resolveOptions) {
173+
if (id === SITE_DATA_ID) {
175174
return SITE_DATA_REQUEST_PATH
176175
}
176+
if (startsWithThemeRE.test(id)) {
177+
return this.resolve(
178+
siteConfig.themeDir + id.slice(6),
179+
importer,
180+
Object.assign({ skipSelf: true }, resolveOptions)
181+
)
182+
}
177183
},
178184

179185
load(id) {
@@ -260,31 +266,6 @@ export async function createVitePressPlugin(
260266
configDeps.forEach((file) => server.watcher.add(file))
261267
}
262268

263-
const onFileAddDelete = async (added: boolean, file: string) => {
264-
const relativePath = path.posix.relative(srcDir, file)
265-
// restart server on theme file creation / deletion
266-
if (themeRE.test(relativePath)) {
267-
siteConfig.logger.info(
268-
c.green(
269-
`${relativePath} ${added ? 'created' : 'deleted'}, restarting server...\n`
270-
),
271-
{ clear: true, timestamp: true }
272-
)
273-
274-
await recreateServer?.()
275-
}
276-
277-
// update pages, dynamicRoutes and rewrites on md file creation / deletion
278-
if (relativePath.endsWith('.md')) await resolvePages(siteConfig)
279-
280-
if (!added && importerMap[relativePath]) {
281-
delete importerMap[relativePath]
282-
}
283-
}
284-
server.watcher
285-
.on('add', onFileAddDelete.bind(null, true))
286-
.on('unlink', onFileAddDelete.bind(null, false))
287-
288269
// serve our index.html after vite history fallback
289270
return () => {
290271
server.middlewares.use(async (req, res, next) => {
@@ -369,8 +350,34 @@ export async function createVitePressPlugin(
369350
}
370351
},
371352

372-
async hotUpdate({ file }) {
353+
async hotUpdate({ file, type }) {
373354
if (this.environment.name !== 'client') return
355+
const relativePath = path.posix.relative(srcDir, file)
356+
357+
if (themeRE.test(relativePath) && type !== 'update') {
358+
siteConfig.themeDir =
359+
type === 'create' ? path.posix.dirname(file) : DEFAULT_THEME_PATH
360+
siteConfig.logger.info(c.green('page reload ') + c.dim(relativePath), {
361+
clear: true,
362+
timestamp: true
363+
})
364+
this.environment.moduleGraph.invalidateAll()
365+
this.environment.hot.send({
366+
type: 'full-reload',
367+
path: '*',
368+
triggeredBy: path.resolve(config.root, file)
369+
})
370+
return []
371+
}
372+
373+
// update pages, dynamicRoutes and rewrites on md file creation / deletion
374+
if (file.endsWith('.md') && type !== 'update') {
375+
await resolvePages(siteConfig)
376+
}
377+
378+
if (type === 'delete') {
379+
delete importerMap[relativePath]
380+
}
374381

375382
if (
376383
file === configPath ||

src/node/plugins/localSearchPlugin.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ export async function localSearchPlugin(
3030
name: 'vitepress:local-search',
3131
resolveId(id) {
3232
if (id.startsWith(LOCAL_SEARCH_INDEX_ID)) {
33-
return `/${id}`
33+
return LOCAL_SEARCH_INDEX_REQUEST_PATH
3434
}
3535
},
3636
load(id) {
@@ -183,7 +183,7 @@ export async function localSearchPlugin(
183183
records.push(
184184
`${JSON.stringify(
185185
locale
186-
)}: () => import('@localSearchIndex${locale}')`
186+
)}: () => import('${LOCAL_SEARCH_INDEX_ID}${locale}')`
187187
)
188188
}
189189
return `export default {${records.join(',')}}`

0 commit comments

Comments
 (0)