methanol 0.0.7 → 0.0.9
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 +5 -0
- package/package.json +2 -1
- package/src/assets.js +1 -1
- package/src/build-system.js +9 -2
- package/src/config.js +134 -4
- package/src/dev-server.js +51 -27
- package/src/logger.js +80 -0
- package/src/main.js +10 -1
- package/src/mdx.js +43 -33
- package/src/pagefind.js +16 -5
- package/src/pages.js +85 -76
- package/src/preview-server.js +1 -1
- package/src/rehype-plugins/link-resolve.js +0 -1
- package/src/stage-logger.js +7 -4
- package/src/state.js +19 -3
- package/src/utils.js +9 -0
- package/src/virtual-module/inject.js +3 -4
- package/src/virtual-module/{pagefind.js → pagefind-loader.js} +23 -2
- package/src/vite-plugins.js +50 -6
- package/themes/default/components/ThemeSearchBox.client.jsx +9 -2
- package/themes/default/page.jsx +54 -26
- package/themes/default/sources/style.css +194 -1
package/README.md
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "methanol",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.9",
|
|
4
4
|
"description": "Static site generator powered by rEFui and MDX",
|
|
5
5
|
"main": "./index.js",
|
|
6
6
|
"type": "module",
|
|
@@ -39,6 +39,7 @@
|
|
|
39
39
|
"refurbish": "^0.1.8",
|
|
40
40
|
"rehype-slug": "^6.0.0",
|
|
41
41
|
"rehype-starry-night": "^2.2.0",
|
|
42
|
+
"remark-gfm": "^4.0.1",
|
|
42
43
|
"unist-util-visit": "^5.0.0",
|
|
43
44
|
"vite": "^7.3.0",
|
|
44
45
|
"yargs": "^18.0.0"
|
package/src/assets.js
CHANGED
|
@@ -27,4 +27,4 @@ const __dirname = dirname(__filename)
|
|
|
27
27
|
|
|
28
28
|
export const INJECT_SCRIPT = readFileSync(resolve(__dirname, './virtual-module/inject.js'), 'utf-8')
|
|
29
29
|
export const LOADER_SCRIPT = readFileSync(resolve(__dirname, './virtual-module/loader.js'), 'utf-8')
|
|
30
|
-
export const
|
|
30
|
+
export const PAGEFIND_LOADER_SCRIPT = readFileSync(resolve(__dirname, './virtual-module/pagefind-loader.js'), 'utf-8')
|
package/src/build-system.js
CHANGED
|
@@ -61,12 +61,13 @@ const collectHtmlFiles = async (dir, basePath = '') => {
|
|
|
61
61
|
}
|
|
62
62
|
|
|
63
63
|
export const buildHtmlEntries = async () => {
|
|
64
|
+
await resolveUserViteConfig('build') // Prepare `base`
|
|
64
65
|
if (state.INTERMEDIATE_DIR) {
|
|
65
66
|
await rm(state.INTERMEDIATE_DIR, { recursive: true, force: true })
|
|
66
67
|
await ensureDir(state.INTERMEDIATE_DIR)
|
|
67
68
|
}
|
|
68
69
|
|
|
69
|
-
const logEnabled = state.CURRENT_MODE === 'production' && cli.command === 'build'
|
|
70
|
+
const logEnabled = state.CURRENT_MODE === 'production' && cli.command === 'build' && !cli.CLI_VERBOSE
|
|
70
71
|
const stageLogger = createStageLogger(logEnabled)
|
|
71
72
|
const themeComponentsDir = state.THEME_COMPONENTS_DIR
|
|
72
73
|
const themeEnv = state.THEME_ENV
|
|
@@ -163,6 +164,10 @@ export const buildHtmlEntries = async () => {
|
|
|
163
164
|
}
|
|
164
165
|
|
|
165
166
|
export const runViteBuild = async (entry, htmlCache) => {
|
|
167
|
+
const logEnabled = state.CURRENT_MODE === 'production' && cli.command === 'build' && !cli.CLI_VERBOSE
|
|
168
|
+
const stageLogger = createStageLogger(logEnabled)
|
|
169
|
+
const token = stageLogger.start('Building bundle')
|
|
170
|
+
|
|
166
171
|
if (state.STATIC_DIR !== false && state.MERGED_ASSETS_DIR) {
|
|
167
172
|
await preparePublicAssets({
|
|
168
173
|
themeDir: state.THEME_ASSETS_DIR,
|
|
@@ -174,8 +179,9 @@ export const runViteBuild = async (entry, htmlCache) => {
|
|
|
174
179
|
const baseConfig = {
|
|
175
180
|
configFile: false,
|
|
176
181
|
root: state.PAGES_DIR,
|
|
177
|
-
|
|
182
|
+
appType: 'mpa',
|
|
178
183
|
publicDir: state.STATIC_DIR === false ? false : state.STATIC_DIR,
|
|
184
|
+
logLevel: cli.CLI_VERBOSE ? 'info' : 'silent',
|
|
179
185
|
build: {
|
|
180
186
|
outDir: state.DIST_DIR,
|
|
181
187
|
emptyOutDir: true,
|
|
@@ -197,4 +203,5 @@ export const runViteBuild = async (entry, htmlCache) => {
|
|
|
197
203
|
const userConfig = await resolveUserViteConfig('build')
|
|
198
204
|
const finalConfig = userConfig ? mergeConfig(baseConfig, userConfig) : baseConfig
|
|
199
205
|
await viteBuild(finalConfig)
|
|
206
|
+
stageLogger.end(token)
|
|
200
207
|
}
|
package/src/config.js
CHANGED
|
@@ -24,9 +24,11 @@ import { resolve, isAbsolute, extname, basename } from 'path'
|
|
|
24
24
|
import { pathToFileURL } from 'url'
|
|
25
25
|
import { mergeConfig } from 'vite'
|
|
26
26
|
import { cli, state } from './state.js'
|
|
27
|
+
import { logger } from './logger.js'
|
|
27
28
|
import { HTMLRenderer } from './renderer.js'
|
|
28
29
|
import { rewindEnv } from './components.js'
|
|
29
30
|
import { env as createEnv } from './rewind.js'
|
|
31
|
+
import { cached, cachedStr } from './utils.js'
|
|
30
32
|
import defaultTheme from '../themes/default/index.js'
|
|
31
33
|
|
|
32
34
|
const CONFIG_FILENAMES = [
|
|
@@ -79,6 +81,52 @@ const resolveThemePublicDir = (root, value) => {
|
|
|
79
81
|
return isAbsolute(value) ? value : resolve(root, value)
|
|
80
82
|
}
|
|
81
83
|
|
|
84
|
+
let devBaseWarningShown = false
|
|
85
|
+
|
|
86
|
+
const normalizeSiteBase = (value) => {
|
|
87
|
+
if (value == null) return null
|
|
88
|
+
if (typeof value !== 'string') return null
|
|
89
|
+
const trimmed = value.trim()
|
|
90
|
+
if (!trimmed || trimmed === './') return '/'
|
|
91
|
+
if (trimmed.startsWith('http://') || trimmed.startsWith('https://')) {
|
|
92
|
+
return trimmed
|
|
93
|
+
}
|
|
94
|
+
let base = trimmed
|
|
95
|
+
if (!base.startsWith('/')) {
|
|
96
|
+
base = `/${base}`
|
|
97
|
+
}
|
|
98
|
+
if (!base.endsWith('/')) {
|
|
99
|
+
base = `${base}/`
|
|
100
|
+
}
|
|
101
|
+
return base
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
const normalizeViteBase = (value) => {
|
|
105
|
+
if (!value || value === '/' || value === './') return '/'
|
|
106
|
+
if (typeof value !== 'string') return '/'
|
|
107
|
+
let base = value.trim()
|
|
108
|
+
if (!base || base === './') return '/'
|
|
109
|
+
if (base.startsWith('http://') || base.startsWith('https://')) {
|
|
110
|
+
try {
|
|
111
|
+
base = new URL(base).pathname
|
|
112
|
+
} catch {
|
|
113
|
+
return '/'
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
if (!base.startsWith('/')) return '/'
|
|
117
|
+
if (!base.endsWith('/')) {
|
|
118
|
+
base = `${base}/`
|
|
119
|
+
}
|
|
120
|
+
return base
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
const warnDevBase = (value) => {
|
|
124
|
+
if (devBaseWarningShown) return
|
|
125
|
+
devBaseWarningShown = true
|
|
126
|
+
const label = value ? ` (received "${value}")` : ''
|
|
127
|
+
logger.warn(`Methanol: \`base\`${label} is disabled in dev mode due to module resolution inconsistencies in Vite. Using "/".\n`)
|
|
128
|
+
}
|
|
129
|
+
|
|
82
130
|
const hasOwn = (obj, key) => Object.prototype.hasOwnProperty.call(obj || {}, key)
|
|
83
131
|
const normalizeSources = (value, root) => {
|
|
84
132
|
if (!value) return []
|
|
@@ -216,11 +264,20 @@ export const applyConfig = async (config, mode) => {
|
|
|
216
264
|
state.ROOT_DIR = root
|
|
217
265
|
const configSiteName = cli.CLI_SITE_NAME ?? config.site?.name ?? null
|
|
218
266
|
state.SITE_NAME = configSiteName || basename(root) || 'Methanol Site'
|
|
219
|
-
|
|
267
|
+
const userSite = config.site && typeof config.site === 'object' ? { ...config.site } : null
|
|
268
|
+
const siteBase = normalizeSiteBase(cli.CLI_BASE || userSite?.base)
|
|
269
|
+
state.SITE_BASE = siteBase
|
|
270
|
+
if (userSite) {
|
|
271
|
+
if (siteBase == null) {
|
|
272
|
+
delete userSite.base
|
|
273
|
+
} else {
|
|
274
|
+
userSite.base = siteBase
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
state.USER_SITE = userSite
|
|
220
278
|
if (mode) {
|
|
221
279
|
state.CURRENT_MODE = mode
|
|
222
280
|
}
|
|
223
|
-
// config.paths / config.dirs are intentionally ignored (deprecated)
|
|
224
281
|
|
|
225
282
|
const pagesDirValue = cli.CLI_PAGES_DIR || config.pagesDir
|
|
226
283
|
const componentsDirValue = cli.CLI_COMPONENTS_DIR || config.componentsDir
|
|
@@ -336,6 +393,9 @@ export const applyConfig = async (config, mode) => {
|
|
|
336
393
|
state.THEME_POST_BUILD_HOOKS = normalizeHooks(state.USER_THEME?.postBuild)
|
|
337
394
|
state.THEME_PRE_BUNDLE_HOOKS = normalizeHooks(state.USER_THEME?.preBundle)
|
|
338
395
|
state.THEME_POST_BUNDLE_HOOKS = normalizeHooks(state.USER_THEME?.postBundle)
|
|
396
|
+
if (hasOwn(config, 'gfm')) {
|
|
397
|
+
state.GFM_ENABLED = config.gfm !== false
|
|
398
|
+
}
|
|
339
399
|
const starryNight = resolveStarryNightConfig(config.starryNight)
|
|
340
400
|
const cliCodeHighlighting = cli.CLI_CODE_HIGHLIGHTING
|
|
341
401
|
if (cliCodeHighlighting != null) {
|
|
@@ -392,6 +452,7 @@ export const resolveUserViteConfig = async (command) => {
|
|
|
392
452
|
if (state.RESOLVED_VITE_CONFIG !== undefined) {
|
|
393
453
|
return state.RESOLVED_VITE_CONFIG
|
|
394
454
|
}
|
|
455
|
+
|
|
395
456
|
const resolveConfig = async (config) => {
|
|
396
457
|
if (!config) return null
|
|
397
458
|
if (typeof config === 'function') {
|
|
@@ -407,16 +468,85 @@ export const resolveUserViteConfig = async (command) => {
|
|
|
407
468
|
}
|
|
408
469
|
return config || null
|
|
409
470
|
}
|
|
471
|
+
|
|
410
472
|
const themeConfig = await resolveConfig(state.USER_THEME.vite)
|
|
411
473
|
const userConfig = await resolveConfig(state.USER_VITE_CONFIG)
|
|
474
|
+
|
|
412
475
|
if (!themeConfig && !userConfig) {
|
|
413
|
-
state.
|
|
414
|
-
|
|
476
|
+
if (state.SITE_BASE) {
|
|
477
|
+
state.RESOLVED_VITE_CONFIG = { base: state.SITE_BASE }
|
|
478
|
+
} else {
|
|
479
|
+
state.RESOLVED_VITE_CONFIG = null
|
|
480
|
+
}
|
|
481
|
+
state.VITE_BASE = normalizeViteBase(state.RESOLVED_VITE_CONFIG?.base || state.SITE_BASE || '/')
|
|
482
|
+
if (command === 'serve') {
|
|
483
|
+
if (state.VITE_BASE !== '/' || (state.SITE_BASE && state.SITE_BASE !== '/')) {
|
|
484
|
+
warnDevBase(state.RESOLVED_VITE_CONFIG?.base || state.SITE_BASE || '')
|
|
485
|
+
}
|
|
486
|
+
if (state.RESOLVED_VITE_CONFIG) {
|
|
487
|
+
state.RESOLVED_VITE_CONFIG.base = '/'
|
|
488
|
+
}
|
|
489
|
+
state.VITE_BASE = '/'
|
|
490
|
+
}
|
|
491
|
+
return state.RESOLVED_VITE_CONFIG
|
|
415
492
|
}
|
|
493
|
+
|
|
416
494
|
state.RESOLVED_VITE_CONFIG = themeConfig
|
|
417
495
|
? userConfig
|
|
418
496
|
? mergeConfig(themeConfig, userConfig)
|
|
419
497
|
: themeConfig
|
|
420
498
|
: userConfig
|
|
499
|
+
|
|
500
|
+
const userHasBase = userConfig && hasOwn(userConfig, 'base')
|
|
501
|
+
if (state.SITE_BASE && (cli.CLI_BASE || !userHasBase)) {
|
|
502
|
+
state.RESOLVED_VITE_CONFIG.base = state.SITE_BASE
|
|
503
|
+
}
|
|
504
|
+
|
|
505
|
+
state.VITE_BASE = normalizeViteBase(state.RESOLVED_VITE_CONFIG?.base || state.SITE_BASE || '/')
|
|
506
|
+
|
|
507
|
+
if (command === 'serve') {
|
|
508
|
+
if (state.VITE_BASE !== '/' || (state.SITE_BASE && state.SITE_BASE !== '/')) {
|
|
509
|
+
warnDevBase(state.RESOLVED_VITE_CONFIG?.base || state.SITE_BASE || '')
|
|
510
|
+
}
|
|
511
|
+
state.RESOLVED_VITE_CONFIG.base = '/'
|
|
512
|
+
state.VITE_BASE = '/'
|
|
513
|
+
}
|
|
514
|
+
|
|
421
515
|
return state.RESOLVED_VITE_CONFIG
|
|
422
516
|
}
|
|
517
|
+
|
|
518
|
+
export const resolveBasePrefix = cached(() => {
|
|
519
|
+
const value = state.VITE_BASE || state.SITE_BASE || '/'
|
|
520
|
+
if (!value || value === '/' || value === './') return ''
|
|
521
|
+
if (typeof value !== 'string') return ''
|
|
522
|
+
let base = value.trim()
|
|
523
|
+
if (!base || base === '/' || base === './') return ''
|
|
524
|
+
if (base.startsWith('http://') || base.startsWith('https://')) {
|
|
525
|
+
try {
|
|
526
|
+
base = new URL(base).pathname
|
|
527
|
+
} catch {
|
|
528
|
+
return ''
|
|
529
|
+
}
|
|
530
|
+
}
|
|
531
|
+
if (!base.startsWith('/')) return ''
|
|
532
|
+
if (base.endsWith('/')) base = base.slice(0, -1)
|
|
533
|
+
return base
|
|
534
|
+
})
|
|
535
|
+
|
|
536
|
+
export const withBase = cachedStr((value) => {
|
|
537
|
+
if (!value || typeof value !== 'string') return value
|
|
538
|
+
if (
|
|
539
|
+
value.startsWith('http://') ||
|
|
540
|
+
value.startsWith('https://') ||
|
|
541
|
+
value.startsWith('//') ||
|
|
542
|
+
value.startsWith('data:') ||
|
|
543
|
+
value.startsWith('mailto:') ||
|
|
544
|
+
value.startsWith('#')
|
|
545
|
+
) {
|
|
546
|
+
return value
|
|
547
|
+
}
|
|
548
|
+
if (!value.startsWith('/')) return value
|
|
549
|
+
const prefix = resolveBasePrefix()
|
|
550
|
+
if (!prefix || value.startsWith(`${prefix}/`)) return value
|
|
551
|
+
return `${prefix}${value}`
|
|
552
|
+
})
|
package/src/dev-server.js
CHANGED
|
@@ -49,6 +49,7 @@ export const runViteDev = async () => {
|
|
|
49
49
|
const baseConfig = {
|
|
50
50
|
configFile: false,
|
|
51
51
|
root: state.PAGES_DIR,
|
|
52
|
+
appType: 'mpa',
|
|
52
53
|
publicDir: state.STATIC_DIR === false ? false : state.STATIC_DIR,
|
|
53
54
|
server: {
|
|
54
55
|
fs: {
|
|
@@ -66,6 +67,8 @@ export const runViteDev = async () => {
|
|
|
66
67
|
}
|
|
67
68
|
const userConfig = await resolveUserViteConfig('serve')
|
|
68
69
|
const finalConfig = userConfig ? mergeConfig(baseConfig, userConfig) : baseConfig
|
|
70
|
+
const devBase = state.VITE_BASE || '/'
|
|
71
|
+
const devBasePrefix = devBase === '/' ? '' : devBase.slice(0, -1)
|
|
69
72
|
if (state.STATIC_DIR !== false && state.MERGED_ASSETS_DIR) {
|
|
70
73
|
await preparePublicAssets({
|
|
71
74
|
themeDir: state.THEME_ASSETS_DIR,
|
|
@@ -169,7 +172,14 @@ export const runViteDev = async () => {
|
|
|
169
172
|
}
|
|
170
173
|
|
|
171
174
|
const resolvePageFile = (routePath) => {
|
|
172
|
-
|
|
175
|
+
let name = 'index'
|
|
176
|
+
if (routePath && routePath !== '/') {
|
|
177
|
+
if (routePath.endsWith('/')) {
|
|
178
|
+
name = `${routePath.slice(1, -1)}/index`
|
|
179
|
+
} else {
|
|
180
|
+
name = routePath.slice(1)
|
|
181
|
+
}
|
|
182
|
+
}
|
|
173
183
|
const mdxPath = resolve(state.PAGES_DIR, `${name}.mdx`)
|
|
174
184
|
if (existsSync(mdxPath)) return mdxPath
|
|
175
185
|
const mdPath = resolve(state.PAGES_DIR, `${name}.md`)
|
|
@@ -181,6 +191,8 @@ export const runViteDev = async () => {
|
|
|
181
191
|
const candidates = []
|
|
182
192
|
if (pathname === '/' || pathname === '') {
|
|
183
193
|
candidates.push('/index.html')
|
|
194
|
+
} else if (pathname.endsWith('/')) {
|
|
195
|
+
candidates.push(`${pathname}index.html`)
|
|
184
196
|
} else if (pathname.endsWith('.html')) {
|
|
185
197
|
candidates.push(pathname)
|
|
186
198
|
} else {
|
|
@@ -196,7 +208,7 @@ export const runViteDev = async () => {
|
|
|
196
208
|
if (hasMdx) return false
|
|
197
209
|
const baseName = basename(relativePath, '.html')
|
|
198
210
|
if (baseName.startsWith('_') || baseName.startsWith('.')) return false
|
|
199
|
-
const excludedDirs = pagesContext
|
|
211
|
+
const excludedDirs = pagesContext.excludedDirs
|
|
200
212
|
if (excludedDirs?.size) {
|
|
201
213
|
const dir = relativePath.split('/').slice(0, -1).join('/')
|
|
202
214
|
for (const excludedDir of excludedDirs) {
|
|
@@ -206,9 +218,9 @@ export const runViteDev = async () => {
|
|
|
206
218
|
}
|
|
207
219
|
}
|
|
208
220
|
}
|
|
209
|
-
const excludedRoutes = pagesContext
|
|
221
|
+
const excludedRoutes = pagesContext.excludedRoutes
|
|
210
222
|
if (excludedRoutes?.has(requestedPath)) return false
|
|
211
|
-
const excludedDirPaths = pagesContext
|
|
223
|
+
const excludedDirPaths = pagesContext.excludedDirPaths
|
|
212
224
|
if (excludedDirPaths?.size) {
|
|
213
225
|
for (const dirPath of excludedDirPaths) {
|
|
214
226
|
if (requestedPath === dirPath || requestedPath.startsWith(`${dirPath}/`)) {
|
|
@@ -223,9 +235,6 @@ export const runViteDev = async () => {
|
|
|
223
235
|
if (!req.url || req.method !== 'GET') {
|
|
224
236
|
return next()
|
|
225
237
|
}
|
|
226
|
-
if (req.url.startsWith('/@vite') || req.url.startsWith('/__vite')) {
|
|
227
|
-
return next()
|
|
228
|
-
}
|
|
229
238
|
|
|
230
239
|
const url = new URL(req.url, 'http://methanol')
|
|
231
240
|
let pathname = url.pathname
|
|
@@ -233,7 +242,20 @@ export const runViteDev = async () => {
|
|
|
233
242
|
pathname = decodeURIComponent(pathname)
|
|
234
243
|
} catch {}
|
|
235
244
|
const originalPathname = pathname
|
|
236
|
-
|
|
245
|
+
if (devBase !== '/') {
|
|
246
|
+
const baseNoSlash = devBasePrefix
|
|
247
|
+
if (originalPathname === baseNoSlash) {
|
|
248
|
+
pathname = '/'
|
|
249
|
+
} else if (originalPathname.startsWith(devBase)) {
|
|
250
|
+
pathname = originalPathname.slice(devBase.length - 1)
|
|
251
|
+
} else {
|
|
252
|
+
return next()
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
if (pathname.startsWith('/@vite') || pathname.startsWith('/__vite')) {
|
|
257
|
+
return next()
|
|
258
|
+
}
|
|
237
259
|
|
|
238
260
|
if (pathname.includes('.') && !pathname.endsWith('.html')) {
|
|
239
261
|
return next()
|
|
@@ -251,15 +273,11 @@ export const runViteDev = async () => {
|
|
|
251
273
|
routePath = '/'
|
|
252
274
|
}
|
|
253
275
|
}
|
|
254
|
-
if (routePath.endsWith('/') && routePath !== '/') {
|
|
255
|
-
routePath = routePath.slice(0, -1)
|
|
256
|
-
}
|
|
257
|
-
|
|
258
276
|
const requestedPath = routePath
|
|
259
277
|
const isExcludedPath = () => {
|
|
260
|
-
const excludedRoutes = pagesContext
|
|
278
|
+
const excludedRoutes = pagesContext.excludedRoutes
|
|
261
279
|
if (excludedRoutes?.has(requestedPath)) return true
|
|
262
|
-
const excludedDirPaths = pagesContext
|
|
280
|
+
const excludedDirPaths = pagesContext.excludedDirPaths
|
|
263
281
|
if (excludedDirPaths?.size) {
|
|
264
282
|
for (const dirPath of excludedDirPaths) {
|
|
265
283
|
if (requestedPath === dirPath || requestedPath.startsWith(`${dirPath}/`)) {
|
|
@@ -269,10 +287,8 @@ export const runViteDev = async () => {
|
|
|
269
287
|
}
|
|
270
288
|
return false
|
|
271
289
|
}
|
|
272
|
-
const notFoundPage = pagesContext
|
|
273
|
-
|
|
274
|
-
? (pagesContext?.pagesByRouteIndex?.get(requestedPath) ?? pagesContext?.pagesByRoute?.get(requestedPath) ?? null)
|
|
275
|
-
: (pagesContext?.pagesByRoute?.get(requestedPath) ?? null)
|
|
290
|
+
const notFoundPage = pagesContext.pagesByRoute.get('/404')
|
|
291
|
+
let pageMeta = pagesContext.pagesByRoute.get(requestedPath)
|
|
276
292
|
let filePath = pageMeta?.filePath || resolvePageFile(requestedPath)
|
|
277
293
|
const hasMdx = Boolean(pageMeta) || existsSync(filePath)
|
|
278
294
|
let status = 200
|
|
@@ -291,7 +307,9 @@ export const runViteDev = async () => {
|
|
|
291
307
|
}
|
|
292
308
|
try {
|
|
293
309
|
const html = await readFile(candidate, 'utf-8')
|
|
294
|
-
const candidateUrl =
|
|
310
|
+
const candidateUrl = devBasePrefix
|
|
311
|
+
? `${devBasePrefix}/${relativePath}`
|
|
312
|
+
: `/${relativePath}`
|
|
295
313
|
const transformed = await server.transformIndexHtml(candidateUrl, html)
|
|
296
314
|
res.statusCode = 200
|
|
297
315
|
res.setHeader('Content-Type', 'text/html')
|
|
@@ -326,6 +344,8 @@ export const runViteDev = async () => {
|
|
|
326
344
|
} else {
|
|
327
345
|
return next()
|
|
328
346
|
}
|
|
347
|
+
} else if (requestedPath.endsWith('/index')) {
|
|
348
|
+
renderRoutePath = requestedPath.slice(0, -5) // remove last 'index'
|
|
329
349
|
}
|
|
330
350
|
|
|
331
351
|
try {
|
|
@@ -338,6 +358,8 @@ export const runViteDev = async () => {
|
|
|
338
358
|
return
|
|
339
359
|
}
|
|
340
360
|
|
|
361
|
+
pageMeta ??= pagesContext.getPageByRoute(renderRoutePath, { filePath })
|
|
362
|
+
|
|
341
363
|
const html = await renderHtml({
|
|
342
364
|
routePath: renderRoutePath,
|
|
343
365
|
filePath,
|
|
@@ -374,16 +396,18 @@ export const runViteDev = async () => {
|
|
|
374
396
|
await server.listen()
|
|
375
397
|
server.printUrls()
|
|
376
398
|
|
|
377
|
-
const
|
|
378
|
-
const
|
|
379
|
-
if (
|
|
380
|
-
server.moduleGraph.invalidateModule(
|
|
381
|
-
}
|
|
382
|
-
const injectModule = server.moduleGraph.getModuleById('\0/.methanol_virtual_module/inject.js')
|
|
383
|
-
if (injectModule) {
|
|
384
|
-
server.moduleGraph.invalidateModule(injectModule)
|
|
399
|
+
const _invalidate = (id) => {
|
|
400
|
+
const _module = server.moduleGraph.getModuleById(id)
|
|
401
|
+
if (_module) {
|
|
402
|
+
server.moduleGraph.invalidateModule(_module)
|
|
385
403
|
}
|
|
386
404
|
}
|
|
405
|
+
const invalidateRewindInject = () => {
|
|
406
|
+
_invalidate('\0/.methanol_virtual_module/registry.js')
|
|
407
|
+
_invalidate('\0methanol:registry')
|
|
408
|
+
_invalidate('\0/.methanol_virtual_module/inject.js')
|
|
409
|
+
_invalidate('\0methanol:inject')
|
|
410
|
+
}
|
|
387
411
|
|
|
388
412
|
let queue = Promise.resolve()
|
|
389
413
|
const enqueue = (task) => {
|
package/src/logger.js
ADDED
|
@@ -0,0 +1,80 @@
|
|
|
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
|
+
const supportColor =
|
|
22
|
+
typeof process !== 'undefined' &&
|
|
23
|
+
process.stdout &&
|
|
24
|
+
(process.stdout.isTTY || process.env.FORCE_COLOR)
|
|
25
|
+
|
|
26
|
+
const formatter = (open, close, replace = open) =>
|
|
27
|
+
supportColor
|
|
28
|
+
? (input) => {
|
|
29
|
+
const string = '' + input
|
|
30
|
+
const index = string.indexOf(close, open.length)
|
|
31
|
+
return ~index
|
|
32
|
+
? open + getReplace(string, index, close, replace) + close
|
|
33
|
+
: open + string + close
|
|
34
|
+
}
|
|
35
|
+
: (input) => '' + input
|
|
36
|
+
|
|
37
|
+
const getReplace = (string, index, close, replace) => {
|
|
38
|
+
const head = string.substring(0, index) + replace
|
|
39
|
+
const tail = string.substring(index + close.length)
|
|
40
|
+
const next = tail.indexOf(close)
|
|
41
|
+
return ~next ? head + getReplace(tail, next, close, replace) : head + tail
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export const style = {
|
|
45
|
+
reset: formatter('\x1b[0m', '\x1b[0m'),
|
|
46
|
+
bold: formatter('\x1b[1m', '\x1b[22m', '\x1b[22m\x1b[1m'),
|
|
47
|
+
dim: formatter('\x1b[2m', '\x1b[22m', '\x1b[22m\x1b[2m'),
|
|
48
|
+
italic: formatter('\x1b[3m', '\x1b[23m'),
|
|
49
|
+
underline: formatter('\x1b[4m', '\x1b[24m'),
|
|
50
|
+
inverse: formatter('\x1b[7m', '\x1b[27m'),
|
|
51
|
+
hidden: formatter('\x1b[8m', '\x1b[28m'),
|
|
52
|
+
strikethrough: formatter('\x1b[9m', '\x1b[29m'),
|
|
53
|
+
|
|
54
|
+
black: formatter('\x1b[30m', '\x1b[39m'),
|
|
55
|
+
red: formatter('\x1b[31m', '\x1b[39m'),
|
|
56
|
+
green: formatter('\x1b[32m', '\x1b[39m'),
|
|
57
|
+
yellow: formatter('\x1b[33m', '\x1b[39m'),
|
|
58
|
+
blue: formatter('\x1b[34m', '\x1b[39m'),
|
|
59
|
+
magenta: formatter('\x1b[35m', '\x1b[39m'),
|
|
60
|
+
cyan: formatter('\x1b[36m', '\x1b[39m'),
|
|
61
|
+
white: formatter('\x1b[37m', '\x1b[39m'),
|
|
62
|
+
gray: formatter('\x1b[90m', '\x1b[39m'),
|
|
63
|
+
|
|
64
|
+
bgBlack: formatter('\x1b[40m', '\x1b[49m'),
|
|
65
|
+
bgRed: formatter('\x1b[41m', '\x1b[49m'),
|
|
66
|
+
bgGreen: formatter('\x1b[42m', '\x1b[49m'),
|
|
67
|
+
bgYellow: formatter('\x1b[43m', '\x1b[49m'),
|
|
68
|
+
bgBlue: formatter('\x1b[44m', '\x1b[49m'),
|
|
69
|
+
bgMagenta: formatter('\x1b[45m', '\x1b[49m'),
|
|
70
|
+
bgCyan: formatter('\x1b[46m', '\x1b[49m'),
|
|
71
|
+
bgWhite: formatter('\x1b[47m', '\x1b[49m')
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
export const logger = {
|
|
75
|
+
info: (msg) => console.log(`${style.blue('ℹ')} ${msg}`),
|
|
76
|
+
success: (msg) => console.log(`${style.green('✔')} ${msg}`),
|
|
77
|
+
warn: (msg) => console.log(`${style.yellow('⚠')} ${msg}`),
|
|
78
|
+
error: (msg) => console.log(`${style.red('✖')} ${msg}`),
|
|
79
|
+
dim: (msg) => console.log(style.dim(msg))
|
|
80
|
+
}
|
package/src/main.js
CHANGED
|
@@ -26,13 +26,14 @@ 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 {
|
|
32
33
|
const pkgUrl = new URL('../package.json', import.meta.url)
|
|
33
34
|
const raw = await readFile(pkgUrl, 'utf-8')
|
|
34
35
|
const pkg = JSON.parse(raw)
|
|
35
|
-
const version =
|
|
36
|
+
const version = `v${pkg.version}`
|
|
36
37
|
const isTty = Boolean(process.stdout && process.stdout.isTTY)
|
|
37
38
|
const label = `Methanol ${version}`.trim()
|
|
38
39
|
if (isTty) {
|
|
@@ -63,6 +64,7 @@ const main = async () => {
|
|
|
63
64
|
const config = await loadUserConfig(mode, cli.CLI_CONFIG_PATH)
|
|
64
65
|
await applyConfig(config, mode)
|
|
65
66
|
const userSite = state.USER_SITE || {}
|
|
67
|
+
const siteBase = state.VITE_BASE ?? userSite.base ?? null
|
|
66
68
|
const hookContext = {
|
|
67
69
|
mode,
|
|
68
70
|
root: state.ROOT_DIR,
|
|
@@ -73,6 +75,7 @@ const main = async () => {
|
|
|
73
75
|
HTMLRenderer,
|
|
74
76
|
site: {
|
|
75
77
|
...userSite,
|
|
78
|
+
base: siteBase,
|
|
76
79
|
name: state.SITE_NAME,
|
|
77
80
|
root: state.ROOT_DIR,
|
|
78
81
|
pagesDir: state.PAGES_DIR,
|
|
@@ -105,6 +108,7 @@ const main = async () => {
|
|
|
105
108
|
return
|
|
106
109
|
}
|
|
107
110
|
if (isBuild) {
|
|
111
|
+
const startTime = performance.now()
|
|
108
112
|
await runHooks(state.USER_PRE_BUILD_HOOKS)
|
|
109
113
|
await runHooks(state.THEME_PRE_BUILD_HOOKS)
|
|
110
114
|
const { entry, htmlCache, pagesContext } = await buildHtmlEntries()
|
|
@@ -127,6 +131,11 @@ const main = async () => {
|
|
|
127
131
|
}
|
|
128
132
|
await runHooks(state.THEME_POST_BUILD_HOOKS, buildContext)
|
|
129
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
|
+
console.log()
|
|
138
|
+
logger.success(`Build completed in ${style.bold(timeString)}.`)
|
|
130
139
|
return
|
|
131
140
|
}
|
|
132
141
|
cli.showHelp()
|