methanol 0.0.8 → 0.0.10
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 +3 -0
- package/index.js +7 -2
- package/package.json +9 -3
- package/src/build-system.js +50 -8
- package/src/client/sw.js +751 -0
- package/src/{assets.js → client/virtual-module/assets.js} +7 -3
- package/src/{virtual-module → client/virtual-module}/inject.js +1 -0
- package/src/{virtual-module → client/virtual-module}/loader.js +5 -5
- package/src/{virtual-module → client/virtual-module}/pagefind-loader.js +1 -1
- package/src/client/virtual-module/pwa-inject.js +25 -0
- package/src/components.js +5 -5
- package/src/config.js +38 -7
- package/src/dev-server.js +64 -66
- package/src/logger.js +84 -0
- package/src/main.js +11 -0
- package/src/mdx.js +33 -38
- package/src/pagefind.js +16 -5
- package/src/pages.js +61 -51
- package/src/public-assets.js +1 -1
- package/src/{rewind.js → reframe.js} +1 -1
- package/src/rehype-plugins/link-resolve.js +2 -2
- package/src/stage-logger.js +10 -6
- package/src/state.js +31 -4
- package/src/utils.js +23 -1
- package/src/vite-plugins.js +17 -4
- package/themes/default/components/ThemeSearchBox.client.jsx +120 -11
- package/themes/default/index.js +2 -2
- package/themes/default/pages/404.mdx +4 -0
- package/themes/default/pages/index.mdx +7 -9
- package/themes/default/pages/offline.mdx +11 -0
- package/themes/default/sources/style.css +248 -169
- package/themes/default/src/nav-tree.jsx +112 -0
- package/themes/default/{page.jsx → src/page.jsx} +10 -55
- /package/themes/default/{heading.jsx → src/heading.jsx} +0 -0
package/src/main.js
CHANGED
|
@@ -26,6 +26,7 @@ import { runVitePreview } from './preview-server.js'
|
|
|
26
26
|
import { cli, state } from './state.js'
|
|
27
27
|
import { HTMLRenderer } from './renderer.js'
|
|
28
28
|
import { readFile } from 'fs/promises'
|
|
29
|
+
import { style, logger } from './logger.js'
|
|
29
30
|
|
|
30
31
|
const printBanner = async () => {
|
|
31
32
|
try {
|
|
@@ -107,6 +108,7 @@ const main = async () => {
|
|
|
107
108
|
return
|
|
108
109
|
}
|
|
109
110
|
if (isBuild) {
|
|
111
|
+
const startTime = performance.now()
|
|
110
112
|
await runHooks(state.USER_PRE_BUILD_HOOKS)
|
|
111
113
|
await runHooks(state.THEME_PRE_BUILD_HOOKS)
|
|
112
114
|
const { entry, htmlCache, pagesContext } = await buildHtmlEntries()
|
|
@@ -129,6 +131,15 @@ const main = async () => {
|
|
|
129
131
|
}
|
|
130
132
|
await runHooks(state.THEME_POST_BUILD_HOOKS, buildContext)
|
|
131
133
|
await runHooks(state.USER_POST_BUILD_HOOKS, buildContext)
|
|
134
|
+
const endTime = performance.now()
|
|
135
|
+
const duration = endTime - startTime
|
|
136
|
+
const timeString = duration > 1000 ? `${(duration / 1000).toFixed(2)}s` : `${Math.round(duration)}ms`
|
|
137
|
+
const totalPages = pagesContext?.pages?.length ?? 0
|
|
138
|
+
const pageLabel = totalPages === 1 ? 'page' : 'pages'
|
|
139
|
+
console.log()
|
|
140
|
+
logger.success(
|
|
141
|
+
`Build complete! Processed ${style.bold(totalPages)} ${pageLabel} in ${style.bold(timeString)}.`
|
|
142
|
+
)
|
|
132
143
|
return
|
|
133
144
|
}
|
|
134
145
|
cli.showHelp()
|
package/src/mdx.js
CHANGED
|
@@ -25,6 +25,7 @@ import rehypeSlug from 'rehype-slug'
|
|
|
25
25
|
import extractToc from '@stefanprobst/rehype-extract-toc'
|
|
26
26
|
import withTocExport from '@stefanprobst/rehype-extract-toc/mdx'
|
|
27
27
|
import rehypeStarryNight from 'rehype-starry-night'
|
|
28
|
+
import remarkGfm from 'remark-gfm'
|
|
28
29
|
import { HTMLRenderer } from './renderer.js'
|
|
29
30
|
import { signal, computed, read, Suspense, nextTick } from 'refui'
|
|
30
31
|
import { createPortal } from 'refui/extras'
|
|
@@ -40,13 +41,13 @@ import { linkResolve } from './rehype-plugins/link-resolve.js'
|
|
|
40
41
|
const resolveRewindInject = () =>
|
|
41
42
|
HTMLRenderer.rawHTML(`<script type="module" src="${withBase('/.methanol_virtual_module/inject.js')}"></script>`)
|
|
42
43
|
const RWND_FALLBACK = HTMLRenderer.rawHTML`<script>
|
|
43
|
-
if (!window.$$
|
|
44
|
+
if (!window.$$rfrm) {
|
|
44
45
|
const l = []
|
|
45
46
|
const r = function(k,i,p) {
|
|
46
47
|
l.push([k,i,p,document.currentScript])
|
|
47
48
|
}
|
|
48
49
|
r.$$loaded = l
|
|
49
|
-
window.$$
|
|
50
|
+
window.$$rfrm = r
|
|
50
51
|
}
|
|
51
52
|
</script>`
|
|
52
53
|
|
|
@@ -73,25 +74,21 @@ const resolveUserHeadAssets = () => {
|
|
|
73
74
|
return assets
|
|
74
75
|
}
|
|
75
76
|
|
|
76
|
-
const resolvePageAssetUrl = (page,
|
|
77
|
-
const root = page.source === 'theme' && state.THEME_PAGES_DIR
|
|
78
|
-
? state.THEME_PAGES_DIR
|
|
79
|
-
: state.PAGES_DIR
|
|
77
|
+
const resolvePageAssetUrl = (page, path) => {
|
|
78
|
+
const root = page.source === 'theme' && state.THEME_PAGES_DIR ? state.THEME_PAGES_DIR : state.PAGES_DIR
|
|
80
79
|
if (!root) return null
|
|
81
|
-
const relPath = relative(root,
|
|
80
|
+
const relPath = relative(root, path).replace(/\\/g, '/')
|
|
82
81
|
if (!relPath || relPath.startsWith('..')) return null
|
|
83
82
|
return withBase(`/${relPath}`)
|
|
84
83
|
}
|
|
85
84
|
|
|
86
85
|
const resolvePageHeadAssets = (page) => {
|
|
87
|
-
if (!page.
|
|
88
|
-
const baseDir = dirname(page.
|
|
89
|
-
const baseName = basename(page.
|
|
86
|
+
if (!page.path) return []
|
|
87
|
+
const baseDir = dirname(page.path)
|
|
88
|
+
const baseName = basename(page.path).replace(/\.(mdx|md)$/, '')
|
|
90
89
|
const pagesRoot = state.PAGES_DIR ? resolve(state.PAGES_DIR) : null
|
|
91
|
-
const isRootIndex =
|
|
92
|
-
|
|
93
|
-
const isRootStylePage =
|
|
94
|
-
pagesRoot && baseName === 'style' && resolve(baseDir) === pagesRoot && page.source !== 'theme'
|
|
90
|
+
const isRootIndex = pagesRoot && baseName === 'index' && resolve(baseDir) === pagesRoot && page.source !== 'theme'
|
|
91
|
+
const isRootStylePage = pagesRoot && baseName === 'style' && resolve(baseDir) === pagesRoot && page.source !== 'theme'
|
|
95
92
|
const assets = []
|
|
96
93
|
const cssPath = resolve(baseDir, `${baseName}.css`)
|
|
97
94
|
if (existsSync(cssPath)) {
|
|
@@ -131,17 +128,11 @@ const resolvePageHeadAssets = (page) => {
|
|
|
131
128
|
return assets
|
|
132
129
|
}
|
|
133
130
|
|
|
134
|
-
export const buildPageContext = ({
|
|
135
|
-
routePath,
|
|
136
|
-
filePath,
|
|
137
|
-
pageMeta,
|
|
138
|
-
pagesContext,
|
|
139
|
-
lazyPagesTree = false
|
|
140
|
-
}) => {
|
|
131
|
+
export const buildPageContext = ({ routePath, path, pageMeta, pagesContext, lazyPagesTree = false }) => {
|
|
141
132
|
const page = pageMeta
|
|
142
133
|
const language = pagesContext.getLanguageForRoute ? pagesContext.getLanguageForRoute(routePath) : null
|
|
143
134
|
const getSiblings = pagesContext.getSiblings
|
|
144
|
-
? () => pagesContext.getSiblings(routePath, page.
|
|
135
|
+
? () => pagesContext.getSiblings(routePath, page.path || path)
|
|
145
136
|
: null
|
|
146
137
|
if (page && getSiblings && page.getSiblings !== getSiblings) {
|
|
147
138
|
page.getSiblings = getSiblings
|
|
@@ -149,7 +140,7 @@ export const buildPageContext = ({
|
|
|
149
140
|
const ctx = {
|
|
150
141
|
routePath,
|
|
151
142
|
routeHref: withBase(routePath),
|
|
152
|
-
|
|
143
|
+
path,
|
|
153
144
|
page,
|
|
154
145
|
pages: pagesContext.pages || [],
|
|
155
146
|
pagesByRoute: pagesContext.pagesByRoute || new Map(),
|
|
@@ -260,11 +251,21 @@ const resolveBaseMdxConfig = async () => {
|
|
|
260
251
|
jsxImportSource: 'refui',
|
|
261
252
|
development: state.CURRENT_MODE !== 'production',
|
|
262
253
|
elementAttributeNameCase: 'html',
|
|
263
|
-
rehypePlugins: [rehypeSlug, extractToc, [withTocExport, { name: 'toc' }]]
|
|
254
|
+
rehypePlugins: [rehypeSlug, extractToc, [withTocExport, { name: 'toc' }]],
|
|
255
|
+
remarkPlugins: []
|
|
264
256
|
}
|
|
257
|
+
|
|
258
|
+
if (state.GFM_ENABLED) {
|
|
259
|
+
baseMdxConfig.remarkPlugins.push(remarkGfm)
|
|
260
|
+
}
|
|
261
|
+
|
|
265
262
|
const mdxConfig = { ...baseMdxConfig, ...userMdxConfig }
|
|
266
263
|
const userRehypePlugins = Array.isArray(userMdxConfig.rehypePlugins) ? userMdxConfig.rehypePlugins : []
|
|
267
264
|
mdxConfig.rehypePlugins = [...baseMdxConfig.rehypePlugins, ...userRehypePlugins]
|
|
265
|
+
|
|
266
|
+
const userRemarkPlugins = Array.isArray(userMdxConfig.remarkPlugins) ? userMdxConfig.remarkPlugins : []
|
|
267
|
+
mdxConfig.remarkPlugins = [...baseMdxConfig.remarkPlugins, ...userRemarkPlugins]
|
|
268
|
+
|
|
268
269
|
mdxConfig.rehypePlugins.push(linkResolve)
|
|
269
270
|
mdxConfig.rehypePlugins.push(methanolCtx)
|
|
270
271
|
return (cachedMdxConfig = mdxConfig)
|
|
@@ -288,14 +289,14 @@ const resolveMdxConfigForPage = async (frontmatter) => {
|
|
|
288
289
|
return mdxConfig
|
|
289
290
|
}
|
|
290
291
|
|
|
291
|
-
export const compileMdx = async ({ content,
|
|
292
|
+
export const compileMdx = async ({ content, path, ctx }) => {
|
|
292
293
|
const mdxConfig = await resolveMdxConfigForPage(ctx.page.frontmatter)
|
|
293
294
|
const runtimeFactory = mdxConfig.development ? JSXDevFactory : JSXFactory
|
|
294
|
-
const compiled = await compile({ value: content, path:
|
|
295
|
+
const compiled = await compile({ value: content, path: path }, mdxConfig)
|
|
295
296
|
|
|
296
297
|
return await run(compiled, {
|
|
297
298
|
...runtimeFactory,
|
|
298
|
-
baseUrl: pathToFileURL(
|
|
299
|
+
baseUrl: pathToFileURL(path).href,
|
|
299
300
|
ctx,
|
|
300
301
|
rawHTML: HTMLRenderer.rawHTML
|
|
301
302
|
})
|
|
@@ -308,14 +309,14 @@ export const compilePageMdx = async (page, pagesContext, options = {}) => {
|
|
|
308
309
|
ctx ||
|
|
309
310
|
buildPageContext({
|
|
310
311
|
routePath: page.routePath,
|
|
311
|
-
|
|
312
|
+
path: page.path,
|
|
312
313
|
pageMeta: page,
|
|
313
314
|
pagesContext,
|
|
314
315
|
lazyPagesTree
|
|
315
316
|
})
|
|
316
317
|
const mdxModule = await compileMdx({
|
|
317
318
|
content: page.content,
|
|
318
|
-
|
|
319
|
+
path: page.path,
|
|
319
320
|
ctx: activeCtx
|
|
320
321
|
})
|
|
321
322
|
page.mdxComponent = mdxModule.default
|
|
@@ -331,23 +332,17 @@ export const compilePageMdx = async (page, pagesContext, options = {}) => {
|
|
|
331
332
|
}
|
|
332
333
|
}
|
|
333
334
|
if (typeof pagesContext.setDerivedTitle === 'function') {
|
|
334
|
-
pagesContext.setDerivedTitle(page.
|
|
335
|
+
pagesContext.setDerivedTitle(page.path, shouldUseTocTitle ? page.title : null, page.toc)
|
|
335
336
|
}
|
|
336
337
|
if (ctx && refreshPagesTree && pagesContext.getPagesTree) {
|
|
337
338
|
ctx.pagesTree = pagesContext.getPagesTree(activeCtx.routePath)
|
|
338
339
|
}
|
|
339
340
|
}
|
|
340
341
|
|
|
341
|
-
export const renderHtml = async ({
|
|
342
|
-
routePath,
|
|
343
|
-
filePath,
|
|
344
|
-
components,
|
|
345
|
-
pagesContext,
|
|
346
|
-
pageMeta
|
|
347
|
-
}) => {
|
|
342
|
+
export const renderHtml = async ({ routePath, path, components, pagesContext, pageMeta }) => {
|
|
348
343
|
const ctx = buildPageContext({
|
|
349
344
|
routePath,
|
|
350
|
-
|
|
345
|
+
path,
|
|
351
346
|
pageMeta,
|
|
352
347
|
pagesContext
|
|
353
348
|
})
|
package/src/pagefind.js
CHANGED
|
@@ -22,7 +22,9 @@ import { access } from 'fs/promises'
|
|
|
22
22
|
import { constants } from 'fs'
|
|
23
23
|
import { join, delimiter } from 'path'
|
|
24
24
|
import { spawn } from 'child_process'
|
|
25
|
-
import { state } from './state.js'
|
|
25
|
+
import { state, cli } from './state.js'
|
|
26
|
+
import { createStageLogger } from './stage-logger.js'
|
|
27
|
+
import { logger } from './logger.js'
|
|
26
28
|
|
|
27
29
|
const resolvePagefindBin = async () => {
|
|
28
30
|
const binName = process.platform === 'win32' ? 'pagefind.cmd' : 'pagefind'
|
|
@@ -92,16 +94,25 @@ const runCommand = (command, args, options) =>
|
|
|
92
94
|
export const runPagefind = async () => {
|
|
93
95
|
const bin = await resolvePagefindBin()
|
|
94
96
|
if (!bin) {
|
|
95
|
-
|
|
97
|
+
logger.warn('Pagefind not found; skipping search indexing.')
|
|
96
98
|
return false
|
|
97
99
|
}
|
|
98
|
-
|
|
100
|
+
const logEnabled = state.CURRENT_MODE === 'production' && cli.command === 'build' && !cli.CLI_VERBOSE
|
|
101
|
+
const stageLogger = createStageLogger(logEnabled)
|
|
102
|
+
const token = stageLogger.start('Indexing search')
|
|
103
|
+
|
|
104
|
+
if (cli.CLI_VERBOSE) {
|
|
105
|
+
logger.info('Running Pagefind search indexing...')
|
|
106
|
+
}
|
|
107
|
+
|
|
99
108
|
const extraArgs = buildArgsFromOptions(state.PAGEFIND_BUILD)
|
|
100
109
|
const ok = await runCommand(bin, ['--site', state.DIST_DIR, ...extraArgs], {
|
|
101
|
-
cwd: state.PROJECT_ROOT
|
|
110
|
+
cwd: state.PROJECT_ROOT,
|
|
111
|
+
stdio: cli.CLI_VERBOSE ? 'inherit' : 'ignore'
|
|
102
112
|
})
|
|
103
113
|
if (!ok) {
|
|
104
|
-
|
|
114
|
+
logger.warn('Pagefind failed to build search index.')
|
|
105
115
|
}
|
|
116
|
+
stageLogger.end(token)
|
|
106
117
|
return ok
|
|
107
118
|
}
|
package/src/pages.js
CHANGED
|
@@ -28,7 +28,6 @@ import { compilePageMdx } from './mdx.js'
|
|
|
28
28
|
import { createStageLogger } from './stage-logger.js'
|
|
29
29
|
|
|
30
30
|
const isPageFile = (name) => name.endsWith('.mdx') || name.endsWith('.md')
|
|
31
|
-
const isInternalPage = (name) => name.startsWith('_') || name.startsWith('.')
|
|
32
31
|
const isIgnoredEntry = (name) => name.startsWith('.') || name.startsWith('_')
|
|
33
32
|
|
|
34
33
|
const pageMetadataCache = new Map()
|
|
@@ -107,17 +106,17 @@ const resolveLanguageForRoute = (languages = [], routePath = '/') => {
|
|
|
107
106
|
return best || rootLanguage
|
|
108
107
|
}
|
|
109
108
|
|
|
110
|
-
export const routePathFromFile = (
|
|
111
|
-
if (!
|
|
109
|
+
export const routePathFromFile = (path, pagesDir = state.PAGES_DIR) => {
|
|
110
|
+
if (!path.endsWith('.mdx') && !path.endsWith('.md')) {
|
|
112
111
|
return null
|
|
113
112
|
}
|
|
114
|
-
const relPath = relative(pagesDir,
|
|
113
|
+
const relPath = relative(pagesDir, path)
|
|
115
114
|
if (relPath.startsWith('..')) {
|
|
116
115
|
return null
|
|
117
116
|
}
|
|
118
117
|
const name = relPath.replace(/\.(mdx|md)$/, '')
|
|
119
118
|
const baseName = name.split(/[\\/]/).pop()
|
|
120
|
-
if (
|
|
119
|
+
if (isIgnoredEntry(baseName)) {
|
|
121
120
|
return null
|
|
122
121
|
}
|
|
123
122
|
const normalized = name.replace(/\\/g, '/')
|
|
@@ -147,8 +146,8 @@ const parseFrontmatter = (raw) => {
|
|
|
147
146
|
}
|
|
148
147
|
}
|
|
149
148
|
|
|
150
|
-
const parsePageMetadata = async (
|
|
151
|
-
const raw = await readFile(
|
|
149
|
+
const parsePageMetadata = async (path) => {
|
|
150
|
+
const raw = await readFile(path, 'utf-8')
|
|
152
151
|
const { data: frontmatter, content, matter } = parseFrontmatter(raw)
|
|
153
152
|
let title = frontmatter.title
|
|
154
153
|
return {
|
|
@@ -198,13 +197,17 @@ const buildPagesTree = (pages, options = {}) => {
|
|
|
198
197
|
}
|
|
199
198
|
return routePath
|
|
200
199
|
}
|
|
200
|
+
const buildDirRoutePath = (dir) => {
|
|
201
|
+
const localPath = dir ? `/${dir}/` : '/'
|
|
202
|
+
if (!rootPrefix) return normalizeRoutePath(localPath)
|
|
203
|
+
return normalizeRoutePath(`${rootPrefix}${localPath}`)
|
|
204
|
+
}
|
|
201
205
|
const currentRouteWithinRoot = resolveRouteWithinRoot(currentRoutePath)
|
|
202
206
|
const isUnderRoot = (page) => {
|
|
203
207
|
if (!rootDir) return true
|
|
204
208
|
return page.routePath === rootPath || (rootPrefix && page.routePath.startsWith(`${rootPrefix}/`))
|
|
205
209
|
}
|
|
206
210
|
const treePages = pages
|
|
207
|
-
.filter((page) => !page.isInternal)
|
|
208
211
|
.filter((page) => isUnderRoot(page))
|
|
209
212
|
.map((page) => {
|
|
210
213
|
if (!rootDir) return page
|
|
@@ -267,10 +270,10 @@ const buildPagesTree = (pages, options = {}) => {
|
|
|
267
270
|
const dir = {
|
|
268
271
|
type: 'directory',
|
|
269
272
|
name,
|
|
270
|
-
path:
|
|
273
|
+
path: resolve(state.PAGES_DIR, path),
|
|
271
274
|
children: [],
|
|
272
275
|
depth,
|
|
273
|
-
routePath:
|
|
276
|
+
routePath: buildDirRoutePath(path),
|
|
274
277
|
routeHref: null,
|
|
275
278
|
title: null,
|
|
276
279
|
weight: null,
|
|
@@ -291,9 +294,9 @@ const buildPagesTree = (pages, options = {}) => {
|
|
|
291
294
|
}
|
|
292
295
|
for (const page of treePages) {
|
|
293
296
|
if (page.hidden && !(includeHiddenRoot && page.routePath === rootPath)) {
|
|
294
|
-
const
|
|
297
|
+
const isHiddenSpecial = page.routePath === '/404' || page.routePath === '/offline'
|
|
295
298
|
const shouldExposeHidden =
|
|
296
|
-
!
|
|
299
|
+
!isHiddenSpecial &&
|
|
297
300
|
page.hiddenByFrontmatter === true &&
|
|
298
301
|
(
|
|
299
302
|
page.routePath === currentRoutePath ||
|
|
@@ -404,7 +407,7 @@ const walkPages = async function* (dir, basePath = '') {
|
|
|
404
407
|
const relativePath = join(basePath, name).replace(/\\/g, '/')
|
|
405
408
|
const isIndex = name === 'index'
|
|
406
409
|
const routePath = isIndex ? (basePath ? `/${basePath}/` : '/') : `/${relativePath}`
|
|
407
|
-
yield { routePath,
|
|
410
|
+
yield { routePath, path: fullPath, isIndex }
|
|
408
411
|
}
|
|
409
412
|
|
|
410
413
|
for (const { entry, fullPath } of dirs) {
|
|
@@ -412,39 +415,45 @@ const walkPages = async function* (dir, basePath = '') {
|
|
|
412
415
|
}
|
|
413
416
|
}
|
|
414
417
|
|
|
415
|
-
export const buildPageEntry = async ({
|
|
416
|
-
const routePath = routePathFromFile(
|
|
418
|
+
export const buildPageEntry = async ({ path, pagesDir, source }) => {
|
|
419
|
+
const routePath = routePathFromFile(path, pagesDir)
|
|
417
420
|
if (!routePath) return null
|
|
418
|
-
const relPath = relative(pagesDir,
|
|
421
|
+
const relPath = relative(pagesDir, path).replace(/\\/g, '/')
|
|
419
422
|
const name = relPath.replace(/\.(mdx|md)$/, '')
|
|
420
423
|
const baseName = name.split('/').pop()
|
|
421
424
|
const dir = name.split('/').slice(0, -1).join('/')
|
|
422
425
|
const dirName = dir ? dir.split('/').pop() : ''
|
|
423
426
|
const isIndex = baseName === 'index'
|
|
424
427
|
const segments = routePath.split('/').filter(Boolean)
|
|
425
|
-
const stats = await stat(
|
|
426
|
-
const cached = pageMetadataCache.get(
|
|
428
|
+
const stats = await stat(path)
|
|
429
|
+
const cached = pageMetadataCache.get(path)
|
|
427
430
|
let metadata = null
|
|
428
431
|
if (cached && cached.mtimeMs === stats.mtimeMs) {
|
|
429
432
|
metadata = cached.metadata
|
|
430
433
|
} else {
|
|
431
|
-
metadata = await parsePageMetadata(
|
|
432
|
-
pageMetadataCache.set(
|
|
434
|
+
metadata = await parsePageMetadata(path)
|
|
435
|
+
pageMetadataCache.set(path, { mtimeMs: stats.mtimeMs, metadata })
|
|
433
436
|
}
|
|
434
|
-
const derived = pageDerivedCache.get(
|
|
437
|
+
const derived = pageDerivedCache.get(path)
|
|
435
438
|
const exclude = Boolean(metadata.frontmatter?.exclude)
|
|
436
439
|
const frontmatterHidden = metadata.frontmatter?.hidden
|
|
437
440
|
const hiddenByFrontmatter = frontmatterHidden === true
|
|
438
441
|
const isNotFoundPage = routePath === '/404'
|
|
439
|
-
const
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
442
|
+
const isOfflinePage = routePath === '/offline'
|
|
443
|
+
const isSpecialPage = isNotFoundPage || isOfflinePage
|
|
444
|
+
const isSiteRoot = routePath === '/'
|
|
445
|
+
const frontmatterIsRoot = Boolean(metadata.frontmatter?.isRoot)
|
|
446
|
+
const hidden = isSpecialPage
|
|
447
|
+
? true
|
|
448
|
+
: frontmatterHidden === false
|
|
449
|
+
? false
|
|
450
|
+
: frontmatterHidden === true
|
|
451
|
+
? true
|
|
452
|
+
: frontmatterIsRoot
|
|
444
453
|
return {
|
|
445
454
|
routePath,
|
|
446
455
|
routeHref: withBase(routePath),
|
|
447
|
-
|
|
456
|
+
path,
|
|
448
457
|
source,
|
|
449
458
|
relativePath: relPath,
|
|
450
459
|
name: baseName,
|
|
@@ -452,11 +461,10 @@ export const buildPageEntry = async ({ filePath, pagesDir, source }) => {
|
|
|
452
461
|
segments,
|
|
453
462
|
depth: segments.length,
|
|
454
463
|
isIndex,
|
|
455
|
-
isInternal: isInternalPage(baseName),
|
|
456
464
|
title: metadata.title || derived?.title || (baseName === 'index' ? (dirName || 'Home') : baseName),
|
|
457
465
|
weight: parseWeight(metadata.frontmatter?.weight),
|
|
458
466
|
date: parseDate(metadata.frontmatter?.date) || parseDate(stats.mtime),
|
|
459
|
-
isRoot:
|
|
467
|
+
isRoot: isSiteRoot || frontmatterIsRoot,
|
|
460
468
|
hidden,
|
|
461
469
|
hiddenByFrontmatter,
|
|
462
470
|
exclude,
|
|
@@ -468,9 +476,7 @@ export const buildPageEntry = async ({ filePath, pagesDir, source }) => {
|
|
|
468
476
|
size: stats.size,
|
|
469
477
|
createdAt: stats.birthtime?.toISOString?.() || null,
|
|
470
478
|
updatedAt: stats.mtime?.toISOString?.() || null
|
|
471
|
-
}
|
|
472
|
-
createdAt: stats.birthtime?.toISOString?.() || null,
|
|
473
|
-
updatedAt: stats.mtime?.toISOString?.() || null
|
|
479
|
+
}
|
|
474
480
|
}
|
|
475
481
|
}
|
|
476
482
|
|
|
@@ -481,7 +487,7 @@ const collectPagesFromDir = async (pagesDir, source) => {
|
|
|
481
487
|
const pages = []
|
|
482
488
|
for await (const page of walkPages(pagesDir)) {
|
|
483
489
|
const entry = await buildPageEntry({
|
|
484
|
-
|
|
490
|
+
path: page.path,
|
|
485
491
|
pagesDir,
|
|
486
492
|
source
|
|
487
493
|
})
|
|
@@ -523,7 +529,12 @@ const collectPages = async () => {
|
|
|
523
529
|
|
|
524
530
|
const buildIndexFallback = (pages, siteName) => {
|
|
525
531
|
const visiblePages = pages
|
|
526
|
-
.filter(
|
|
532
|
+
.filter(
|
|
533
|
+
(page) =>
|
|
534
|
+
page.routePath !== '/' &&
|
|
535
|
+
page.routePath !== '/404' &&
|
|
536
|
+
page.routePath !== '/offline'
|
|
537
|
+
)
|
|
527
538
|
.sort((a, b) => a.routePath.localeCompare(b.routePath))
|
|
528
539
|
|
|
529
540
|
const lines = [
|
|
@@ -574,7 +585,7 @@ const buildNavSequence = (nodes, pagesByRoute) => {
|
|
|
574
585
|
const seen = new Set()
|
|
575
586
|
const addEntry = (entry) => {
|
|
576
587
|
if (!entry.routePath) return
|
|
577
|
-
const key = entry.
|
|
588
|
+
const key = entry.path || entry.routePath
|
|
578
589
|
if (seen.has(key)) return
|
|
579
590
|
seen.add(key)
|
|
580
591
|
result.push(entry)
|
|
@@ -616,14 +627,13 @@ export const buildPagesContext = async ({ compileAll = true } = {}) => {
|
|
|
616
627
|
pages.unshift({
|
|
617
628
|
routePath: '/',
|
|
618
629
|
routeHref: withBase('/'),
|
|
619
|
-
|
|
630
|
+
path: resolve(state.PAGES_DIR, 'index.md'),
|
|
620
631
|
relativePath: 'index.md',
|
|
621
632
|
name: 'index',
|
|
622
633
|
dir: '',
|
|
623
634
|
segments: [],
|
|
624
635
|
depth: 0,
|
|
625
636
|
isIndex: true,
|
|
626
|
-
isInternal: false,
|
|
627
637
|
title: state.SITE_NAME || 'Methanol Site',
|
|
628
638
|
weight: null,
|
|
629
639
|
date: null,
|
|
@@ -648,10 +658,10 @@ export const buildPagesContext = async ({ compileAll = true } = {}) => {
|
|
|
648
658
|
}
|
|
649
659
|
}
|
|
650
660
|
const getPageByRoute = (routePath, options = {}) => {
|
|
651
|
-
const {
|
|
652
|
-
if (
|
|
661
|
+
const { path } = options || {}
|
|
662
|
+
if (path) {
|
|
653
663
|
for (const page of pages) {
|
|
654
|
-
if (page.routePath === routePath && page.
|
|
664
|
+
if (page.routePath === routePath && page.path === path) {
|
|
655
665
|
return page
|
|
656
666
|
}
|
|
657
667
|
}
|
|
@@ -717,26 +727,26 @@ export const buildPagesContext = async ({ compileAll = true } = {}) => {
|
|
|
717
727
|
pagesTree,
|
|
718
728
|
getPagesTree,
|
|
719
729
|
derivedTitleCache: pageDerivedCache,
|
|
720
|
-
setDerivedTitle: (
|
|
721
|
-
if (!
|
|
722
|
-
pageDerivedCache.set(
|
|
730
|
+
setDerivedTitle: (path, title, toc) => {
|
|
731
|
+
if (!path) return
|
|
732
|
+
pageDerivedCache.set(path, { title, toc })
|
|
723
733
|
},
|
|
724
|
-
clearDerivedTitle: (
|
|
725
|
-
if (!
|
|
726
|
-
pageDerivedCache.delete(
|
|
734
|
+
clearDerivedTitle: (path) => {
|
|
735
|
+
if (!path) return
|
|
736
|
+
pageDerivedCache.delete(path)
|
|
727
737
|
},
|
|
728
738
|
refreshPagesTree: () => {
|
|
729
739
|
pagesTreeCache.clear()
|
|
730
740
|
navSequenceCache.clear()
|
|
731
741
|
pagesContext.pagesTree = getPagesTree('/')
|
|
732
742
|
},
|
|
733
|
-
getSiblings: (routePath,
|
|
743
|
+
getSiblings: (routePath, path = null) => {
|
|
734
744
|
if (!routePath) return { prev: null, next: null }
|
|
735
745
|
const sequence = getNavSequence(routePath)
|
|
736
746
|
if (!sequence.length) return { prev: null, next: null }
|
|
737
747
|
let index = -1
|
|
738
|
-
if (
|
|
739
|
-
index = sequence.findIndex((entry) => entry.
|
|
748
|
+
if (path) {
|
|
749
|
+
index = sequence.findIndex((entry) => entry.path === path)
|
|
740
750
|
}
|
|
741
751
|
if (index < 0) {
|
|
742
752
|
index = sequence.findIndex((entry) => entry.routePath === routePath)
|
|
@@ -748,7 +758,7 @@ export const buildPagesContext = async ({ compileAll = true } = {}) => {
|
|
|
748
758
|
routePath: entry.routePath,
|
|
749
759
|
routeHref: entry.routeHref,
|
|
750
760
|
title: entry.title || entry.name || entry.routePath,
|
|
751
|
-
|
|
761
|
+
path: entry.path || null
|
|
752
762
|
}
|
|
753
763
|
}
|
|
754
764
|
return {
|
|
@@ -775,7 +785,7 @@ export const buildPagesContext = async ({ compileAll = true } = {}) => {
|
|
|
775
785
|
for (let i = 0; i < pages.length; i++) {
|
|
776
786
|
const page = pages[i]
|
|
777
787
|
if (logEnabled) {
|
|
778
|
-
stageLogger.update(compileToken, `Compiling MDX [${i + 1}/${totalPages}] ${page.
|
|
788
|
+
stageLogger.update(compileToken, `Compiling MDX [${i + 1}/${totalPages}] ${page.path}`)
|
|
779
789
|
}
|
|
780
790
|
await compilePageMdx(page, pagesContext, {
|
|
781
791
|
lazyPagesTree: true,
|
package/src/public-assets.js
CHANGED
|
@@ -110,7 +110,7 @@ export const preparePublicAssets = async ({ themeDir, userDir, targetDir }) => {
|
|
|
110
110
|
}
|
|
111
111
|
}
|
|
112
112
|
|
|
113
|
-
export const updateAsset = async ({ type,
|
|
113
|
+
export const updateAsset = async ({ type, path, themeDir, userDir, targetDir, relPath }) => {
|
|
114
114
|
const targetPath = resolve(targetDir, relPath)
|
|
115
115
|
|
|
116
116
|
if (type === 'unlink') {
|
|
@@ -58,7 +58,7 @@ export function env(parentEnv) {
|
|
|
58
58
|
const component = ({ children: childrenProp, ...props }, ...children) => {
|
|
59
59
|
const id = renderCount++
|
|
60
60
|
const idStr = id.toString(16)
|
|
61
|
-
const script = `$$
|
|
61
|
+
const script = `$$rfrm(${JSON.stringify(key)},${id},${Object.keys(props).length ? JSON5.stringify(props) : '{}'})`
|
|
62
62
|
|
|
63
63
|
return (R) => {
|
|
64
64
|
return [
|
|
@@ -76,8 +76,8 @@ const resolvePagesRoot = (filePath) => {
|
|
|
76
76
|
|
|
77
77
|
export const linkResolve = () => {
|
|
78
78
|
return (tree, file) => {
|
|
79
|
-
const baseDir = file
|
|
80
|
-
const pagesRoot = resolvePagesRoot(file
|
|
79
|
+
const baseDir = file.path ? dirname(file.path) : file.cwd || process.cwd()
|
|
80
|
+
const pagesRoot = resolvePagesRoot(file.path || null)
|
|
81
81
|
visit(tree, (node) => {
|
|
82
82
|
if (!isElement(node) || node.tagName !== 'a') {
|
|
83
83
|
return
|
package/src/stage-logger.js
CHANGED
|
@@ -18,7 +18,10 @@
|
|
|
18
18
|
* under the License.
|
|
19
19
|
*/
|
|
20
20
|
|
|
21
|
+
import { style } from './logger.js'
|
|
22
|
+
|
|
21
23
|
const now = () => (typeof performance !== 'undefined' ? performance.now() : Date.now())
|
|
24
|
+
const log = console.log.bind(console)
|
|
22
25
|
|
|
23
26
|
export const createStageLogger = (enabled) => {
|
|
24
27
|
let lastLength = 0
|
|
@@ -26,13 +29,13 @@ export const createStageLogger = (enabled) => {
|
|
|
26
29
|
const writeLine = (text, newline) => {
|
|
27
30
|
if (!process.stdout || !process.stdout.write) {
|
|
28
31
|
if (newline) {
|
|
29
|
-
|
|
32
|
+
log(text)
|
|
30
33
|
}
|
|
31
34
|
return
|
|
32
35
|
}
|
|
33
36
|
if (!isTty) {
|
|
34
37
|
if (newline) {
|
|
35
|
-
|
|
38
|
+
log(text)
|
|
36
39
|
}
|
|
37
40
|
return
|
|
38
41
|
}
|
|
@@ -43,17 +46,18 @@ export const createStageLogger = (enabled) => {
|
|
|
43
46
|
}
|
|
44
47
|
const start = (label) => {
|
|
45
48
|
if (!enabled) return null
|
|
46
|
-
writeLine(`${label}...`, false)
|
|
49
|
+
writeLine(`${style.cyan('◼')} ${label}...`, false)
|
|
47
50
|
return { label, start: now() }
|
|
48
51
|
}
|
|
49
52
|
const update = (token, message) => {
|
|
50
53
|
if (!enabled || !token || !message) return
|
|
51
|
-
writeLine(message
|
|
54
|
+
writeLine(`${style.cyan('◼')} ${message}`, false)
|
|
52
55
|
}
|
|
53
56
|
const end = (token) => {
|
|
54
57
|
if (!enabled || !token) return
|
|
55
|
-
const duration =
|
|
56
|
-
|
|
58
|
+
const duration = now() - token.start
|
|
59
|
+
const timeString = duration > 1000 ? `${(duration / 1000).toFixed(2)}s` : `${Math.round(duration)}ms`
|
|
60
|
+
writeLine(`${style.green('✔')} ${token.label}\t${style.dim(timeString)}`, true)
|
|
57
61
|
}
|
|
58
62
|
return { start, update, end }
|
|
59
63
|
}
|