methanol 0.0.6 → 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 +5 -0
- package/package.json +1 -1
- package/src/assets.js +1 -1
- package/src/build-system.js +2 -1
- package/src/config.js +122 -4
- package/src/dev-server.js +49 -27
- package/src/main.js +3 -1
- package/src/mdx.js +31 -32
- package/src/pages.js +89 -77
- package/src/preview-server.js +1 -1
- package/src/public-assets.js +6 -6
- package/src/rehype-plugins/link-resolve.js +0 -1
- package/src/state.js +2 -0
- package/src/utils.js +9 -0
- package/src/virtual-module/inject.js +3 -4
- package/src/virtual-module/{pagefind.js → pagefind-loader.js} +23 -2
- package/src/vite-plugins.js +50 -6
- package/themes/default/components/ButtonGroup.jsx +38 -0
- package/themes/default/components/LinkButton.jsx +37 -0
- package/themes/default/components/ThemeSearchBox.client.jsx +9 -2
- package/themes/default/page.jsx +57 -28
- package/themes/default/sources/style.css +109 -1
package/README.md
CHANGED
package/package.json
CHANGED
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
|
|
30
|
+
export const PAGEFIND_LOADER_SCRIPT = readFileSync(resolve(__dirname, './virtual-module/pagefind-loader.js'), 'utf-8')
|
package/src/build-system.js
CHANGED
|
@@ -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
|
-
|
|
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
|
-
|
|
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.
|
|
414
|
-
|
|
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
|
-
|
|
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
|
|
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
|
|
221
|
+
const excludedRoutes = pagesContext.excludedRoutes
|
|
210
222
|
if (excludedRoutes?.has(requestedPath)) return false
|
|
211
|
-
const excludedDirPaths = pagesContext
|
|
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
|
-
|
|
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
|
|
278
|
+
const excludedRoutes = pagesContext.excludedRoutes
|
|
261
279
|
if (excludedRoutes?.has(requestedPath)) return true
|
|
262
|
-
const excludedDirPaths = pagesContext
|
|
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
|
|
273
|
-
|
|
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 =
|
|
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
|
|
378
|
-
const
|
|
379
|
-
if (
|
|
380
|
-
server.moduleGraph.invalidateModule(
|
|
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 =
|
|
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
|
|
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
|
|
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
|
|
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
|
|
142
|
-
const getSiblings = pagesContext
|
|
143
|
-
? () => pagesContext.getSiblings(routePath, page
|
|
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
|
|
153
|
-
pagesByRoute: pagesContext
|
|
154
|
-
languages: pagesContext
|
|
154
|
+
pages: pagesContext.pages || [],
|
|
155
|
+
pagesByRoute: pagesContext.pagesByRoute || new Map(),
|
|
156
|
+
languages: pagesContext.languages || [],
|
|
155
157
|
language,
|
|
156
|
-
site: pagesContext
|
|
157
|
-
getSiblings
|
|
158
|
+
site: pagesContext.site || null,
|
|
159
|
+
getSiblings,
|
|
160
|
+
withBase
|
|
158
161
|
}
|
|
159
162
|
const resolvePagesTree = () =>
|
|
160
|
-
pagesContext
|
|
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
|
|
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
|
|
328
|
+
if (typeof pagesContext.refreshPagesTree === 'function') {
|
|
326
329
|
pagesContext.refreshPagesTree()
|
|
327
330
|
}
|
|
328
331
|
}
|
|
329
332
|
}
|
|
330
|
-
if (typeof pagesContext
|
|
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
|
|
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
|
|
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
|
-
|
|
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
|
|
367
|
+
const mdxComponent = pageMeta.mdxComponent
|
|
371
368
|
|
|
372
|
-
const
|
|
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
|
-
|
|
394
|
+
page: ctx.page,
|
|
395
|
+
withBase,
|
|
396
|
+
PageContent,
|
|
398
397
|
ExtraHead,
|
|
399
398
|
HTMLRenderer,
|
|
400
399
|
components
|