methanol 0.0.11 → 0.0.13

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/src/mdx.js CHANGED
@@ -40,16 +40,9 @@ import { linkResolve } from './rehype-plugins/link-resolve.js'
40
40
  // Workaround for Vite: it doesn't support resolving module/virtual modules in script src in dev mode
41
41
  const resolveRewindInject = () =>
42
42
  HTMLRenderer.rawHTML(`<script type="module" src="${withBase('/.methanol_virtual_module/inject.js')}"></script>`)
43
- const RWND_FALLBACK = HTMLRenderer.rawHTML`<script>
44
- if (!window.$$rfrm) {
45
- const l = []
46
- const r = function(k,i,p) {
47
- l.push([k,i,p,document.currentScript])
48
- }
49
- r.$$loaded = l
50
- window.$$rfrm = r
51
- }
52
- </script>`
43
+ const RWND_FALLBACK = HTMLRenderer.rawHTML(
44
+ '<script>if(!window.$$rfrm){var l=[];var r=function(k,i,p){l.push([k,i,p,document.currentScript])};r.$$loaded=l;window.$$rfrm=r}</script>'
45
+ )
53
46
 
54
47
  let cachedHeadAssets = null
55
48
 
@@ -131,9 +124,7 @@ const resolvePageHeadAssets = (page) => {
131
124
  export const buildPageContext = ({ routePath, path, pageMeta, pagesContext, lazyPagesTree = false }) => {
132
125
  const page = pageMeta
133
126
  const language = pagesContext.getLanguageForRoute ? pagesContext.getLanguageForRoute(routePath) : null
134
- const getSiblings = pagesContext.getSiblings
135
- ? () => pagesContext.getSiblings(routePath, page.path || path)
136
- : null
127
+ const getSiblings = pagesContext.getSiblings ? () => pagesContext.getSiblings(routePath, page.path || path) : null
137
128
  if (page && getSiblings && page.getSiblings !== getSiblings) {
138
129
  page.getSiblings = getSiblings
139
130
  }
@@ -215,7 +206,7 @@ const normalizeStarryNightConfig = (value) => {
215
206
  }
216
207
  if (typeof value !== 'object') return null
217
208
  const { enabled, options, ...rest } = value
218
- if (enabled === false) return { enabled: false, options: null }
209
+ if (enabled === false) return { enabled: false, options }
219
210
  if (options && typeof options === 'object') {
220
211
  return { enabled: true, options: { ...options } }
221
212
  }
@@ -289,12 +280,17 @@ const resolveMdxConfigForPage = async (frontmatter) => {
289
280
  return mdxConfig
290
281
  }
291
282
 
292
- export const compileMdx = async ({ content, path, ctx }) => {
293
- const mdxConfig = await resolveMdxConfigForPage(ctx.page.frontmatter)
294
- const runtimeFactory = mdxConfig.development ? JSXDevFactory : JSXFactory
283
+ export const compileMdxSource = async ({ content, path, frontmatter }) => {
284
+ const mdxConfig = await resolveMdxConfigForPage(frontmatter)
295
285
  const compiled = await compile({ value: content, path: path }, mdxConfig)
286
+ const code = String(compiled.value ?? compiled)
287
+ return { code, development: Boolean(mdxConfig.development) }
288
+ }
296
289
 
297
- return await run(compiled, {
290
+ export const runMdxSource = async ({ code, path, ctx, development = null }) => {
291
+ const isDev = development == null ? state.CURRENT_MODE !== 'production' : development
292
+ const runtimeFactory = isDev ? JSXDevFactory : JSXFactory
293
+ return await run(code, {
298
294
  ...runtimeFactory,
299
295
  baseUrl: pathToFileURL(path).href,
300
296
  ctx,
@@ -302,9 +298,23 @@ export const compileMdx = async ({ content, path, ctx }) => {
302
298
  })
303
299
  }
304
300
 
301
+ export const compileMdx = async ({ content, path, ctx }) => {
302
+ const result = await compileMdxSource({
303
+ content,
304
+ path,
305
+ frontmatter: ctx?.page?.frontmatter || null
306
+ })
307
+ return await runMdxSource({
308
+ code: result.code,
309
+ path,
310
+ ctx,
311
+ development: result.development
312
+ })
313
+ }
314
+
305
315
  export const compilePageMdx = async (page, pagesContext, options = {}) => {
306
316
  if (!page || page.content == null || page.mdxComponent) return
307
- const { ctx = null, lazyPagesTree = false, refreshPagesTree = true } = options || {}
317
+ const { ctx = null, lazyPagesTree = false, refreshPagesTree = true, compiled = null } = options || {}
308
318
  const activeCtx =
309
319
  ctx ||
310
320
  buildPageContext({
@@ -314,11 +324,19 @@ export const compilePageMdx = async (page, pagesContext, options = {}) => {
314
324
  pagesContext,
315
325
  lazyPagesTree
316
326
  })
317
- const mdxModule = await compileMdx({
318
- content: page.content,
319
- path: page.path,
320
- ctx: activeCtx
321
- })
327
+ page.mdxCtx = activeCtx
328
+ const mdxModule = compiled?.code
329
+ ? await runMdxSource({
330
+ code: compiled.code,
331
+ path: page.path,
332
+ ctx: activeCtx,
333
+ development: compiled.development
334
+ })
335
+ : await compileMdx({
336
+ content: page.content,
337
+ path: page.path,
338
+ ctx: activeCtx
339
+ })
322
340
  page.mdxComponent = mdxModule.default
323
341
  page.toc = mdxModule.toc
324
342
  const shouldUseTocTitle = page.frontmatter?.title == null
@@ -346,6 +364,7 @@ export const renderHtml = async ({ routePath, path, components, pagesContext, pa
346
364
  pageMeta,
347
365
  pagesContext
348
366
  })
367
+
349
368
  await compilePageMdx(pageMeta, pagesContext, { ctx })
350
369
 
351
370
  const [Head, Outlet] = createPortal()
@@ -359,8 +378,6 @@ export const renderHtml = async ({ routePath, path, components, pagesContext, pa
359
378
  ]
360
379
  }
361
380
 
362
- const mdxComponent = pageMeta.mdxComponent
363
-
364
381
  const PageContent = ({ components: extraComponents, ...props }, ...children) =>
365
382
  mdxComponent({
366
383
  children,
@@ -374,25 +391,28 @@ export const renderHtml = async ({ routePath, path, components, pagesContext, pa
374
391
  })
375
392
 
376
393
  const template = state.USER_THEME.template
394
+ const mdxComponent = pageMeta.mdxComponent
377
395
 
378
- const renderResult = await new Promise((r) => {
396
+ const renderResult = await new Promise((resolve, reject) => {
379
397
  const result = HTMLRenderer.c(
380
398
  Suspense,
381
399
  {
382
400
  onLoad() {
383
- nextTick(() => r(result))
401
+ nextTick(() => resolve(result))
402
+ },
403
+ catch({ error }) {
404
+ reject(error)
384
405
  }
385
406
  },
386
- () =>
387
- template({
388
- ctx,
389
- page: ctx.page,
390
- withBase,
391
- PageContent,
392
- ExtraHead,
393
- HTMLRenderer,
394
- components
395
- })
407
+ template({
408
+ ctx,
409
+ page: ctx.page,
410
+ withBase,
411
+ PageContent,
412
+ ExtraHead,
413
+ HTMLRenderer,
414
+ components
415
+ })
396
416
  )
397
417
  })
398
418
 
package/src/pages.js CHANGED
@@ -22,9 +22,11 @@ import matter from 'gray-matter'
22
22
  import { readdir, readFile, stat } from 'fs/promises'
23
23
  import { existsSync } from 'fs'
24
24
  import { resolve, join, relative } from 'path'
25
+ import { cpus } from 'os'
26
+ import { Worker } from 'worker_threads'
25
27
  import { state, cli } from './state.js'
26
28
  import { withBase } from './config.js'
27
- import { compilePageMdx } from './mdx.js'
29
+ import { compileMdxSource, compilePageMdx } from './mdx.js'
28
30
  import { createStageLogger } from './stage-logger.js'
29
31
 
30
32
  const isPageFile = (name) => name.endsWith('.mdx') || name.endsWith('.md')
@@ -32,6 +34,137 @@ const isIgnoredEntry = (name) => name.startsWith('.') || name.startsWith('_')
32
34
 
33
35
  const pageMetadataCache = new Map()
34
36
  const pageDerivedCache = new Map()
37
+ const MDX_WORKER_URL = new URL('./workers/mdx-compile-worker.js', import.meta.url)
38
+ const cliOverrides = {
39
+ CLI_INTERMEDIATE_DIR: cli.CLI_INTERMEDIATE_DIR,
40
+ CLI_EMIT_INTERMEDIATE: cli.CLI_EMIT_INTERMEDIATE,
41
+ CLI_HOST: cli.CLI_HOST,
42
+ CLI_PORT: cli.CLI_PORT,
43
+ CLI_PAGES_DIR: cli.CLI_PAGES_DIR,
44
+ CLI_COMPONENTS_DIR: cli.CLI_COMPONENTS_DIR,
45
+ CLI_ASSETS_DIR: cli.CLI_ASSETS_DIR,
46
+ CLI_OUTPUT_DIR: cli.CLI_OUTPUT_DIR,
47
+ CLI_CONFIG_PATH: cli.CLI_CONFIG_PATH,
48
+ CLI_SITE_NAME: cli.CLI_SITE_NAME,
49
+ CLI_CODE_HIGHLIGHTING: cli.CLI_CODE_HIGHLIGHTING,
50
+ CLI_JOBS: cli.CLI_JOBS,
51
+ CLI_VERBOSE: cli.CLI_VERBOSE,
52
+ CLI_BASE: cli.CLI_BASE,
53
+ CLI_SEARCH: cli.CLI_SEARCH,
54
+ CLI_PWA: cli.CLI_PWA
55
+ }
56
+
57
+ const resolveWorkerCount = (total) => {
58
+ const cpuCount = Math.max(1, cpus()?.length || 1)
59
+ const requested = state.WORKER_JOBS
60
+ if (requested == null || requested <= 0) {
61
+ const items = Math.max(1, Number.isFinite(total) ? total : 1)
62
+ const autoCount = Math.round(Math.log(items))
63
+ return Math.max(1, Math.min(cpuCount, autoCount))
64
+ }
65
+ return Math.max(1, Math.min(cpuCount, Math.floor(requested)))
66
+ }
67
+
68
+ const compileMdxSources = async (pages, options = {}) => {
69
+ const targets = pages.filter((page) => page && page.content != null && !page.mdxComponent)
70
+ const results = new Map()
71
+ if (!targets.length) return results
72
+ const { onProgress } = options || {}
73
+ const reportProgress = (page) => {
74
+ if (typeof onProgress === 'function') {
75
+ onProgress(page)
76
+ }
77
+ }
78
+ const workerCount = Math.min(resolveWorkerCount(targets.length), targets.length)
79
+ if (workerCount <= 1) {
80
+ for (const page of targets) {
81
+ const result = await compileMdxSource({
82
+ content: page.content,
83
+ path: page.path,
84
+ frontmatter: page.frontmatter
85
+ })
86
+ results.set(page, result)
87
+ reportProgress(page)
88
+ }
89
+ return results
90
+ }
91
+
92
+ return await new Promise((resolve, reject) => {
93
+ const workers = []
94
+ const pending = new Map()
95
+ let cursor = 0
96
+ let nextId = 0
97
+ let finished = false
98
+
99
+ const finalize = async (error) => {
100
+ if (finished) return
101
+ finished = true
102
+ await Promise.all(workers.map((worker) => worker.terminate().catch(() => null)))
103
+ if (error) {
104
+ reject(error)
105
+ return
106
+ }
107
+ resolve(results)
108
+ }
109
+
110
+ const assign = (worker) => {
111
+ if (cursor >= targets.length) return false
112
+ const page = targets[cursor++]
113
+ const id = nextId++
114
+ pending.set(id, page)
115
+ worker.postMessage({
116
+ id,
117
+ path: page.path,
118
+ content: page.content,
119
+ frontmatter: page.frontmatter
120
+ })
121
+ return true
122
+ }
123
+
124
+ const handleMessage = (worker, message) => {
125
+ if (finished) return
126
+ const { id, result, error } = message || {}
127
+ const page = pending.get(id)
128
+ pending.delete(id)
129
+ if (!page) return
130
+ if (error) {
131
+ void finalize(new Error(error))
132
+ return
133
+ }
134
+ results.set(page, result)
135
+ reportProgress(page)
136
+ assign(worker)
137
+ if (results.size === targets.length && pending.size === 0) {
138
+ void finalize()
139
+ }
140
+ }
141
+
142
+ const handleError = (error) => {
143
+ if (finished) return
144
+ void finalize(error instanceof Error ? error : new Error(String(error)))
145
+ }
146
+
147
+ for (let i = 0; i < workerCount; i += 1) {
148
+ const worker = new Worker(MDX_WORKER_URL, {
149
+ type: 'module',
150
+ workerData: {
151
+ mode: state.CURRENT_MODE,
152
+ configPath: cli.CLI_CONFIG_PATH,
153
+ cli: cliOverrides
154
+ }
155
+ })
156
+ workers.push(worker)
157
+ worker.on('message', (message) => handleMessage(worker, message))
158
+ worker.on('error', handleError)
159
+ worker.on('exit', (code) => {
160
+ if (code !== 0) {
161
+ handleError(new Error(`MDX worker exited with code ${code}`))
162
+ }
163
+ })
164
+ assign(worker)
165
+ }
166
+ })
167
+ }
35
168
 
36
169
  const collectLanguagesFromPages = (pages = []) => {
37
170
  const languages = new Map()
@@ -616,47 +749,12 @@ const buildNavSequence = (nodes, pagesByRoute) => {
616
749
  return result
617
750
  }
618
751
 
619
- export const buildPagesContext = async ({ compileAll = true } = {}) => {
620
- const logEnabled = state.CURRENT_MODE === 'production' && cli.command === 'build'
621
- const stageLogger = createStageLogger(logEnabled)
622
- const collectToken = stageLogger.start('Collecting pages')
623
- const collected = await collectPages()
624
- stageLogger.end(collectToken)
625
- let pages = collected.pages
626
- const excludedRoutes = collected.excludedRoutes
627
- const excludedDirs = collected.excludedDirs
628
- const hasIndex = pages.some((page) => page.routePath === '/')
629
- if (!hasIndex) {
630
- const content = buildIndexFallback(pages, state.SITE_NAME)
631
- pages.unshift({
632
- routePath: '/',
633
- routeHref: withBase('/'),
634
- path: resolve(state.PAGES_DIR, 'index.md'),
635
- relativePath: 'index.md',
636
- name: 'index',
637
- dir: '',
638
- segments: [],
639
- depth: 0,
640
- isIndex: true,
641
- title: state.SITE_NAME || 'Methanol Site',
642
- weight: null,
643
- date: null,
644
- isRoot: false,
645
- hidden: false,
646
- content,
647
- frontmatter: {},
648
- matter: null,
649
- stats: { size: content.length, createdAt: null, updatedAt: null },
650
- createdAt: null,
651
- updatedAt: null
652
- })
653
- if (excludedRoutes?.has('/')) {
654
- excludedRoutes.delete('/')
655
- }
656
- }
657
-
752
+ export const createPagesContextFromPages = ({ pages, excludedRoutes, excludedDirs } = {}) => {
753
+ const pageList = Array.isArray(pages) ? pages : []
754
+ const routeExcludes = excludedRoutes || new Set()
755
+ const dirExcludes = excludedDirs || new Set()
658
756
  const pagesByRoute = new Map()
659
- for (const page of pages) {
757
+ for (const page of pageList) {
660
758
  if (!pagesByRoute.has(page.routePath)) {
661
759
  pagesByRoute.set(page.routePath, page)
662
760
  }
@@ -703,7 +801,7 @@ export const buildPagesContext = async ({ compileAll = true } = {}) => {
703
801
  }
704
802
  let pagesTree = getPagesTree('/')
705
803
  const notFound = pagesByRoute.get('/404') || null
706
- const languages = collectLanguagesFromPages(pages)
804
+ const languages = collectLanguagesFromPages(pageList)
707
805
  const userSite = state.USER_SITE || {}
708
806
  const siteBase = state.VITE_BASE ?? userSite.base ?? null
709
807
  const site = {
@@ -723,9 +821,9 @@ export const buildPagesContext = async ({ compileAll = true } = {}) => {
723
821
  },
724
822
  generatedAt: new Date().toISOString()
725
823
  }
726
- const excludedDirPaths = new Set(Array.from(excludedDirs).map((dir) => `/${dir}`))
824
+ const excludedDirPaths = new Set(Array.from(dirExcludes).map((dir) => `/${dir}`))
727
825
  const pagesContext = {
728
- pages,
826
+ pages: pageList,
729
827
  pagesByRoute,
730
828
  getPageByRoute,
731
829
  pagesTree,
@@ -775,34 +873,96 @@ export const buildPagesContext = async ({ compileAll = true } = {}) => {
775
873
  pagesContext.getLanguageForRoute = (routePath) =>
776
874
  resolveLanguageForRoute(pagesContext.languages, routePath)
777
875
  },
778
- excludedRoutes,
779
- excludedDirs,
876
+ excludedRoutes: routeExcludes,
877
+ excludedDirs: dirExcludes,
780
878
  excludedDirPaths,
781
879
  notFound,
782
880
  languages,
783
881
  getLanguageForRoute: (routePath) => resolveLanguageForRoute(languages, routePath),
784
882
  site
785
883
  }
884
+ return pagesContext
885
+ }
886
+
887
+ export const buildPagesContext = async ({ compileAll = true } = {}) => {
888
+ const logEnabled = state.CURRENT_MODE === 'production' && cli.command === 'build'
889
+ const stageLogger = createStageLogger(logEnabled)
890
+ const collectToken = stageLogger.start('Collecting pages')
891
+ const collected = await collectPages()
892
+ stageLogger.end(collectToken)
893
+ let pages = collected.pages
894
+ const excludedRoutes = collected.excludedRoutes
895
+ const excludedDirs = collected.excludedDirs
896
+ const hasIndex = pages.some((page) => page.routePath === '/')
897
+ if (!hasIndex) {
898
+ const content = buildIndexFallback(pages, state.SITE_NAME)
899
+ pages.unshift({
900
+ routePath: '/',
901
+ routeHref: withBase('/'),
902
+ path: resolve(state.PAGES_DIR, 'index.md'),
903
+ relativePath: 'index.md',
904
+ name: 'index',
905
+ dir: '',
906
+ segments: [],
907
+ depth: 0,
908
+ isIndex: true,
909
+ title: state.SITE_NAME || 'Methanol Site',
910
+ weight: null,
911
+ date: null,
912
+ isRoot: false,
913
+ hidden: false,
914
+ content,
915
+ frontmatter: {},
916
+ matter: null,
917
+ stats: { size: content.length, createdAt: null, updatedAt: null },
918
+ createdAt: null,
919
+ updatedAt: null
920
+ })
921
+ if (excludedRoutes?.has('/')) {
922
+ excludedRoutes.delete('/')
923
+ }
924
+ }
925
+
926
+ const pagesContext = createPagesContextFromPages({
927
+ pages,
928
+ excludedRoutes,
929
+ excludedDirs
930
+ })
786
931
  if (compileAll) {
787
932
  const compileToken = stageLogger.start('Compiling MDX')
788
- const totalPages = pages.length
789
- for (let i = 0; i < pages.length; i++) {
790
- const page = pages[i]
791
- if (logEnabled) {
933
+ const compileTargets = pages.filter((page) => page && page.content != null && !page.mdxComponent)
934
+ const totalPages = compileTargets.length
935
+ let completed = 0
936
+ const compiledSources = await compileMdxSources(compileTargets, {
937
+ onProgress: (page) => {
938
+ if (!logEnabled) return
939
+ completed += 1
792
940
  stageLogger.update(
793
941
  compileToken,
794
- `Compiling MDX [${i + 1}/${totalPages}] ${page.routePath || page.path}`
942
+ `Compiling MDX [${completed}/${totalPages}] ${page.routePath || page.path}`
795
943
  )
796
944
  }
945
+ })
946
+ stageLogger.end(compileToken)
947
+ const executeToken = stageLogger.start('Running MDX')
948
+ completed = 0
949
+ for (const page of compileTargets) {
950
+ const compiled = compiledSources.get(page) || null
797
951
  await compilePageMdx(page, pagesContext, {
798
952
  lazyPagesTree: true,
799
- refreshPagesTree: false
953
+ refreshPagesTree: false,
954
+ compiled
800
955
  })
956
+ if (logEnabled) {
957
+ completed += 1
958
+ stageLogger.update(
959
+ executeToken,
960
+ `Running MDX [${completed}/${totalPages}] ${page.routePath || page.path}`
961
+ )
962
+ }
801
963
  }
802
- stageLogger.end(compileToken)
803
- pagesTreeCache.clear()
804
- pagesTree = getPagesTree('/')
805
- pagesContext.pagesTree = pagesTree
964
+ stageLogger.end(executeToken)
965
+ pagesContext.refreshPagesTree?.()
806
966
  }
807
967
  return pagesContext
808
968
  }
package/src/reframe.js CHANGED
@@ -18,6 +18,7 @@
18
18
  * under the License.
19
19
  */
20
20
 
21
+ import { lazy } from 'refui'
21
22
  import fnv1a from '@sindresorhus/fnv1a'
22
23
  import JSON5 from 'json5'
23
24
 
@@ -45,8 +46,12 @@ export function env(parentEnv) {
45
46
 
46
47
  let renderCount = 0
47
48
 
48
- function client(info) {
49
- const { clientPath, staticComponent, exportName } = info
49
+ function register(info) {
50
+ const { clientPath, staticPath, staticImportURL, exportName } = info
51
+
52
+ if (!clientPath) {
53
+ return lazy(() => import(staticImportURL))
54
+ }
50
55
 
51
56
  let key = null
52
57
  let _clientPath = clientPath
@@ -55,7 +60,9 @@ export function env(parentEnv) {
55
60
  key = hash(_clientPath)
56
61
  } while (keyPathRegistry[key] && keyPathRegistry[key] !== clientPath)
57
62
 
58
- const component = ({ children: childrenProp, ...props }, ...children) => {
63
+ const component = async ({ children: childrenProp, ...props }, ...children) => {
64
+ const staticComponent = (await import(staticImportURL)).default
65
+
59
66
  const id = renderCount++
60
67
  const idStr = id.toString(16)
61
68
  const script = `$$rfrm(${JSON.stringify(key)},${id},${Object.keys(props).length ? JSON5.stringify(props) : '{}'})`
@@ -63,13 +70,13 @@ export function env(parentEnv) {
63
70
  return (R) => {
64
71
  return [
65
72
  R.createAnchor(`{${idStr}}`, true),
66
- R.c(
73
+ staticComponent ? R.c(
67
74
  staticComponent,
68
75
  props,
69
76
  R.createAnchor(`[${idStr}[`, true),
70
77
  ...children,
71
78
  R.createAnchor(`]${idStr}]`, true)
72
- ),
79
+ ): null,
73
80
  R.c('script', null, R.rawHTML(script))
74
81
  ]
75
82
  }
@@ -106,7 +113,7 @@ export function env(parentEnv) {
106
113
  }
107
114
 
108
115
  return {
109
- client,
116
+ register,
110
117
  invalidate,
111
118
  genRegistryScript,
112
119
  setParent,
@@ -41,7 +41,8 @@ export const createStageLogger = (enabled) => {
41
41
  }
42
42
  const padding = lastLength > text.length ? ' '.repeat(lastLength - text.length) : ''
43
43
  const clearLine = '\u001b[2K'
44
- process.stdout.write(`${clearLine}\r${text}${padding}${newline ? '\n' : ''}`)
44
+ const reset = '\x1b[0m'
45
+ process.stdout.write(`${clearLine}\r${reset}${text}${reset}${padding}${newline ? '\n' : ''}`)
45
46
  lastLength = text.length
46
47
  }
47
48
  const start = (label) => {
package/src/state.js CHANGED
@@ -104,14 +104,14 @@ const withCommonOptions = (y) =>
104
104
  .option('highlight', {
105
105
  describe: 'Enable or disable code highlighting',
106
106
  type: 'boolean',
107
- coerce: (value) => {
108
- if (value == null) return null
109
- if (typeof value === 'boolean') return value
110
- const normalized = String(value).trim().toLowerCase()
111
- if (normalized === 'true') return true
112
- if (normalized === 'false') return false
113
- return null
114
- }
107
+ default: undefined
108
+ })
109
+ .option('jobs', {
110
+ alias: 'j',
111
+ describe: 'Worker thread count (0 for auto)',
112
+ type: 'number',
113
+ requiresArg: true,
114
+ nargs: 1
115
115
  })
116
116
  .option('verbose', {
117
117
  alias: 'v',
@@ -126,12 +126,14 @@ const withCommonOptions = (y) =>
126
126
  nargs: 1
127
127
  })
128
128
  .option('search', {
129
- describe: 'Enable search indexing (pagefind)',
130
- type: 'boolean'
129
+ describe: 'Enable or disable search indexing (pagefind)',
130
+ type: 'boolean',
131
+ default: undefined
131
132
  })
132
133
  .option('pwa', {
133
- describe: 'Enable PWA support',
134
- type: 'boolean'
134
+ describe: 'Enable or disable PWA support',
135
+ type: 'boolean',
136
+ default: undefined
135
137
  })
136
138
 
137
139
  const parser = yargs(hideBin(process.argv))
@@ -161,10 +163,11 @@ export const cli = {
161
163
  CLI_CONFIG_PATH: argv.config || null,
162
164
  CLI_SITE_NAME: argv['site-name'] || null,
163
165
  CLI_CODE_HIGHLIGHTING: typeof argv.highlight === 'boolean' ? argv.highlight : null,
166
+ CLI_JOBS: typeof argv.jobs === 'number' && Number.isFinite(argv.jobs) ? argv.jobs : null,
164
167
  CLI_VERBOSE: Boolean(argv.verbose),
165
168
  CLI_BASE: argv.base || null,
166
- CLI_SEARCH: argv.search,
167
- CLI_PWA: argv.pwa
169
+ CLI_SEARCH: typeof argv.search === 'boolean' ? argv.search : undefined,
170
+ CLI_PWA: typeof argv.pwa === 'boolean' ? argv.pwa : undefined
168
171
  }
169
172
 
170
173
  export const state = {
@@ -204,6 +207,7 @@ export const state = {
204
207
  THEME_POST_BUNDLE_HOOKS: [],
205
208
  STARRY_NIGHT_ENABLED: false,
206
209
  STARRY_NIGHT_OPTIONS: null,
210
+ WORKER_JOBS: 0,
207
211
  GFM_ENABLED: true,
208
212
  PWA_ENABLED: false,
209
213
  PWA_OPTIONS: null,