methanol 0.0.17 → 0.0.19

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
@@ -64,6 +64,10 @@ export default () => ({
64
64
  })
65
65
  ```
66
66
 
67
+ ## Themes
68
+
69
+ Methanol includes built-in themes (`default`, `blog`). Use `--theme <name>` or set `theme: '<name>'` in config. For local themes inside your project, import the theme entry in `methanol.config.*` and pass the theme object/factory.
70
+
67
71
  ## CLI notes
68
72
 
69
73
  - `methanol preview` is an alias for `methanol serve`
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "methanol",
3
- "version": "0.0.17",
3
+ "version": "0.0.19",
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.4",
39
+ "refui": "^0.17.1",
40
40
  "refurbish": "^0.1.8",
41
41
  "rehype-slug": "^6.0.0",
42
42
  "rehype-starry-night": "^2.2.0",
package/src/client/sw.js CHANGED
@@ -139,7 +139,6 @@ self.addEventListener('install', (event) => {
139
139
  const assetCache = await openCache(ASSETS_CACHE)
140
140
  const manifestEntries = getManifestEntries()
141
141
  const manifestMap = buildManifestMap(manifestEntries)
142
- const previousMap = await loadStoredManifestMap()
143
142
  const manifestUrls = manifestEntries.map((entry) => entry.url)
144
143
  const [prioritized] = prioritizeManifestUrls(manifestUrls)
145
144
  const { failedIndex } = await runConcurrentQueue(prioritized, {
@@ -150,11 +149,9 @@ self.addEventListener('install', (event) => {
150
149
  const cached = await matchCache(cacheName, url)
151
150
  const key = manifestKey(url)
152
151
  const currentRevision = manifestMap.get(key) ?? null
153
- const previousRevision = previousMap.get(key) ?? null
154
152
  const shouldFetch = shouldFetchWithRevision({
155
153
  cached,
156
- currentRevision,
157
- previousRevision
154
+ currentRevision
158
155
  })
159
156
  if (!shouldFetch) return true
160
157
  const cache = isHtml ? pageCache : assetCache
@@ -272,11 +269,12 @@ async function runConcurrentQueue(list, { concurrency, handler, stopOnError = tr
272
269
  return { ok: failedIndex === null, failedIndex }
273
270
  }
274
271
 
275
- function shouldFetchWithRevision({ cached, currentRevision, previousRevision }) {
272
+ function shouldFetchWithRevision({ cached, currentRevision }) {
276
273
  if (!cached) return true
277
274
  if (currentRevision == null) return false
278
- if (previousRevision == null) return true
279
- return currentRevision !== previousRevision
275
+ const cachedRevision = cached.headers?.get?.(REVISION_HEADER)
276
+ if (cachedRevision == null) return true
277
+ return cachedRevision !== String(currentRevision)
280
278
  }
281
279
 
282
280
  function shouldRevalidateCached(cached, currentRevision) {
@@ -550,7 +548,6 @@ const DB_STORE = 'kv'
550
548
  const KEY_INDEX = 'warmIndex'
551
549
  const KEY_LEASE = 'warmLease'
552
550
  const KEY_FORCE = 'warmForce'
553
- const KEY_MANIFEST = 'warmManifest'
554
551
 
555
552
  function idbOpen() {
556
553
  return new Promise((resolve, reject) => {
@@ -611,12 +608,6 @@ function buildManifestMap(entries) {
611
608
  return map
612
609
  }
613
610
 
614
- async function loadStoredManifestMap() {
615
- const stored = await idbGet(KEY_MANIFEST)
616
- if (!stored) return new Map()
617
- if (Array.isArray(stored)) return buildManifestMap(stored)
618
- return new Map()
619
- }
620
611
 
621
612
  async function tryAcquireLease(leaseMs) {
622
613
  const leaseId = randomId()
@@ -667,7 +658,6 @@ async function warmManifestResumable({ force = false } = {}) {
667
658
  try {
668
659
  const manifestEntries = getManifestEntries()
669
660
  const manifestMap = buildManifestMap(manifestEntries)
670
- const previousMap = await loadStoredManifestMap()
671
661
  const [, urls] = prioritizeManifestUrls(manifestEntries.map((entry) => entry.url))
672
662
  if (!urls.length) return
673
663
  if (index >= urls.length) {
@@ -685,14 +675,12 @@ async function warmManifestResumable({ force = false } = {}) {
685
675
  const isHtml = abs.endsWith('.html')
686
676
  const key = manifestKey(abs)
687
677
  const currentRevision = manifestMap.get(key) ?? null
688
- const previousRevision = previousMap.get(key) ?? null
689
678
 
690
679
  if (isHtml) {
691
680
  const cached = await matchCache(PAGES_CACHE, abs)
692
681
  const shouldFetch = shouldFetchWithRevision({
693
682
  cached,
694
- currentRevision,
695
- previousRevision
683
+ currentRevision
696
684
  })
697
685
  if (!shouldFetch) return true
698
686
 
@@ -709,8 +697,7 @@ async function warmManifestResumable({ force = false } = {}) {
709
697
  const cached = await matchCache(ASSETS_CACHE, abs)
710
698
  const shouldFetch = shouldFetchWithRevision({
711
699
  cached,
712
- currentRevision,
713
- previousRevision
700
+ currentRevision
714
701
  })
715
702
  if (!shouldFetch) return true
716
703
 
@@ -738,7 +725,6 @@ async function warmManifestResumable({ force = false } = {}) {
738
725
  completed = true
739
726
  } finally {
740
727
  if (completed) {
741
- await idbSet(KEY_MANIFEST, getManifestEntries())
742
728
  await idbSet(KEY_FORCE, 0)
743
729
  }
744
730
  await releaseLease(lease)
package/src/components.js CHANGED
@@ -51,6 +51,7 @@ export const reframeEnv = env()
51
51
  export const register = reframeEnv.register
52
52
  export const invalidateRegistryEntry = reframeEnv.invalidate
53
53
  export const genRegistryScript = reframeEnv.genRegistryScript
54
+ export const resetReframeRenderCount = () => reframeEnv.resetRenderCount()
54
55
 
55
56
  const resolveComponentExport = (componentPath, exportName, ext) => {
56
57
  const staticCandidate = `${componentPath}.static${ext}`
@@ -75,7 +76,9 @@ const resolveComponentExport = (componentPath, exportName, ext) => {
75
76
  }
76
77
 
77
78
  if (ret.staticPath) {
78
- ret.staticImportURL = `${pathToFileURL(ret.staticPath).href}?t=${componentImportNonce}`
79
+ const baseUrl = pathToFileURL(ret.staticPath).href
80
+ ret.staticImportURL =
81
+ state.CURRENT_MODE === 'production' ? baseUrl : `${baseUrl}?t=${componentImportNonce}`
79
82
  }
80
83
 
81
84
  return ret
package/src/mdx.js CHANGED
@@ -38,6 +38,7 @@ import { resolveUserMdxConfig, withBase } from './config.js'
38
38
  import { methanolCtx } from './rehype-plugins/methanol-ctx.js'
39
39
  import { linkResolve } from './rehype-plugins/link-resolve.js'
40
40
  import { cached } from './utils.js'
41
+ import { resetReframeRenderCount } from './components.js'
41
42
 
42
43
  // Workaround for Vite: it doesn't support resolving module/virtual modules in script src in dev mode
43
44
  const resolveRewindInject = cached(() =>
@@ -585,6 +586,7 @@ export const compilePageMdx = async (page, pagesContext, options = {}) => {
585
586
  }
586
587
 
587
588
  export const renderHtml = async ({ routePath, path, components, pagesContext, pageMeta }) => {
589
+ resetReframeRenderCount()
588
590
  const ctx = buildPageContext({
589
591
  routePath,
590
592
  path,
package/src/reframe.js CHANGED
@@ -61,10 +61,10 @@ export function env(parentEnv) {
61
61
  } while (keyPathRegistry[key] && keyPathRegistry[key] !== clientPath)
62
62
 
63
63
  const component = async ({ children: childrenProp, ...props }, ...children) => {
64
- const staticComponent = (await import(staticImportURL)).default
65
-
66
64
  const id = renderCount++
67
65
  const idStr = id.toString(16)
66
+
67
+ const staticComponent = (await import(staticImportURL)).default
68
68
  const script = `$$rfrm(${JSON.stringify(key)},${id},${Object.keys(props).length ? JSON5.stringify(props).replace(/<\/script/ig, '<\\/script') : '{}'})`
69
69
 
70
70
  return (R) => {
@@ -101,6 +101,11 @@ export function env(parentEnv) {
101
101
  parent = nextParent || null
102
102
  }
103
103
 
104
+ function resetRenderCount() {
105
+ renderCount = 0
106
+ parent?.resetRenderCount()
107
+ }
108
+
104
109
  function getMergedRegistry() {
105
110
  return Object.assign({}, parent?.registry, registry)
106
111
  }
@@ -117,6 +122,7 @@ export function env(parentEnv) {
117
122
  invalidate,
118
123
  genRegistryScript,
119
124
  setParent,
125
+ resetRenderCount,
120
126
  get registry() {
121
127
  return getMergedRegistry()
122
128
  }
@@ -0,0 +1,52 @@
1
+ # Themes
2
+
3
+ Methanol ships with built-in themes under `themes/`.
4
+
5
+ ## Built-in themes
6
+
7
+ - `default`: Documentation-style theme (sidebar + ToC).
8
+ - `blog`: Blog theme (post list, tags/categories UI).
9
+
10
+ ## Using a theme
11
+
12
+ CLI:
13
+
14
+ ```bash
15
+ methanol build --theme blog
16
+ methanol dev --theme default
17
+ ```
18
+
19
+ Config (`methanol.config.*`):
20
+
21
+ ```js
22
+ export default () => ({
23
+ theme: 'blog'
24
+ })
25
+ ```
26
+
27
+ ## Using a local theme (in your project)
28
+
29
+ Theme name resolution only applies when `theme` is a string (built-in or `methanol-theme-xxx` from `node_modules`).
30
+ If your theme lives inside your project, import it and pass the theme object/factory:
31
+
32
+ ```js
33
+ import createTheme from './themes/my-theme/index.js'
34
+
35
+ export default () => ({
36
+ theme: createTheme()
37
+ })
38
+ ```
39
+
40
+ ## Publishing a theme
41
+
42
+ If you publish a theme as an npm package named `methanol-theme-xxx`, users can enable it via `--theme xxx` or `theme: 'xxx'`.
43
+
44
+ ## Theme structure (convention)
45
+
46
+ - `index.js`: entrypoint that exports a theme object or a factory function (recommended).
47
+ - `src/`: theme runtime/template modules (e.g. `src/page.jsx`).
48
+ - `components/`: theme components (used by MDX).
49
+ - `pages/`: theme-provided pages (e.g. `_404.mdx`, `offline.mdx`).
50
+ - `public/`: theme static assets (merged with user `public/`).
51
+ - `sources/`: extra source mappings exposed via `theme.sources`.
52
+
@@ -1,26 +1,46 @@
1
1
  # Blog Theme
2
2
 
3
- A simple, clean blog theme for Methanol.
3
+ A blog theme for Methanol.
4
4
 
5
5
  ## Features
6
- - Clean typography
7
- - Post list on homepage
8
- - Responsive design
9
- - Dark mode support (via system preference)
6
+
7
+ - Post list and post pages
8
+ - Category/collection views (theme-provided client UI)
9
+ - Responsive layout
10
10
 
11
11
  ## Usage
12
12
 
13
- To use this theme, configure your Methanol project to point to this directory.
13
+ CLI:
14
+
15
+ ```bash
16
+ methanol build --theme blog
17
+ methanol dev --theme blog
18
+ ```
19
+
20
+ Config (`methanol.config.*`):
14
21
 
15
22
  ```js
16
- // methanol.config.js
17
- export default {
18
- theme: './themes/blog',
19
- // ...
20
- }
23
+ export default () => ({
24
+ theme: 'blog'
25
+ })
21
26
  ```
22
27
 
23
28
  ## Structure
24
- - `src/page.jsx`: Main layout template.
25
- - `sources/style.css`: Stylesheet.
26
- - `pages/`: Default pages (Home, 404, Offline).
29
+
30
+ - `src/page.jsx`: main layout template
31
+ - `pages/`: theme pages (including special pages like `_404.mdx` and `offline.mdx` when present)
32
+ - `components/`: theme components used by MDX
33
+ - `public/`: theme static assets
34
+ - `sources/`: theme source mappings (used by `theme.sources`)
35
+
36
+ ## Local development
37
+
38
+ If you want to use the theme from a local folder (instead of built-in name / npm package), import it in config:
39
+
40
+ ```js
41
+ import createBlogTheme from './themes/blog/index.js'
42
+
43
+ export default () => ({
44
+ theme: createBlogTheme()
45
+ })
46
+ ```
@@ -0,0 +1,26 @@
1
+ # Default Theme
2
+
3
+ The default Methanol theme is designed for documentation sites (sidebar navigation + table of contents).
4
+
5
+ ## Enable
6
+
7
+ CLI:
8
+
9
+ ```bash
10
+ methanol build --theme default
11
+ methanol dev --theme default
12
+ ```
13
+
14
+ Config:
15
+
16
+ ```js
17
+ export default () => ({
18
+ theme: 'default'
19
+ })
20
+ ```
21
+
22
+ ## Notes
23
+
24
+ - User `public/` assets override theme-provided `public/` assets.
25
+ - Theme pages under `pages/` can provide special routes like `_404.mdx` and `offline.mdx`.
26
+
@@ -75,6 +75,19 @@ export default function () {
75
75
  localStorage.setItem('methanol-theme', theme.value)
76
76
  document.documentElement.classList.toggle('light', theme.value === 'light')
77
77
  document.documentElement.classList.toggle('dark', theme.value === 'dark')
78
+
79
+ const metas = document.querySelectorAll('meta[name="theme-color"]')
80
+ let meta = metas[0]
81
+ if (!meta) {
82
+ meta = document.createElement('meta')
83
+ meta.name = 'theme-color'
84
+ document.head.appendChild(meta)
85
+ }
86
+ for (let i = 1; i < metas.length; i++) {
87
+ metas[i].remove()
88
+ }
89
+ meta.content = theme.value === 'light' ? '#ffffff' : '#09090b'
90
+ meta.removeAttribute('media')
78
91
  }
79
92
 
80
93
  const CurrentIcon = $(() => {
@@ -25,6 +25,19 @@
25
25
  document.documentElement.classList.toggle('light', theme === 'light')
26
26
  document.documentElement.classList.toggle('dark', theme === 'dark')
27
27
 
28
+ const metas = document.querySelectorAll('meta[name="theme-color"]')
29
+ let meta = metas[0]
30
+ if (!meta) {
31
+ meta = document.createElement('meta')
32
+ meta.name = 'theme-color'
33
+ document.head.appendChild(meta)
34
+ }
35
+ for (let i = 1; i < metas.length; i++) {
36
+ metas[i].remove()
37
+ }
38
+ meta.content = theme === 'light' ? '#ffffff' : '#09090b'
39
+ meta.removeAttribute('media')
40
+
28
41
  const savedAccent = localStorage.getItem('methanol-accent')
29
42
  if (savedAccent && savedAccent !== 'default') {
30
43
  document.documentElement.classList.add('accent-' + savedAccent)
@@ -108,6 +108,8 @@ const PAGE_TEMPLATE = ({ PageContent, ExtraHead, components, ctx }) => {
108
108
  <head>
109
109
  <meta charset="UTF-8" />
110
110
  <meta name="viewport" content="width=device-width" />
111
+ <meta name="theme-color" content="#ffffff" media="(prefers-color-scheme: light)" />
112
+ <meta name="theme-color" content="#09090b" media="(prefers-color-scheme: dark)" />
111
113
  <title>
112
114
  {title} | {siteName}
113
115
  </title>