methanol 0.0.12 → 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/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  Opinionated MDX-first static site generator powered by rEFui + Vite.
4
4
 
5
- For full documentation and examples, visit [Methanol Docs](https://methanol.netlify.app/).
5
+ For full documentation and examples, visit [Methanol Docs](https://methanol.sudomaker.com/).
6
6
 
7
7
  ## Quick start
8
8
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "methanol",
3
- "version": "0.0.12",
3
+ "version": "0.0.13",
4
4
  "description": "Static site generator powered by rEFui and MDX",
5
5
  "main": "./index.js",
6
6
  "type": "module",
@@ -36,7 +36,7 @@
36
36
  "hast-util-is-element": "^3.0.0",
37
37
  "json5": "^2.2.3",
38
38
  "null-prototype-object": "^1.2.5",
39
- "refui": "^0.16.3",
39
+ "refui": "^0.16.4",
40
40
  "refurbish": "^0.1.8",
41
41
  "rehype-slug": "^6.0.0",
42
42
  "rehype-starry-night": "^2.2.0",
@@ -78,7 +78,7 @@ export const buildHtmlEntries = async () => {
78
78
  if (themeComponentsDir) {
79
79
  await buildComponentRegistry({
80
80
  componentsDir: themeComponentsDir,
81
- client: themeEnv.client
81
+ register: themeEnv.register
82
82
  })
83
83
  }
84
84
  await buildComponentRegistry()
package/src/components.js CHANGED
@@ -48,21 +48,24 @@ export const bumpComponentImportNonce = () => {
48
48
  }
49
49
 
50
50
  export const reframeEnv = env()
51
- export const client = reframeEnv.client
51
+ export const register = reframeEnv.register
52
52
  export const invalidateRegistryEntry = reframeEnv.invalidate
53
53
  export const genRegistryScript = reframeEnv.genRegistryScript
54
54
 
55
- const resolveComponentExport = (componentPath, ext) => {
55
+ const resolveComponentExport = (componentPath, exportName, ext) => {
56
56
  const staticCandidate = `${componentPath}.static${ext}`
57
57
  const clientCandidate = `${componentPath}.client${ext}`
58
58
  const genericCandidate = `${componentPath}${ext}`
59
- const ret = {}
59
+ const ret = { exportName }
60
+
60
61
  if (existsSync(staticCandidate)) {
61
62
  ret.staticPath = staticCandidate
62
63
  }
64
+
63
65
  if (existsSync(clientCandidate)) {
64
66
  ret.clientPath = clientCandidate
65
67
  }
68
+
66
69
  if (!ret.staticPath) {
67
70
  if (existsSync(genericCandidate)) {
68
71
  ret.staticPath = genericCandidate
@@ -70,34 +73,29 @@ const resolveComponentExport = (componentPath, ext) => {
70
73
  ret.staticPath = clientCandidate
71
74
  }
72
75
  }
73
- return ret
74
- }
75
76
 
76
- export const buildComponentEntry = async ({ dir, exportName, ext, client: clientFn = client }) => {
77
- const info = resolveComponentExport(join(dir, exportName), ext)
78
- if (!info.staticPath) {
79
- return { component: null, hasClient: false, staticPath: null, clientPath: null }
77
+ if (ret.staticPath) {
78
+ ret.staticImportURL = `${pathToFileURL(ret.staticPath).href}?t=${componentImportNonce}`
80
79
  }
81
80
 
82
- let component = (await import(`${pathToFileURL(info.staticPath).href}?t=${componentImportNonce}`)).default
81
+ return ret
82
+ }
83
83
 
84
- if (!component) {
84
+ export const buildComponentEntry = async ({ dir, exportName, ext, register: registerFn = register }) => {
85
+ const info = resolveComponentExport(join(dir, exportName), exportName, ext)
86
+ if (!info.staticPath) {
85
87
  return { component: null, hasClient: false, staticPath: null, clientPath: null }
86
88
  }
87
89
 
88
- if (info.clientPath) {
89
- component = clientFn({ ...info, staticComponent: component, exportName })
90
- }
91
-
92
90
  return {
93
- component,
91
+ component: registerFn(info),
94
92
  hasClient: Boolean(info.clientPath),
95
93
  staticPath: info.staticPath,
96
94
  clientPath: info.clientPath || null
97
95
  }
98
96
  }
99
97
 
100
- export const buildComponentRegistry = async ({ componentsDir = state.COMPONENTS_DIR, client: clientFn = client } = {}) => {
98
+ export const buildComponentRegistry = async ({ componentsDir = state.COMPONENTS_DIR, register: registerFn = register } = {}) => {
101
99
  const components = {}
102
100
  const sources = new Map()
103
101
 
@@ -130,7 +128,7 @@ export const buildComponentRegistry = async ({ componentsDir = state.COMPONENTS_
130
128
  dir,
131
129
  exportName,
132
130
  ext: extname(entry),
133
- client: clientFn
131
+ register: registerFn
134
132
  })
135
133
  if (!component) continue
136
134
  components[exportName] = component
package/src/dev-server.js CHANGED
@@ -129,7 +129,7 @@ export const runViteDev = async () => {
129
129
  const themeRegistry = themeComponentsDir
130
130
  ? await buildComponentRegistry({
131
131
  componentsDir: themeComponentsDir,
132
- client: themeEnv.client
132
+ register: themeEnv.register
133
133
  })
134
134
  : { components: {} }
135
135
  const themeComponents = {
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
 
@@ -331,6 +324,7 @@ export const compilePageMdx = async (page, pagesContext, options = {}) => {
331
324
  pagesContext,
332
325
  lazyPagesTree
333
326
  })
327
+ page.mdxCtx = activeCtx
334
328
  const mdxModule = compiled?.code
335
329
  ? await runMdxSource({
336
330
  code: compiled.code,
@@ -373,55 +367,52 @@ export const renderHtml = async ({ routePath, path, components, pagesContext, pa
373
367
 
374
368
  await compilePageMdx(pageMeta, pagesContext, { ctx })
375
369
 
370
+ const [Head, Outlet] = createPortal()
371
+ const ExtraHead = () => {
372
+ return [
373
+ resolveRewindInject(),
374
+ ...resolveUserHeadAssets(),
375
+ ...resolvePageHeadAssets(pageMeta),
376
+ Outlet(),
377
+ RWND_FALLBACK
378
+ ]
379
+ }
380
+
381
+ const PageContent = ({ components: extraComponents, ...props }, ...children) =>
382
+ mdxComponent({
383
+ children,
384
+ ...props,
385
+ components: {
386
+ ...components,
387
+ ...extraComponents,
388
+ head: Head,
389
+ Head
390
+ }
391
+ })
392
+
376
393
  const template = state.USER_THEME.template
377
394
  const mdxComponent = pageMeta.mdxComponent
378
395
 
379
396
  const renderResult = await new Promise((resolve, reject) => {
380
- const [Head, Outlet] = createPortal()
381
- const ExtraHead = () => {
382
- return [
383
- resolveRewindInject(),
384
- ...resolveUserHeadAssets(),
385
- ...resolvePageHeadAssets(pageMeta),
386
- Outlet(),
387
- RWND_FALLBACK
388
- ]
389
- }
390
-
391
- const PageContent = ({ components: extraComponents, ...props }, ...children) => {
392
- try {
393
- return mdxComponent({
394
- children,
395
- ...props,
396
- components: {
397
- ...components,
398
- ...extraComponents,
399
- head: Head,
400
- Head
401
- }
402
- })
403
- } catch (e) {
404
- reject(e)
405
- }
406
- }
407
-
408
397
  const result = HTMLRenderer.c(
409
398
  Suspense,
410
399
  {
411
400
  onLoad() {
412
401
  nextTick(() => resolve(result))
402
+ },
403
+ catch({ error }) {
404
+ reject(error)
413
405
  }
414
406
  },
415
- () =>
416
- template({
417
- ctx,
418
- page: ctx.page,
419
- withBase,
420
- PageContent,
421
- ExtraHead,
422
- HTMLRenderer,
423
- components
424
- })
407
+ template({
408
+ ctx,
409
+ page: ctx.page,
410
+ withBase,
411
+ PageContent,
412
+ ExtraHead,
413
+ HTMLRenderer,
414
+ components
415
+ })
425
416
  )
426
417
  })
427
418
 
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) => {
@@ -46,7 +46,7 @@ const ensureInit = async () => {
46
46
  const themeRegistry = themeComponentsDir
47
47
  ? await buildComponentRegistry({
48
48
  componentsDir: themeComponentsDir,
49
- client: themeEnv.client
49
+ register: themeEnv.register
50
50
  })
51
51
  : { components: {} }
52
52
  const themeComponents = {
@@ -71,6 +71,30 @@ const rebuildPagesContext = async (excludedRoutes, excludedDirs) => {
71
71
  })
72
72
  }
73
73
 
74
+ const refreshMdxCtx = (page) => {
75
+ if (!page?.mdxCtx || !pagesContext) return
76
+ const ctx = page.mdxCtx
77
+ ctx.page = page
78
+ ctx.pages = pagesContext.pages || []
79
+ ctx.pagesByRoute = pagesContext.pagesByRoute || new Map()
80
+ ctx.languages = pagesContext.languages || []
81
+ ctx.language = pagesContext.getLanguageForRoute
82
+ ? pagesContext.getLanguageForRoute(page.routePath)
83
+ : null
84
+ ctx.site = pagesContext.site || null
85
+ ctx.getSiblings = pagesContext.getSiblings
86
+ ? () => pagesContext.getSiblings(page.routePath, page.path)
87
+ : null
88
+ if (page && ctx.getSiblings && page.getSiblings !== ctx.getSiblings) {
89
+ page.getSiblings = ctx.getSiblings
90
+ }
91
+ if (pagesContext.getPagesTree) {
92
+ ctx.pagesTree = pagesContext.getPagesTree(page.routePath)
93
+ } else {
94
+ ctx.pagesTree = pagesContext.pagesTree || []
95
+ }
96
+ }
97
+
74
98
  const serializeError = (error) => {
75
99
  if (!error) return 'Unknown error'
76
100
  if (error.stack) return error.stack
@@ -112,6 +136,10 @@ const handleSyncUpdates = async (message) => {
112
136
  excludedRoutes ? new Set(excludedRoutes) : pagesContext?.excludedRoutes || new Set(),
113
137
  excludedDirs ? new Set(excludedDirs) : pagesContext?.excludedDirs || new Set()
114
138
  )
139
+ for (const page of pages) {
140
+ if (!page?.mdxCtx) continue
141
+ refreshMdxCtx(page)
142
+ }
115
143
  }
116
144
 
117
145
  const handleCompile = async (message) => {
@@ -18,6 +18,6 @@
18
18
  * under the License.
19
19
  */
20
20
 
21
- export default function () {
22
- // render nothing on server side
23
- }
21
+ // Nothing needs to be rendered on the server side for accent switch
22
+ // But we explicitly need to keep a file here to prevent Methanol from
23
+ // rendering the client version as fallback
@@ -18,6 +18,6 @@
18
18
  * under the License.
19
19
  */
20
20
 
21
- export default function () {
22
- // render nothing on server side
23
- }
21
+ // Nothing needs to be rendered on the server side for accent switch
22
+ // But we explicitly need to keep a file here to prevent Methanol from
23
+ // rendering the client version as fallback
@@ -38,7 +38,7 @@ export default function (props, ...children) {
38
38
  }
39
39
  }
40
40
 
41
- const Btn = copied.choose(
41
+ const BtnImg = copied.choose(
42
42
  () => (
43
43
  <svg
44
44
  attr:width="14"
@@ -74,7 +74,7 @@ export default function (props, ...children) {
74
74
  return (
75
75
  <div class="code-block-container">
76
76
  <button class="copy-btn" on:click={copy} attr:aria-label="Copy code">
77
- <Btn />
77
+ <BtnImg />
78
78
  </button>
79
79
  <pre {...props} $ref={el}>
80
80
  {...children}
@@ -29,7 +29,7 @@
29
29
  if (savedAccent && savedAccent !== 'default') {
30
30
  document.documentElement.classList.add('accent-' + savedAccent)
31
31
  }
32
- })()
32
+ })
33
33
  ;(function initPrefetch() {
34
34
  const prefetched = new Set()
35
35
  const canPrefetch = (anchor) => {
@@ -58,4 +58,5 @@
58
58
  document.head.appendChild(link)
59
59
  }
60
60
  document.addEventListener('pointerover', onHover, { capture: true, passive: true })
61
- })()
61
+ })
62
+ console.log('theme prep')
@@ -22,7 +22,7 @@ import { HTMLRenderer as R, DOCTYPE_HTML } from 'methanol'
22
22
  import { renderToc } from '../components/ThemeToCContainer.static.jsx'
23
23
  import { renderNavTree } from './nav-tree.jsx'
24
24
 
25
- const PAGE_TEMPLATE = async ({ PageContent, ExtraHead, components, ctx }) => {
25
+ const PAGE_TEMPLATE = ({ PageContent, ExtraHead, components, ctx }) => {
26
26
  const page = ctx.page
27
27
  const pagesByRoute = ctx.pagesByRoute
28
28
  const pages = ctx.pages || []
@@ -122,13 +122,13 @@ const PAGE_TEMPLATE = async ({ PageContent, ExtraHead, components, ctx }) => {
122
122
  {twitterTitle ? <meta name="twitter:title" content={twitterTitle} /> : null}
123
123
  {twitterDescription ? <meta name="twitter:description" content={twitterDescription} /> : null}
124
124
  {twitterImage ? <meta name="twitter:image" content={twitterImage} /> : null}
125
- <ExtraHead />
126
125
  <link
127
126
  rel="preload stylesheet"
128
127
  as="style"
129
128
  href="/.methanol_theme_default/style.css"
130
129
  />
131
- <script src="/theme-prepare.js"></script>
130
+ <script type="module" src="/.methanol_theme_default/theme-prepare.js"></script>
131
+ <ExtraHead />
132
132
  </head>
133
133
  <body>
134
134
  <input type="checkbox" id="nav-toggle" class="nav-toggle" />