methanol 0.0.7 → 0.0.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -44,6 +44,11 @@ export default () => ({
44
44
  // optional: code highlighting (Starry Night)
45
45
  starryNight: false,
46
46
 
47
+ // optional: site metadata
48
+ site: {
49
+ base: '/docs/'
50
+ },
51
+
47
52
  // optional: theme sources
48
53
  theme: {
49
54
  sources: {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "methanol",
3
- "version": "0.0.7",
3
+ "version": "0.0.8",
4
4
  "description": "Static site generator powered by rEFui and MDX",
5
5
  "main": "./index.js",
6
6
  "type": "module",
package/src/assets.js CHANGED
@@ -27,4 +27,4 @@ const __dirname = dirname(__filename)
27
27
 
28
28
  export const INJECT_SCRIPT = readFileSync(resolve(__dirname, './virtual-module/inject.js'), 'utf-8')
29
29
  export const LOADER_SCRIPT = readFileSync(resolve(__dirname, './virtual-module/loader.js'), 'utf-8')
30
- export const PAGEFIND_SCRIPT = readFileSync(resolve(__dirname, './virtual-module/pagefind.js'), 'utf-8')
30
+ export const PAGEFIND_LOADER_SCRIPT = readFileSync(resolve(__dirname, './virtual-module/pagefind-loader.js'), 'utf-8')
@@ -61,6 +61,7 @@ const collectHtmlFiles = async (dir, basePath = '') => {
61
61
  }
62
62
 
63
63
  export const buildHtmlEntries = async () => {
64
+ await resolveUserViteConfig('build') // Prepare `base`
64
65
  if (state.INTERMEDIATE_DIR) {
65
66
  await rm(state.INTERMEDIATE_DIR, { recursive: true, force: true })
66
67
  await ensureDir(state.INTERMEDIATE_DIR)
@@ -174,7 +175,7 @@ export const runViteBuild = async (entry, htmlCache) => {
174
175
  const baseConfig = {
175
176
  configFile: false,
176
177
  root: state.PAGES_DIR,
177
- base: '/',
178
+ appType: 'mpa',
178
179
  publicDir: state.STATIC_DIR === false ? false : state.STATIC_DIR,
179
180
  build: {
180
181
  outDir: state.DIST_DIR,
package/src/config.js CHANGED
@@ -27,6 +27,7 @@ import { cli, state } from './state.js'
27
27
  import { HTMLRenderer } from './renderer.js'
28
28
  import { rewindEnv } from './components.js'
29
29
  import { env as createEnv } from './rewind.js'
30
+ import { cached, cachedStr } from './utils.js'
30
31
  import defaultTheme from '../themes/default/index.js'
31
32
 
32
33
  const CONFIG_FILENAMES = [
@@ -79,6 +80,52 @@ const resolveThemePublicDir = (root, value) => {
79
80
  return isAbsolute(value) ? value : resolve(root, value)
80
81
  }
81
82
 
83
+ let devBaseWarningShown = false
84
+
85
+ const normalizeSiteBase = (value) => {
86
+ if (value == null) return null
87
+ if (typeof value !== 'string') return null
88
+ const trimmed = value.trim()
89
+ if (!trimmed || trimmed === './') return '/'
90
+ if (trimmed.startsWith('http://') || trimmed.startsWith('https://')) {
91
+ return trimmed
92
+ }
93
+ let base = trimmed
94
+ if (!base.startsWith('/')) {
95
+ base = `/${base}`
96
+ }
97
+ if (!base.endsWith('/')) {
98
+ base = `${base}/`
99
+ }
100
+ return base
101
+ }
102
+
103
+ const normalizeViteBase = (value) => {
104
+ if (!value || value === '/' || value === './') return '/'
105
+ if (typeof value !== 'string') return '/'
106
+ let base = value.trim()
107
+ if (!base || base === './') return '/'
108
+ if (base.startsWith('http://') || base.startsWith('https://')) {
109
+ try {
110
+ base = new URL(base).pathname
111
+ } catch {
112
+ return '/'
113
+ }
114
+ }
115
+ if (!base.startsWith('/')) return '/'
116
+ if (!base.endsWith('/')) {
117
+ base = `${base}/`
118
+ }
119
+ return base
120
+ }
121
+
122
+ const warnDevBase = (value) => {
123
+ if (devBaseWarningShown) return
124
+ devBaseWarningShown = true
125
+ const label = value ? ` (received "${value}")` : ''
126
+ console.warn(`Methanol: \`base\`${label} is disabled in dev mode due to module resolution inconsistencies in Vite. Using "/".\n`)
127
+ }
128
+
82
129
  const hasOwn = (obj, key) => Object.prototype.hasOwnProperty.call(obj || {}, key)
83
130
  const normalizeSources = (value, root) => {
84
131
  if (!value) return []
@@ -216,11 +263,20 @@ export const applyConfig = async (config, mode) => {
216
263
  state.ROOT_DIR = root
217
264
  const configSiteName = cli.CLI_SITE_NAME ?? config.site?.name ?? null
218
265
  state.SITE_NAME = configSiteName || basename(root) || 'Methanol Site'
219
- state.USER_SITE = config.site && typeof config.site === 'object' ? { ...config.site } : null
266
+ const userSite = config.site && typeof config.site === 'object' ? { ...config.site } : null
267
+ const siteBase = normalizeSiteBase(userSite?.base)
268
+ state.SITE_BASE = siteBase
269
+ if (userSite) {
270
+ if (siteBase == null) {
271
+ delete userSite.base
272
+ } else {
273
+ userSite.base = siteBase
274
+ }
275
+ }
276
+ state.USER_SITE = userSite
220
277
  if (mode) {
221
278
  state.CURRENT_MODE = mode
222
279
  }
223
- // config.paths / config.dirs are intentionally ignored (deprecated)
224
280
 
225
281
  const pagesDirValue = cli.CLI_PAGES_DIR || config.pagesDir
226
282
  const componentsDirValue = cli.CLI_COMPONENTS_DIR || config.componentsDir
@@ -409,14 +465,76 @@ export const resolveUserViteConfig = async (command) => {
409
465
  }
410
466
  const themeConfig = await resolveConfig(state.USER_THEME.vite)
411
467
  const userConfig = await resolveConfig(state.USER_VITE_CONFIG)
468
+ const userHasBase = userConfig && hasOwn(userConfig, 'base')
412
469
  if (!themeConfig && !userConfig) {
413
- state.RESOLVED_VITE_CONFIG = null
414
- return null
470
+ if (state.SITE_BASE) {
471
+ state.RESOLVED_VITE_CONFIG = { base: state.SITE_BASE }
472
+ } else {
473
+ state.RESOLVED_VITE_CONFIG = null
474
+ }
475
+ state.VITE_BASE = normalizeViteBase(state.RESOLVED_VITE_CONFIG?.base || state.SITE_BASE || '/')
476
+ if (command === 'serve') {
477
+ if (state.VITE_BASE !== '/' || (state.SITE_BASE && state.SITE_BASE !== '/')) {
478
+ warnDevBase(state.RESOLVED_VITE_CONFIG?.base || state.SITE_BASE || '')
479
+ }
480
+ if (state.RESOLVED_VITE_CONFIG) {
481
+ state.RESOLVED_VITE_CONFIG.base = '/'
482
+ }
483
+ state.VITE_BASE = '/'
484
+ }
485
+ return state.RESOLVED_VITE_CONFIG
415
486
  }
416
487
  state.RESOLVED_VITE_CONFIG = themeConfig
417
488
  ? userConfig
418
489
  ? mergeConfig(themeConfig, userConfig)
419
490
  : themeConfig
420
491
  : userConfig
492
+ if (state.SITE_BASE && !userHasBase) {
493
+ state.RESOLVED_VITE_CONFIG.base = state.SITE_BASE
494
+ }
495
+ state.VITE_BASE = normalizeViteBase(state.RESOLVED_VITE_CONFIG?.base || state.SITE_BASE || '/')
496
+ if (command === 'serve') {
497
+ if (state.VITE_BASE !== '/' || (state.SITE_BASE && state.SITE_BASE !== '/')) {
498
+ warnDevBase(state.RESOLVED_VITE_CONFIG?.base || state.SITE_BASE || '')
499
+ }
500
+ state.RESOLVED_VITE_CONFIG.base = '/'
501
+ state.VITE_BASE = '/'
502
+ }
421
503
  return state.RESOLVED_VITE_CONFIG
422
504
  }
505
+
506
+ export const resolveBasePrefix = cached(() => {
507
+ const value = state.VITE_BASE || state.SITE_BASE || '/'
508
+ if (!value || value === '/' || value === './') return ''
509
+ if (typeof value !== 'string') return ''
510
+ let base = value.trim()
511
+ if (!base || base === '/' || base === './') return ''
512
+ if (base.startsWith('http://') || base.startsWith('https://')) {
513
+ try {
514
+ base = new URL(base).pathname
515
+ } catch {
516
+ return ''
517
+ }
518
+ }
519
+ if (!base.startsWith('/')) return ''
520
+ if (base.endsWith('/')) base = base.slice(0, -1)
521
+ return base
522
+ })
523
+
524
+ export const withBase = cachedStr((value) => {
525
+ if (!value || typeof value !== 'string') return value
526
+ if (
527
+ value.startsWith('http://') ||
528
+ value.startsWith('https://') ||
529
+ value.startsWith('//') ||
530
+ value.startsWith('data:') ||
531
+ value.startsWith('mailto:') ||
532
+ value.startsWith('#')
533
+ ) {
534
+ return value
535
+ }
536
+ if (!value.startsWith('/')) return value
537
+ const prefix = resolveBasePrefix()
538
+ if (!prefix || value.startsWith(`${prefix}/`)) return value
539
+ return `${prefix}${value}`
540
+ })
package/src/dev-server.js CHANGED
@@ -49,6 +49,7 @@ export const runViteDev = async () => {
49
49
  const baseConfig = {
50
50
  configFile: false,
51
51
  root: state.PAGES_DIR,
52
+ appType: 'mpa',
52
53
  publicDir: state.STATIC_DIR === false ? false : state.STATIC_DIR,
53
54
  server: {
54
55
  fs: {
@@ -66,6 +67,8 @@ export const runViteDev = async () => {
66
67
  }
67
68
  const userConfig = await resolveUserViteConfig('serve')
68
69
  const finalConfig = userConfig ? mergeConfig(baseConfig, userConfig) : baseConfig
70
+ const devBase = state.VITE_BASE || '/'
71
+ const devBasePrefix = devBase === '/' ? '' : devBase.slice(0, -1)
69
72
  if (state.STATIC_DIR !== false && state.MERGED_ASSETS_DIR) {
70
73
  await preparePublicAssets({
71
74
  themeDir: state.THEME_ASSETS_DIR,
@@ -169,7 +172,14 @@ export const runViteDev = async () => {
169
172
  }
170
173
 
171
174
  const resolvePageFile = (routePath) => {
172
- const name = routePath === '/' ? 'index' : routePath.slice(1)
175
+ let name = 'index'
176
+ if (routePath && routePath !== '/') {
177
+ if (routePath.endsWith('/')) {
178
+ name = `${routePath.slice(1, -1)}/index`
179
+ } else {
180
+ name = routePath.slice(1)
181
+ }
182
+ }
173
183
  const mdxPath = resolve(state.PAGES_DIR, `${name}.mdx`)
174
184
  if (existsSync(mdxPath)) return mdxPath
175
185
  const mdPath = resolve(state.PAGES_DIR, `${name}.md`)
@@ -181,6 +191,8 @@ export const runViteDev = async () => {
181
191
  const candidates = []
182
192
  if (pathname === '/' || pathname === '') {
183
193
  candidates.push('/index.html')
194
+ } else if (pathname.endsWith('/')) {
195
+ candidates.push(`${pathname}index.html`)
184
196
  } else if (pathname.endsWith('.html')) {
185
197
  candidates.push(pathname)
186
198
  } else {
@@ -196,7 +208,7 @@ export const runViteDev = async () => {
196
208
  if (hasMdx) return false
197
209
  const baseName = basename(relativePath, '.html')
198
210
  if (baseName.startsWith('_') || baseName.startsWith('.')) return false
199
- const excludedDirs = pagesContext?.excludedDirs
211
+ const excludedDirs = pagesContext.excludedDirs
200
212
  if (excludedDirs?.size) {
201
213
  const dir = relativePath.split('/').slice(0, -1).join('/')
202
214
  for (const excludedDir of excludedDirs) {
@@ -206,9 +218,9 @@ export const runViteDev = async () => {
206
218
  }
207
219
  }
208
220
  }
209
- const excludedRoutes = pagesContext?.excludedRoutes
221
+ const excludedRoutes = pagesContext.excludedRoutes
210
222
  if (excludedRoutes?.has(requestedPath)) return false
211
- const excludedDirPaths = pagesContext?.excludedDirPaths
223
+ const excludedDirPaths = pagesContext.excludedDirPaths
212
224
  if (excludedDirPaths?.size) {
213
225
  for (const dirPath of excludedDirPaths) {
214
226
  if (requestedPath === dirPath || requestedPath.startsWith(`${dirPath}/`)) {
@@ -223,9 +235,6 @@ export const runViteDev = async () => {
223
235
  if (!req.url || req.method !== 'GET') {
224
236
  return next()
225
237
  }
226
- if (req.url.startsWith('/@vite') || req.url.startsWith('/__vite')) {
227
- return next()
228
- }
229
238
 
230
239
  const url = new URL(req.url, 'http://methanol')
231
240
  let pathname = url.pathname
@@ -233,7 +242,20 @@ export const runViteDev = async () => {
233
242
  pathname = decodeURIComponent(pathname)
234
243
  } catch {}
235
244
  const originalPathname = pathname
236
- const hasTrailingSlash = originalPathname.endsWith('/') && originalPathname !== '/'
245
+ if (devBase !== '/') {
246
+ const baseNoSlash = devBasePrefix
247
+ if (originalPathname === baseNoSlash) {
248
+ pathname = '/'
249
+ } else if (originalPathname.startsWith(devBase)) {
250
+ pathname = originalPathname.slice(devBase.length - 1)
251
+ } else {
252
+ return next()
253
+ }
254
+ }
255
+
256
+ if (pathname.startsWith('/@vite') || pathname.startsWith('/__vite')) {
257
+ return next()
258
+ }
237
259
 
238
260
  if (pathname.includes('.') && !pathname.endsWith('.html')) {
239
261
  return next()
@@ -251,15 +273,11 @@ export const runViteDev = async () => {
251
273
  routePath = '/'
252
274
  }
253
275
  }
254
- if (routePath.endsWith('/') && routePath !== '/') {
255
- routePath = routePath.slice(0, -1)
256
- }
257
-
258
276
  const requestedPath = routePath
259
277
  const isExcludedPath = () => {
260
- const excludedRoutes = pagesContext?.excludedRoutes
278
+ const excludedRoutes = pagesContext.excludedRoutes
261
279
  if (excludedRoutes?.has(requestedPath)) return true
262
- const excludedDirPaths = pagesContext?.excludedDirPaths
280
+ const excludedDirPaths = pagesContext.excludedDirPaths
263
281
  if (excludedDirPaths?.size) {
264
282
  for (const dirPath of excludedDirPaths) {
265
283
  if (requestedPath === dirPath || requestedPath.startsWith(`${dirPath}/`)) {
@@ -269,10 +287,8 @@ export const runViteDev = async () => {
269
287
  }
270
288
  return false
271
289
  }
272
- const notFoundPage = pagesContext?.pagesByRoute?.get('/404') ?? null
273
- const pageMeta = hasTrailingSlash
274
- ? (pagesContext?.pagesByRouteIndex?.get(requestedPath) ?? pagesContext?.pagesByRoute?.get(requestedPath) ?? null)
275
- : (pagesContext?.pagesByRoute?.get(requestedPath) ?? null)
290
+ const notFoundPage = pagesContext.pagesByRoute.get('/404')
291
+ let pageMeta = pagesContext.pagesByRoute.get(requestedPath)
276
292
  let filePath = pageMeta?.filePath || resolvePageFile(requestedPath)
277
293
  const hasMdx = Boolean(pageMeta) || existsSync(filePath)
278
294
  let status = 200
@@ -291,7 +307,9 @@ export const runViteDev = async () => {
291
307
  }
292
308
  try {
293
309
  const html = await readFile(candidate, 'utf-8')
294
- const candidateUrl = `/${relativePath}`
310
+ const candidateUrl = devBasePrefix
311
+ ? `${devBasePrefix}/${relativePath}`
312
+ : `/${relativePath}`
295
313
  const transformed = await server.transformIndexHtml(candidateUrl, html)
296
314
  res.statusCode = 200
297
315
  res.setHeader('Content-Type', 'text/html')
@@ -338,6 +356,8 @@ export const runViteDev = async () => {
338
356
  return
339
357
  }
340
358
 
359
+ pageMeta ??= pagesContext.getPageByRoute(renderRoutePath, { filePath })
360
+
341
361
  const html = await renderHtml({
342
362
  routePath: renderRoutePath,
343
363
  filePath,
@@ -374,16 +394,18 @@ export const runViteDev = async () => {
374
394
  await server.listen()
375
395
  server.printUrls()
376
396
 
377
- const invalidateRewindInject = () => {
378
- const registryModule = server.moduleGraph.getModuleById('\0/.methanol_virtual_module/registry.js')
379
- if (registryModule) {
380
- server.moduleGraph.invalidateModule(registryModule)
381
- }
382
- const injectModule = server.moduleGraph.getModuleById('\0/.methanol_virtual_module/inject.js')
383
- if (injectModule) {
384
- server.moduleGraph.invalidateModule(injectModule)
397
+ const _invalidate = (id) => {
398
+ const _module = server.moduleGraph.getModuleById(id)
399
+ if (_module) {
400
+ server.moduleGraph.invalidateModule(_module)
385
401
  }
386
402
  }
403
+ const invalidateRewindInject = () => {
404
+ _invalidate('\0/.methanol_virtual_module/registry.js')
405
+ _invalidate('\0methanol:registry')
406
+ _invalidate('\0/.methanol_virtual_module/inject.js')
407
+ _invalidate('\0methanol:inject')
408
+ }
387
409
 
388
410
  let queue = Promise.resolve()
389
411
  const enqueue = (task) => {
package/src/main.js CHANGED
@@ -32,7 +32,7 @@ const printBanner = async () => {
32
32
  const pkgUrl = new URL('../package.json', import.meta.url)
33
33
  const raw = await readFile(pkgUrl, 'utf-8')
34
34
  const pkg = JSON.parse(raw)
35
- const version = pkg?.version ? `v${pkg.version}` : ''
35
+ const version = `v${pkg.version}`
36
36
  const isTty = Boolean(process.stdout && process.stdout.isTTY)
37
37
  const label = `Methanol ${version}`.trim()
38
38
  if (isTty) {
@@ -63,6 +63,7 @@ const main = async () => {
63
63
  const config = await loadUserConfig(mode, cli.CLI_CONFIG_PATH)
64
64
  await applyConfig(config, mode)
65
65
  const userSite = state.USER_SITE || {}
66
+ const siteBase = state.VITE_BASE ?? userSite.base ?? null
66
67
  const hookContext = {
67
68
  mode,
68
69
  root: state.ROOT_DIR,
@@ -73,6 +74,7 @@ const main = async () => {
73
74
  HTMLRenderer,
74
75
  site: {
75
76
  ...userSite,
77
+ base: siteBase,
76
78
  name: state.SITE_NAME,
77
79
  root: state.ROOT_DIR,
78
80
  pagesDir: state.PAGES_DIR,
package/src/mdx.js CHANGED
@@ -32,12 +32,13 @@ import { pathToFileURL } from 'url'
32
32
  import { existsSync } from 'fs'
33
33
  import { resolve, dirname, basename, relative } from 'path'
34
34
  import { state } from './state.js'
35
- import { resolveUserMdxConfig } from './config.js'
35
+ import { resolveUserMdxConfig, withBase } from './config.js'
36
36
  import { methanolCtx } from './rehype-plugins/methanol-ctx.js'
37
37
  import { linkResolve } from './rehype-plugins/link-resolve.js'
38
38
 
39
39
  // Workaround for Vite: it doesn't support resolving module/virtual modules in script src in dev mode
40
- const RWND_INJECT = HTMLRenderer.rawHTML`<script type="module" src="/.methanol_virtual_module/inject.js"></script>`
40
+ const resolveRewindInject = () =>
41
+ HTMLRenderer.rawHTML(`<script type="module" src="${withBase('/.methanol_virtual_module/inject.js')}"></script>`)
41
42
  const RWND_FALLBACK = HTMLRenderer.rawHTML`<script>
42
43
  if (!window.$$rwnd) {
43
44
  const l = []
@@ -59,12 +60,12 @@ const resolveUserHeadAssets = () => {
59
60
  const pagesDir = state.PAGES_DIR
60
61
  if (!pagesDir) return assets
61
62
  if (existsSync(resolve(pagesDir, 'style.css'))) {
62
- assets.push(HTMLRenderer.c('link', { rel: 'stylesheet', href: '/style.css' }))
63
+ assets.push(HTMLRenderer.c('link', { rel: 'stylesheet', href: withBase('/style.css') }))
63
64
  }
64
65
  if (existsSync(resolve(pagesDir, 'index.js'))) {
65
- assets.push(HTMLRenderer.c('script', { type: 'module', src: '/index.js' }))
66
+ assets.push(HTMLRenderer.c('script', { type: 'module', src: withBase('/index.js') }))
66
67
  } else if (existsSync(resolve(pagesDir, 'index.ts'))) {
67
- assets.push(HTMLRenderer.c('script', { type: 'module', src: '/index.ts' }))
68
+ assets.push(HTMLRenderer.c('script', { type: 'module', src: withBase('/index.ts') }))
68
69
  }
69
70
  if (state.CURRENT_MODE === 'production') {
70
71
  cachedHeadAssets = assets
@@ -73,17 +74,17 @@ const resolveUserHeadAssets = () => {
73
74
  }
74
75
 
75
76
  const resolvePageAssetUrl = (page, filePath) => {
76
- const root = page?.source === 'theme' && state.THEME_PAGES_DIR
77
+ const root = page.source === 'theme' && state.THEME_PAGES_DIR
77
78
  ? state.THEME_PAGES_DIR
78
79
  : state.PAGES_DIR
79
80
  if (!root) return null
80
81
  const relPath = relative(root, filePath).replace(/\\/g, '/')
81
82
  if (!relPath || relPath.startsWith('..')) return null
82
- return `/${relPath}`
83
+ return withBase(`/${relPath}`)
83
84
  }
84
85
 
85
86
  const resolvePageHeadAssets = (page) => {
86
- if (!page?.filePath) return []
87
+ if (!page.filePath) return []
87
88
  const baseDir = dirname(page.filePath)
88
89
  const baseName = basename(page.filePath).replace(/\.(mdx|md)$/, '')
89
90
  const pagesRoot = state.PAGES_DIR ? resolve(state.PAGES_DIR) : null
@@ -138,26 +139,28 @@ export const buildPageContext = ({
138
139
  lazyPagesTree = false
139
140
  }) => {
140
141
  const page = pageMeta
141
- const language = pagesContext?.getLanguageForRoute ? pagesContext.getLanguageForRoute(routePath) : null
142
- const getSiblings = pagesContext?.getSiblings
143
- ? () => pagesContext.getSiblings(routePath, page?.filePath || filePath)
142
+ const language = pagesContext.getLanguageForRoute ? pagesContext.getLanguageForRoute(routePath) : null
143
+ const getSiblings = pagesContext.getSiblings
144
+ ? () => pagesContext.getSiblings(routePath, page.filePath || filePath)
144
145
  : null
145
146
  if (page && getSiblings && page.getSiblings !== getSiblings) {
146
147
  page.getSiblings = getSiblings
147
148
  }
148
149
  const ctx = {
149
150
  routePath,
151
+ routeHref: withBase(routePath),
150
152
  filePath,
151
153
  page,
152
- pages: pagesContext?.pages || [],
153
- pagesByRoute: pagesContext?.pagesByRoute || new Map(),
154
- languages: pagesContext?.languages || [],
154
+ pages: pagesContext.pages || [],
155
+ pagesByRoute: pagesContext.pagesByRoute || new Map(),
156
+ languages: pagesContext.languages || [],
155
157
  language,
156
- site: pagesContext?.site || null,
157
- getSiblings
158
+ site: pagesContext.site || null,
159
+ getSiblings,
160
+ withBase
158
161
  }
159
162
  const resolvePagesTree = () =>
160
- pagesContext?.getPagesTree ? pagesContext.getPagesTree(routePath) : pagesContext?.pagesTree || []
163
+ pagesContext.getPagesTree ? pagesContext.getPagesTree(routePath) : pagesContext.pagesTree || []
161
164
  if (lazyPagesTree) {
162
165
  let cachedTree = null
163
166
  let hasTree = false
@@ -286,7 +289,7 @@ const resolveMdxConfigForPage = async (frontmatter) => {
286
289
  }
287
290
 
288
291
  export const compileMdx = async ({ content, filePath, ctx }) => {
289
- const mdxConfig = await resolveMdxConfigForPage(ctx?.page?.frontmatter)
292
+ const mdxConfig = await resolveMdxConfigForPage(ctx.page.frontmatter)
290
293
  const runtimeFactory = mdxConfig.development ? JSXDevFactory : JSXFactory
291
294
  const compiled = await compile({ value: content, path: filePath }, mdxConfig)
292
295
 
@@ -322,15 +325,15 @@ export const compilePageMdx = async (page, pagesContext, options = {}) => {
322
325
  const nextTitle = findTitleFromToc(page.toc) || page.title
323
326
  if (nextTitle !== page.title) {
324
327
  page.title = nextTitle
325
- if (typeof pagesContext?.refreshPagesTree === 'function') {
328
+ if (typeof pagesContext.refreshPagesTree === 'function') {
326
329
  pagesContext.refreshPagesTree()
327
330
  }
328
331
  }
329
332
  }
330
- if (typeof pagesContext?.setDerivedTitle === 'function') {
333
+ if (typeof pagesContext.setDerivedTitle === 'function') {
331
334
  pagesContext.setDerivedTitle(page.filePath, shouldUseTocTitle ? page.title : null, page.toc)
332
335
  }
333
- if (ctx && refreshPagesTree && pagesContext?.getPagesTree) {
336
+ if (ctx && refreshPagesTree && pagesContext.getPagesTree) {
334
337
  ctx.pagesTree = pagesContext.getPagesTree(activeCtx.routePath)
335
338
  }
336
339
  }
@@ -340,14 +343,8 @@ export const renderHtml = async ({
340
343
  filePath,
341
344
  components,
342
345
  pagesContext,
343
- pageMeta: explicitPageMeta = null
346
+ pageMeta
344
347
  }) => {
345
- const pageMeta =
346
- explicitPageMeta ||
347
- (pagesContext.getPageByRoute
348
- ? pagesContext.getPageByRoute(routePath, { filePath })
349
- : pagesContext.pagesByRoute.get(routePath))
350
-
351
348
  const ctx = buildPageContext({
352
349
  routePath,
353
350
  filePath,
@@ -359,7 +356,7 @@ export const renderHtml = async ({
359
356
  const [Head, Outlet] = createPortal()
360
357
  const ExtraHead = () => {
361
358
  return [
362
- RWND_INJECT,
359
+ resolveRewindInject(),
363
360
  ...resolveUserHeadAssets(),
364
361
  ...resolvePageHeadAssets(pageMeta),
365
362
  Outlet(),
@@ -367,9 +364,9 @@ export const renderHtml = async ({
367
364
  ]
368
365
  }
369
366
 
370
- const mdxComponent = pageMeta?.mdxComponent
367
+ const mdxComponent = pageMeta.mdxComponent
371
368
 
372
- const Page = ({ components: extraComponents, ...props }, ...children) =>
369
+ const PageContent = ({ components: extraComponents, ...props }, ...children) =>
373
370
  mdxComponent({
374
371
  children,
375
372
  ...props,
@@ -394,7 +391,9 @@ export const renderHtml = async ({
394
391
  () =>
395
392
  template({
396
393
  ctx,
397
- Page,
394
+ page: ctx.page,
395
+ withBase,
396
+ PageContent,
398
397
  ExtraHead,
399
398
  HTMLRenderer,
400
399
  components