methanol 0.0.21 → 0.0.22
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/bin/methanol.js +1 -2
- package/package.json +6 -4
- package/src/base.js +36 -0
- package/src/build-system.js +319 -69
- package/src/client/sw.js +227 -180
- package/src/client/virtual-module/pwa-inject.js +25 -3
- package/src/config.js +16 -35
- package/src/dev-server.js +4 -2
- package/src/entry.js +22 -0
- package/src/html/build-html.js +221 -0
- package/src/html/utils.js +125 -0
- package/src/html/worker-html.js +591 -0
- package/src/main.js +97 -6
- package/src/mdx.js +33 -1
- package/src/pages-index.js +1 -2
- package/src/pages.js +26 -11
- package/src/pwa.js +240 -0
- package/src/state.js +6 -0
- package/src/utils.js +1 -1
- package/src/vite-plugins.js +6 -2
- package/src/workers/build-pool.js +1 -1
- package/src/workers/build-worker.js +165 -3
- package/src/workers/entry-build-worker.js +22 -0
- package/src/workers/entry-mdx-compile-worker.js +22 -0
- package/src/workers/mdx-compile-worker.js +0 -1
- package/themes/benchmark/README.md +5 -0
- package/themes/benchmark/index.js +33 -0
- package/themes/benchmark/src/page.jsx +25 -0
- package/themes/blog/src/page.jsx +0 -2
- package/themes/default/src/page.jsx +0 -2
package/src/client/sw.js
CHANGED
|
@@ -18,39 +18,16 @@
|
|
|
18
18
|
* under the License.
|
|
19
19
|
*/
|
|
20
20
|
|
|
21
|
-
import { clientsClaim } from 'workbox-core'
|
|
22
|
-
import { registerRoute } from 'workbox-routing'
|
|
23
21
|
import { cached, cachedStr } from '../utils.js'
|
|
22
|
+
import { normalizeBasePrefix } from '../base.js'
|
|
24
23
|
|
|
25
|
-
const
|
|
26
|
-
const
|
|
24
|
+
const MANIFEST_HASH = '__METHANOL_MANIFEST_HASH__'
|
|
25
|
+
const DEFAULT_BATCH_SIZE = 5
|
|
27
26
|
const REVISION_HEADER = 'X-Methanol-Revision'
|
|
28
27
|
|
|
29
28
|
self.skipWaiting()
|
|
30
|
-
clientsClaim()
|
|
31
29
|
|
|
32
|
-
const resolveBasePrefix = cached(() =>
|
|
33
|
-
let base = import.meta.env?.BASE_URL || '/'
|
|
34
|
-
if (!base || base === '/' || base === './') return ''
|
|
35
|
-
if (base.startsWith('http://') || base.startsWith('https://')) {
|
|
36
|
-
try {
|
|
37
|
-
base = new URL(base).pathname
|
|
38
|
-
} catch {
|
|
39
|
-
return ''
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
if (!base.startsWith('/')) return ''
|
|
43
|
-
if (base.endsWith('/')) base = base.slice(0, -1)
|
|
44
|
-
return base
|
|
45
|
-
})
|
|
46
|
-
|
|
47
|
-
const resolveCurrentBasePrefix = cached(() => {
|
|
48
|
-
const prefix = resolveBasePrefix()
|
|
49
|
-
if (!prefix) {
|
|
50
|
-
return self.location.origin
|
|
51
|
-
}
|
|
52
|
-
return new URL(prefix, self.location.origin).href
|
|
53
|
-
})
|
|
30
|
+
const resolveBasePrefix = cached(() => normalizeBasePrefix(import.meta.env?.BASE_URL || '/'))
|
|
54
31
|
|
|
55
32
|
const withBase = cachedStr((path) => {
|
|
56
33
|
const prefix = resolveBasePrefix()
|
|
@@ -58,73 +35,93 @@ const withBase = cachedStr((path) => {
|
|
|
58
35
|
return `${prefix}${path}`
|
|
59
36
|
})
|
|
60
37
|
|
|
38
|
+
const MANIFEST_URL = withBase('/precache-manifest.json')
|
|
39
|
+
|
|
61
40
|
const NOT_FOUND_URL = new URL(withBase('/404.html'), self.location.origin).href.toLowerCase()
|
|
62
41
|
const OFFLINE_FALLBACK_URL = new URL(withBase('/offline.html'), self.location.origin).href.toLowerCase()
|
|
63
42
|
|
|
64
43
|
const PAGES_CACHE = withBase(':methanol-pages-swr')
|
|
65
44
|
const ASSETS_CACHE = withBase(':methanol-assets-swr')
|
|
66
45
|
|
|
67
|
-
const stripBase = cachedStr((url) => {
|
|
68
|
-
const base = resolveCurrentBasePrefix()
|
|
69
|
-
if (!base) return url
|
|
70
|
-
if (url === base) return '/'
|
|
71
|
-
if (url.startsWith(`${base}/`)) return url.slice(base.length)
|
|
72
|
-
return url
|
|
73
|
-
})
|
|
74
46
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
47
|
+
let manifestCache = null
|
|
48
|
+
let manifestPromise = null
|
|
49
|
+
let manifestIndexCache = null
|
|
50
|
+
let manifestIndexPromise = null
|
|
51
|
+
|
|
52
|
+
const resolveManifestUrl = () => {
|
|
53
|
+
if (!MANIFEST_HASH || MANIFEST_HASH === '__METHANOL_MANIFEST_HASH__') return MANIFEST_URL
|
|
54
|
+
return `${MANIFEST_URL}?v=${MANIFEST_HASH}`
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
async function loadManifest(force = false) {
|
|
58
|
+
if (manifestCache && !force) return manifestCache
|
|
59
|
+
if (manifestPromise && !force) return manifestPromise
|
|
60
|
+
manifestPromise = (async () => {
|
|
61
|
+
if (!force) {
|
|
62
|
+
const cached = await idbGet(KEY_MANIFEST_DATA).catch(() => null)
|
|
63
|
+
if (cached && cached.entries) {
|
|
64
|
+
if (!cached.hash || cached.hash === MANIFEST_HASH) {
|
|
65
|
+
manifestCache = cached
|
|
66
|
+
manifestIndexCache = null
|
|
67
|
+
manifestIndexPromise = null
|
|
68
|
+
return cached
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
try {
|
|
73
|
+
const url = new URL(resolveManifestUrl(), self.location.origin).toString()
|
|
74
|
+
const res = await fetch(url, { cache: 'no-store' })
|
|
75
|
+
if (!res || !res.ok) {
|
|
76
|
+
throw new Error('manifest fetch failed')
|
|
77
|
+
}
|
|
78
|
+
const data = await res.json()
|
|
79
|
+
const entries = Array.isArray(data?.entries) ? data.entries : []
|
|
80
|
+
const normalized = entries
|
|
81
|
+
.filter((entry) => entry && entry.url)
|
|
82
|
+
.map((entry) => ({
|
|
83
|
+
url: new URL(entry.url, self.location.href).toString(),
|
|
84
|
+
revision: entry.revision ?? null
|
|
85
|
+
}))
|
|
86
|
+
const installCount = Number.isFinite(data?.installCount)
|
|
87
|
+
? Math.max(0, Math.min(normalized.length, data.installCount))
|
|
88
|
+
: normalized.length
|
|
89
|
+
const batchSize = Number.isFinite(data?.batchSize) ? data.batchSize : DEFAULT_BATCH_SIZE
|
|
90
|
+
const result = { entries: normalized, installCount, batchSize, hash: data?.hash || '' }
|
|
91
|
+
manifestCache = result
|
|
92
|
+
manifestIndexCache = null
|
|
93
|
+
manifestIndexPromise = null
|
|
94
|
+
await idbSet(KEY_MANIFEST_DATA, result).catch(() => {})
|
|
95
|
+
return result
|
|
96
|
+
} catch (error) {
|
|
97
|
+
if (manifestCache) return manifestCache
|
|
98
|
+
throw error
|
|
99
|
+
} finally {
|
|
100
|
+
manifestPromise = null
|
|
101
|
+
}
|
|
102
|
+
})()
|
|
103
|
+
return manifestPromise
|
|
80
104
|
}
|
|
81
105
|
|
|
82
|
-
|
|
83
|
-
const
|
|
84
|
-
|
|
85
|
-
if (!entry?.url) continue
|
|
86
|
-
entries.push({
|
|
87
|
-
url: new URL(entry.url, self.location.href).toString(),
|
|
88
|
-
revision: entry.revision
|
|
89
|
-
})
|
|
90
|
-
}
|
|
91
|
-
return entries
|
|
92
|
-
})
|
|
93
|
-
|
|
94
|
-
const getManifestIndex = cached(() => {
|
|
95
|
-
const map = new Map()
|
|
96
|
-
for (const entry of getManifestEntries()) {
|
|
97
|
-
map.set(manifestKey(entry.url), entry.revision ?? null)
|
|
98
|
-
}
|
|
99
|
-
return map
|
|
100
|
-
})
|
|
101
|
-
|
|
102
|
-
function collectManifestUrls() {
|
|
103
|
-
return getManifestEntries().map((entry) => entry.url)
|
|
106
|
+
async function getManifestEntries() {
|
|
107
|
+
const data = await loadManifest()
|
|
108
|
+
return data.entries
|
|
104
109
|
}
|
|
105
110
|
|
|
106
|
-
function
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
const
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
continue
|
|
115
|
-
}
|
|
116
|
-
if ((lower.endsWith('.js') || lower.endsWith('.mjs')) && isRootOrAssets(url)) {
|
|
117
|
-
prioritized.push(url)
|
|
118
|
-
continue
|
|
111
|
+
async function getManifestIndex() {
|
|
112
|
+
if (manifestIndexCache) return manifestIndexCache
|
|
113
|
+
if (manifestIndexPromise) return manifestIndexPromise
|
|
114
|
+
manifestIndexPromise = (async () => {
|
|
115
|
+
const map = new Map()
|
|
116
|
+
const entries = await getManifestEntries()
|
|
117
|
+
for (const entry of entries) {
|
|
118
|
+
map.set(manifestKey(entry.url), entry.revision ?? null)
|
|
119
119
|
}
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
return [prioritized, other]
|
|
120
|
+
manifestIndexCache = map
|
|
121
|
+
manifestIndexPromise = null
|
|
122
|
+
return map
|
|
123
|
+
})()
|
|
124
|
+
return manifestIndexPromise
|
|
128
125
|
}
|
|
129
126
|
|
|
130
127
|
// Precache prioritized entries during install
|
|
@@ -132,41 +129,60 @@ self.addEventListener('install', (event) => {
|
|
|
132
129
|
event.waitUntil(
|
|
133
130
|
(async () => {
|
|
134
131
|
try {
|
|
135
|
-
await
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
const manifestUrls = manifestEntries.map((entry) => entry.url)
|
|
143
|
-
const [prioritized] = prioritizeManifestUrls(manifestUrls)
|
|
144
|
-
const { failedIndex } = await runConcurrentQueue(prioritized, {
|
|
145
|
-
concurrency: BATCH_SIZE,
|
|
146
|
-
handler: async (url) => {
|
|
147
|
-
const isHtml = url.endsWith('.html')
|
|
148
|
-
const cacheName = isHtml ? PAGES_CACHE : ASSETS_CACHE
|
|
149
|
-
const cached = await matchCache(cacheName, url)
|
|
150
|
-
const key = manifestKey(url)
|
|
151
|
-
const currentRevision = manifestMap.get(key) ?? null
|
|
152
|
-
const shouldFetch = shouldFetchWithRevision({
|
|
153
|
-
cached,
|
|
154
|
-
currentRevision
|
|
155
|
-
})
|
|
156
|
-
if (!shouldFetch) return true
|
|
157
|
-
const cache = isHtml ? pageCache : assetCache
|
|
158
|
-
return fetchAndCache(cache, url, currentRevision)
|
|
132
|
+
const prevHash = await idbGet(KEY_MANIFEST)
|
|
133
|
+
const swChanged = prevHash !== MANIFEST_HASH
|
|
134
|
+
if (swChanged) {
|
|
135
|
+
await idbSet(KEY_FORCE, 1)
|
|
136
|
+
await idbSet(KEY_INDEX, 0)
|
|
137
|
+
await idbSet(KEY_MANIFEST, MANIFEST_HASH)
|
|
138
|
+
await idbSet(KEY_MANIFEST_DATA, null)
|
|
159
139
|
}
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
140
|
+
const manifest = await loadManifest(swChanged)
|
|
141
|
+
await installManifest(manifest)
|
|
142
|
+
} catch (error) {
|
|
143
|
+
throw error
|
|
163
144
|
}
|
|
164
145
|
})()
|
|
165
146
|
)
|
|
166
147
|
})
|
|
167
148
|
|
|
149
|
+
async function installManifest(manifest) {
|
|
150
|
+
const pageCache = await openCache(PAGES_CACHE)
|
|
151
|
+
const assetCache = await openCache(ASSETS_CACHE)
|
|
152
|
+
const manifestEntries = manifest.entries
|
|
153
|
+
const manifestMap = buildManifestMap(manifestEntries)
|
|
154
|
+
const installCount = manifest.installCount ?? manifestEntries.length
|
|
155
|
+
const installUrls = manifestEntries.slice(0, installCount).map((entry) => entry.url)
|
|
156
|
+
const batchSize = Math.max(1, manifest.batchSize || DEFAULT_BATCH_SIZE)
|
|
157
|
+
const { failedIndex } = await runConcurrentQueue(installUrls, {
|
|
158
|
+
concurrency: batchSize,
|
|
159
|
+
handler: async (url) => {
|
|
160
|
+
const isHtml = url.endsWith('.html')
|
|
161
|
+
const cacheName = isHtml ? PAGES_CACHE : ASSETS_CACHE
|
|
162
|
+
const cached = await matchCache(cacheName, url)
|
|
163
|
+
const key = manifestKey(url)
|
|
164
|
+
const currentRevision = manifestMap.get(key) ?? null
|
|
165
|
+
const shouldFetch = shouldFetchWithRevision({
|
|
166
|
+
cached,
|
|
167
|
+
currentRevision
|
|
168
|
+
})
|
|
169
|
+
if (!shouldFetch) return true
|
|
170
|
+
const cache = isHtml ? pageCache : assetCache
|
|
171
|
+
return fetchAndCache(cache, url, currentRevision)
|
|
172
|
+
}
|
|
173
|
+
})
|
|
174
|
+
if (failedIndex !== null) {
|
|
175
|
+
throw new Error('install cache failed')
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
|
|
168
179
|
self.addEventListener('activate', (event) => {
|
|
169
|
-
|
|
180
|
+
event.waitUntil(
|
|
181
|
+
(async () => {
|
|
182
|
+
await self.clients.claim()
|
|
183
|
+
await warmManifestResumable()
|
|
184
|
+
})()
|
|
185
|
+
)
|
|
170
186
|
})
|
|
171
187
|
|
|
172
188
|
function stripSearch(urlString) {
|
|
@@ -466,88 +482,114 @@ async function serveOffline() {
|
|
|
466
482
|
})
|
|
467
483
|
}
|
|
468
484
|
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
const key = manifestKey(normalizedKey)
|
|
475
|
-
const manifestRevision = getManifestIndex().get(key) ?? null
|
|
476
|
-
const inManifest = getManifestIndex().has(key)
|
|
477
|
-
|
|
478
|
-
if (inManifest) {
|
|
479
|
-
const cached = await matchCache(PAGES_CACHE, normalizedKey)
|
|
480
|
-
const shouldRevalidate = shouldRevalidateCached(cached, manifestRevision)
|
|
481
|
-
if (cached && !shouldRevalidate) return cached
|
|
482
|
-
if (cached && shouldRevalidate) {
|
|
483
|
-
const fresh = await fetchWithCleanUrlFallback(event, request, {
|
|
484
|
-
usePreload: isHtmlNavigation(request),
|
|
485
|
-
allowNotOk: true
|
|
486
|
-
})
|
|
487
|
-
if (fresh && fresh.status === 200) {
|
|
488
|
-
await putCache(PAGES_CACHE, normalizedKey, fresh.clone(), manifestRevision)
|
|
489
|
-
return fresh
|
|
490
|
-
}
|
|
491
|
-
if (fresh && fresh.status === 404) {
|
|
492
|
-
return serveNotFound()
|
|
493
|
-
}
|
|
494
|
-
if (fresh) return fresh
|
|
495
|
-
return cached
|
|
496
|
-
}
|
|
497
|
-
}
|
|
485
|
+
const handleNavigationRequest = async (event, request, index) => {
|
|
486
|
+
const normalizedKey = normalizeNavigationURL(new URL(request.url)).toString()
|
|
487
|
+
const key = manifestKey(normalizedKey)
|
|
488
|
+
const manifestRevision = index.get(key) ?? null
|
|
489
|
+
const inManifest = index.has(key)
|
|
498
490
|
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
if (
|
|
504
|
-
|
|
491
|
+
if (inManifest) {
|
|
492
|
+
const cached = await matchCache(PAGES_CACHE, normalizedKey)
|
|
493
|
+
const shouldRevalidate = shouldRevalidateCached(cached, manifestRevision)
|
|
494
|
+
if (cached && !shouldRevalidate) return cached
|
|
495
|
+
if (cached && shouldRevalidate) {
|
|
496
|
+
const fresh = await fetchWithCleanUrlFallback(event, request, {
|
|
497
|
+
usePreload: isHtmlNavigation(request),
|
|
498
|
+
allowNotOk: true
|
|
499
|
+
})
|
|
500
|
+
if (fresh && fresh.status === 200) {
|
|
505
501
|
await putCache(PAGES_CACHE, normalizedKey, fresh.clone(), manifestRevision)
|
|
502
|
+
return fresh
|
|
503
|
+
}
|
|
504
|
+
if (fresh && fresh.status === 404) {
|
|
505
|
+
return serveNotFound()
|
|
506
506
|
}
|
|
507
|
-
return fresh
|
|
507
|
+
if (fresh) return fresh
|
|
508
|
+
return cached
|
|
508
509
|
}
|
|
509
|
-
|
|
510
|
-
|
|
510
|
+
}
|
|
511
|
+
|
|
512
|
+
const fresh = await fetchWithCleanUrlFallback(event, request, {
|
|
513
|
+
usePreload: isHtmlNavigation(request),
|
|
514
|
+
allowNotOk: true
|
|
515
|
+
})
|
|
516
|
+
if (fresh && fresh.status === 200) {
|
|
517
|
+
if (inManifest) {
|
|
518
|
+
await putCache(PAGES_CACHE, normalizedKey, fresh.clone(), manifestRevision)
|
|
511
519
|
}
|
|
520
|
+
return fresh
|
|
521
|
+
}
|
|
522
|
+
if (fresh && fresh.status === 404) {
|
|
523
|
+
return serveNotFound()
|
|
524
|
+
}
|
|
512
525
|
|
|
513
|
-
|
|
526
|
+
if (fresh) return fresh
|
|
514
527
|
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
)
|
|
518
|
-
|
|
519
|
-
registerRoute(
|
|
520
|
-
({ request, url }) =>
|
|
521
|
-
url.origin === self.location.origin &&
|
|
522
|
-
request.method === 'GET' &&
|
|
523
|
-
request.destination !== 'document' &&
|
|
524
|
-
!isHtmlNavigation(request) &&
|
|
525
|
-
getManifestIndex().has(manifestKey(request.url)),
|
|
526
|
-
async ({ request }) => {
|
|
527
|
-
const key = manifestKey(request.url)
|
|
528
|
-
const manifestRevision = getManifestIndex().get(key) ?? null
|
|
529
|
-
const cached = await matchCache(ASSETS_CACHE, key)
|
|
530
|
-
const shouldRevalidate = shouldRevalidateCached(cached, manifestRevision)
|
|
531
|
-
if (cached && !shouldRevalidate) return cached
|
|
528
|
+
return serveOffline()
|
|
529
|
+
}
|
|
532
530
|
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
531
|
+
const handleAssetRequest = async (request, index) => {
|
|
532
|
+
const key = manifestKey(request.url)
|
|
533
|
+
const manifestRevision = index.get(key) ?? null
|
|
534
|
+
const cached = await matchCache(ASSETS_CACHE, key)
|
|
535
|
+
const shouldRevalidate = shouldRevalidateCached(cached, manifestRevision)
|
|
536
|
+
if (cached && !shouldRevalidate) return cached
|
|
537
|
+
|
|
538
|
+
try {
|
|
539
|
+
const res = await fetch(request)
|
|
540
|
+
if (res && res.status === 200) {
|
|
541
|
+
await putCache(ASSETS_CACHE, key, res.clone(), manifestRevision)
|
|
542
542
|
}
|
|
543
|
+
return res
|
|
544
|
+
} catch {
|
|
545
|
+
if (cached) return cached
|
|
546
|
+
return new Response(null, { status: 503 })
|
|
543
547
|
}
|
|
544
|
-
|
|
548
|
+
}
|
|
549
|
+
|
|
550
|
+
self.addEventListener('fetch', (event) => {
|
|
551
|
+
const request = event.request
|
|
552
|
+
if (!request || request.method !== 'GET') return
|
|
553
|
+
let url = null
|
|
554
|
+
try {
|
|
555
|
+
url = new URL(request.url)
|
|
556
|
+
} catch {
|
|
557
|
+
return
|
|
558
|
+
}
|
|
559
|
+
if (url.origin !== self.location.origin) return
|
|
560
|
+
|
|
561
|
+
event.respondWith(
|
|
562
|
+
(async () => {
|
|
563
|
+
try {
|
|
564
|
+
const manifestKeyUrl = stripSearch(new URL(MANIFEST_URL, self.location.origin).toString()).toString()
|
|
565
|
+
if (stripSearch(request.url).toString() === manifestKeyUrl) {
|
|
566
|
+
return fetch(request)
|
|
567
|
+
}
|
|
568
|
+
if (isHtmlNavigation(request) || isPrefetch(request)) {
|
|
569
|
+
const index = await getManifestIndex().catch(() => new Map())
|
|
570
|
+
return await handleNavigationRequest(event, request, index)
|
|
571
|
+
}
|
|
572
|
+
const index = await getManifestIndex().catch(() => new Map())
|
|
573
|
+
if (
|
|
574
|
+
request.destination !== 'document' &&
|
|
575
|
+
!isHtmlNavigation(request) &&
|
|
576
|
+
index.has(manifestKey(request.url))
|
|
577
|
+
) {
|
|
578
|
+
return await handleAssetRequest(request, index)
|
|
579
|
+
}
|
|
580
|
+
} catch {}
|
|
581
|
+
return fetch(request)
|
|
582
|
+
})()
|
|
583
|
+
)
|
|
584
|
+
})
|
|
545
585
|
|
|
546
586
|
const DB_NAME = withBase(':methanol-pwa-warm-db')
|
|
547
587
|
const DB_STORE = 'kv'
|
|
548
588
|
const KEY_INDEX = 'warmIndex'
|
|
549
589
|
const KEY_LEASE = 'warmLease'
|
|
550
590
|
const KEY_FORCE = 'warmForce'
|
|
591
|
+
const KEY_MANIFEST = 'warmManifestHash'
|
|
592
|
+
const KEY_MANIFEST_DATA = 'warmManifestData'
|
|
551
593
|
|
|
552
594
|
function idbOpen() {
|
|
553
595
|
return new Promise((resolve, reject) => {
|
|
@@ -639,7 +681,12 @@ async function releaseLease(lease) {
|
|
|
639
681
|
}
|
|
640
682
|
|
|
641
683
|
async function warmManifestResumable({ force = false } = {}) {
|
|
642
|
-
|
|
684
|
+
let manifest = null
|
|
685
|
+
try {
|
|
686
|
+
manifest = await loadManifest()
|
|
687
|
+
} catch {
|
|
688
|
+
return
|
|
689
|
+
}
|
|
643
690
|
|
|
644
691
|
const forceFlag = await idbGet(KEY_FORCE)
|
|
645
692
|
if (forceFlag) force = true
|
|
@@ -656,9 +703,9 @@ async function warmManifestResumable({ force = false } = {}) {
|
|
|
656
703
|
|
|
657
704
|
let completed = false
|
|
658
705
|
try {
|
|
659
|
-
const manifestEntries =
|
|
706
|
+
const manifestEntries = manifest.entries
|
|
660
707
|
const manifestMap = buildManifestMap(manifestEntries)
|
|
661
|
-
const
|
|
708
|
+
const urls = manifestEntries.slice(manifest.installCount).map((entry) => entry.url)
|
|
662
709
|
if (!urls.length) return
|
|
663
710
|
if (index >= urls.length) {
|
|
664
711
|
completed = true
|
|
@@ -667,7 +714,7 @@ async function warmManifestResumable({ force = false } = {}) {
|
|
|
667
714
|
|
|
668
715
|
const startIndex = index
|
|
669
716
|
const { failedIndex } = await runConcurrentQueue(urls.slice(startIndex), {
|
|
670
|
-
concurrency:
|
|
717
|
+
concurrency: Math.max(1, manifest.batchSize || DEFAULT_BATCH_SIZE),
|
|
671
718
|
handler: async (abs) => {
|
|
672
719
|
const leaseOk = await renewLease(lease, leaseMs)
|
|
673
720
|
if (!leaseOk) return false
|
|
@@ -18,8 +18,30 @@
|
|
|
18
18
|
* under the License.
|
|
19
19
|
*/
|
|
20
20
|
|
|
21
|
+
const resolveBasePrefix = () => {
|
|
22
|
+
let base = import.meta.env?.BASE_URL || '/'
|
|
23
|
+
if (!base || base === '/' || base === './') return ''
|
|
24
|
+
if (base.startsWith('http://') || base.startsWith('https://')) {
|
|
25
|
+
try {
|
|
26
|
+
base = new URL(base).pathname
|
|
27
|
+
} catch {
|
|
28
|
+
return ''
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
if (!base.startsWith('/')) return ''
|
|
32
|
+
if (base.endsWith('/')) base = base.slice(0, -1)
|
|
33
|
+
return base
|
|
34
|
+
}
|
|
35
|
+
|
|
21
36
|
if (typeof navigator !== 'undefined' && 'serviceWorker' in navigator) {
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
}
|
|
37
|
+
const base = resolveBasePrefix()
|
|
38
|
+
const scope = base ? `${base}/` : '/'
|
|
39
|
+
const swUrl = `${scope}sw.js`
|
|
40
|
+
navigator.serviceWorker
|
|
41
|
+
.register(swUrl)
|
|
42
|
+
.then(() => navigator.serviceWorker.ready)
|
|
43
|
+
.then((reg) => {
|
|
44
|
+
reg.active?.postMessage({ type: 'METHANOL_WARM_MANIFEST' })
|
|
45
|
+
})
|
|
46
|
+
.catch(() => {})
|
|
25
47
|
}
|
package/src/config.js
CHANGED
|
@@ -31,6 +31,8 @@ import { HTMLRenderer } from './renderer.js'
|
|
|
31
31
|
import { reframeEnv } from './components.js'
|
|
32
32
|
import { env as createEnv } from './reframe.js'
|
|
33
33
|
import { cached, cachedStr } from './utils.js'
|
|
34
|
+
import { normalizeBasePrefix } from './base.js'
|
|
35
|
+
import { resolvePwaOptions } from './pwa.js'
|
|
34
36
|
import defaultTheme from '../themes/default/index.js'
|
|
35
37
|
|
|
36
38
|
const CONFIG_FILENAMES = [
|
|
@@ -431,12 +433,7 @@ export const applyConfig = async (config, mode) => {
|
|
|
431
433
|
state.MERGED_ASSETS_DIR = null
|
|
432
434
|
} else {
|
|
433
435
|
// We need to merge
|
|
434
|
-
|
|
435
|
-
if (existsSync(nodeModulesPath)) {
|
|
436
|
-
state.MERGED_ASSETS_DIR = resolve(nodeModulesPath, '.methanol/assets')
|
|
437
|
-
} else {
|
|
438
|
-
state.MERGED_ASSETS_DIR = resolve(state.PAGES_DIR || resolve(root, 'pages'), '.methanol/assets')
|
|
439
|
-
}
|
|
436
|
+
state.MERGED_ASSETS_DIR = resolve(state.PAGES_DIR || resolve(root, 'pages'), '.methanol/assets')
|
|
440
437
|
state.STATIC_DIR = state.MERGED_ASSETS_DIR
|
|
441
438
|
}
|
|
442
439
|
} else {
|
|
@@ -471,29 +468,29 @@ export const applyConfig = async (config, mode) => {
|
|
|
471
468
|
state.RSS_OPTIONS = { ...(state.RSS_OPTIONS || {}), atom: cli.CLI_ATOM }
|
|
472
469
|
}
|
|
473
470
|
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
state.PWA_OPTIONS = null
|
|
478
|
-
} else if (typeof config.pwa === 'object' && config.pwa !== null) {
|
|
479
|
-
state.PWA_ENABLED = true
|
|
480
|
-
state.PWA_OPTIONS = config.pwa
|
|
481
|
-
} else {
|
|
482
|
-
state.PWA_ENABLED = false
|
|
483
|
-
state.PWA_OPTIONS = null
|
|
484
|
-
}
|
|
485
|
-
}
|
|
471
|
+
const resolvedPwa = resolvePwaOptions(config.pwa)
|
|
472
|
+
state.PWA_ENABLED = resolvedPwa.enabled
|
|
473
|
+
state.PWA_OPTIONS = resolvedPwa.options
|
|
486
474
|
if (cli.CLI_PWA !== undefined) {
|
|
487
475
|
state.PWA_ENABLED = cli.CLI_PWA
|
|
476
|
+
if (cli.CLI_PWA && !state.PWA_OPTIONS) {
|
|
477
|
+
state.PWA_OPTIONS = resolvePwaOptions(true).options
|
|
478
|
+
}
|
|
488
479
|
}
|
|
489
480
|
state.USER_PRE_BUILD_HOOKS = normalizeHooks(config.preBuild)
|
|
490
481
|
state.USER_POST_BUILD_HOOKS = normalizeHooks(config.postBuild)
|
|
491
482
|
state.USER_PRE_BUNDLE_HOOKS = normalizeHooks(config.preBundle)
|
|
492
483
|
state.USER_POST_BUNDLE_HOOKS = normalizeHooks(config.postBundle)
|
|
484
|
+
state.USER_PRE_WRITE_HOOKS = normalizeHooks(config.preWrite)
|
|
485
|
+
state.USER_POST_WRITE_HOOKS = normalizeHooks(config.postWrite)
|
|
486
|
+
state.USER_FINALIZE_HOOKS = normalizeHooks(config.finalize)
|
|
493
487
|
state.THEME_PRE_BUILD_HOOKS = normalizeHooks(state.USER_THEME?.preBuild)
|
|
494
488
|
state.THEME_POST_BUILD_HOOKS = normalizeHooks(state.USER_THEME?.postBuild)
|
|
495
489
|
state.THEME_PRE_BUNDLE_HOOKS = normalizeHooks(state.USER_THEME?.preBundle)
|
|
496
490
|
state.THEME_POST_BUNDLE_HOOKS = normalizeHooks(state.USER_THEME?.postBundle)
|
|
491
|
+
state.THEME_PRE_WRITE_HOOKS = normalizeHooks(state.USER_THEME?.preWrite)
|
|
492
|
+
state.THEME_POST_WRITE_HOOKS = normalizeHooks(state.USER_THEME?.postWrite)
|
|
493
|
+
state.THEME_FINALIZE_HOOKS = normalizeHooks(state.USER_THEME?.finalize)
|
|
497
494
|
if (hasOwn(config, 'gfm')) {
|
|
498
495
|
state.GFM_ENABLED = config.gfm !== false
|
|
499
496
|
}
|
|
@@ -619,23 +616,7 @@ export const resolveUserViteConfig = async (command) => {
|
|
|
619
616
|
return state.RESOLVED_VITE_CONFIG
|
|
620
617
|
}
|
|
621
618
|
|
|
622
|
-
export const resolveBasePrefix = cached(() =>
|
|
623
|
-
const value = state.VITE_BASE || state.SITE_BASE || '/'
|
|
624
|
-
if (!value || value === '/' || value === './') return ''
|
|
625
|
-
if (typeof value !== 'string') return ''
|
|
626
|
-
let base = value.trim()
|
|
627
|
-
if (!base || base === '/' || base === './') return ''
|
|
628
|
-
if (base.startsWith('http://') || base.startsWith('https://')) {
|
|
629
|
-
try {
|
|
630
|
-
base = new URL(base).pathname
|
|
631
|
-
} catch {
|
|
632
|
-
return ''
|
|
633
|
-
}
|
|
634
|
-
}
|
|
635
|
-
if (!base.startsWith('/')) return ''
|
|
636
|
-
if (base.endsWith('/')) base = base.slice(0, -1)
|
|
637
|
-
return base
|
|
638
|
-
})
|
|
619
|
+
export const resolveBasePrefix = cached(() => normalizeBasePrefix(state.VITE_BASE || state.SITE_BASE || '/'))
|
|
639
620
|
|
|
640
621
|
export const withBase = cachedStr((value) => {
|
|
641
622
|
if (!value || typeof value !== 'string') return value
|
package/src/dev-server.js
CHANGED
|
@@ -214,7 +214,7 @@ export const runViteDev = async () => {
|
|
|
214
214
|
|
|
215
215
|
const prebuildHtmlCache = async (token) => {
|
|
216
216
|
if (!pagesContext || token !== pagesContextToken) return
|
|
217
|
-
const pages = pagesContext.pages || []
|
|
217
|
+
const pages = pagesContext.pagesAll || pagesContext.pages || []
|
|
218
218
|
if (!pages.length) return
|
|
219
219
|
const { workers, assignments } = createBuildWorkers(pages.length, { command: 'serve' })
|
|
220
220
|
const excludedRoutes = Array.from(pagesContext.excludedRoutes || [])
|
|
@@ -691,7 +691,9 @@ export const runViteDev = async () => {
|
|
|
691
691
|
source: resolved.source
|
|
692
692
|
})
|
|
693
693
|
if (!nextEntry) return false
|
|
694
|
-
const prevEntry = pagesContext.
|
|
694
|
+
const prevEntry = pagesContext.pagesAll?.find?.((page) => page.path === path)
|
|
695
|
+
|| pagesContext.pages?.find?.((page) => page.path === path)
|
|
696
|
+
|| null
|
|
695
697
|
if (!prevEntry) return false
|
|
696
698
|
if (prevEntry.exclude !== nextEntry.exclude) return false
|
|
697
699
|
if (prevEntry.isIndex !== nextEntry.isIndex || prevEntry.dir !== nextEntry.dir) return false
|
package/src/entry.js
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/* Copyright Yukino Song, SudoMaker Ltd.
|
|
2
|
+
*
|
|
3
|
+
* Licensed to the Apache Software Foundation (ASF) under one
|
|
4
|
+
* or more contributor license agreements. See the NOTICE file
|
|
5
|
+
* distributed with this work for additional information
|
|
6
|
+
* regarding copyright ownership. The ASF licenses this file
|
|
7
|
+
* to you under the Apache License, Version 2.0 (the
|
|
8
|
+
* "License"); you may not use this file except in compliance
|
|
9
|
+
* with the License. You may obtain a copy of the License at
|
|
10
|
+
*
|
|
11
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
12
|
+
*
|
|
13
|
+
* Unless required by applicable law or agreed to in writing,
|
|
14
|
+
* software distributed under the License is distributed on an
|
|
15
|
+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
16
|
+
* KIND, either express or implied. See the License for the
|
|
17
|
+
* specific language governing permissions and limitations
|
|
18
|
+
* under the License.
|
|
19
|
+
*/
|
|
20
|
+
|
|
21
|
+
import './register-loader.js'
|
|
22
|
+
import('./main.js')
|