valaxy 0.28.1 → 0.28.2

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.
@@ -0,0 +1,89 @@
1
+ <script lang="ts" setup>
2
+ import type { LocalSearchResult } from '../composables/search/useLocalSearch'
3
+ import { ref, watch } from 'vue'
4
+ import { useRouter } from 'vue-router'
5
+ import { useLocalSearch } from '../composables/search/useLocalSearch'
6
+
7
+ const props = defineProps<{
8
+ open: boolean
9
+ }>()
10
+
11
+ const emit = defineEmits<{
12
+ (e: 'close'): void
13
+ }>()
14
+
15
+ const query = ref('')
16
+ const { results, loading, load } = useLocalSearch(query)
17
+ const selectedIndex = ref(0)
18
+
19
+ const router = useRouter()
20
+
21
+ watch(() => props.open, (val) => {
22
+ if (val) {
23
+ load()
24
+ selectedIndex.value = 0
25
+ }
26
+ else {
27
+ query.value = ''
28
+ }
29
+ })
30
+
31
+ watch(results, () => {
32
+ selectedIndex.value = 0
33
+ })
34
+
35
+ function getPageTitle(id: string): string {
36
+ return id.replace(/#.*$/, '').replace(/\.html$/, '') || '/'
37
+ }
38
+
39
+ function getSectionTitle(result: LocalSearchResult): string {
40
+ return [...result.titles, result.title].filter(Boolean).join(' > ')
41
+ }
42
+
43
+ function navigate(result: LocalSearchResult) {
44
+ const url = result.id
45
+ router.push(url)
46
+ emit('close')
47
+ }
48
+
49
+ function updateQuery(value: string) {
50
+ query.value = value
51
+ }
52
+
53
+ function onKeydown(e: KeyboardEvent) {
54
+ switch (e.key) {
55
+ case 'ArrowDown':
56
+ e.preventDefault()
57
+ selectedIndex.value = Math.min(selectedIndex.value + 1, results.value.length - 1)
58
+ break
59
+ case 'ArrowUp':
60
+ e.preventDefault()
61
+ selectedIndex.value = Math.max(selectedIndex.value - 1, 0)
62
+ break
63
+ case 'Enter':
64
+ e.preventDefault()
65
+ if (results.value[selectedIndex.value]) {
66
+ navigate(results.value[selectedIndex.value])
67
+ }
68
+ break
69
+ case 'Escape':
70
+ e.preventDefault()
71
+ emit('close')
72
+ break
73
+ }
74
+ }
75
+ </script>
76
+
77
+ <template>
78
+ <slot
79
+ :query="query"
80
+ :results="results"
81
+ :loading="loading"
82
+ :selected-index="selectedIndex"
83
+ :update-query="updateQuery"
84
+ :navigate="navigate"
85
+ :on-keydown="onKeydown"
86
+ :get-page-title="getPageTitle"
87
+ :get-section-title="getSectionTitle"
88
+ />
89
+ </template>
@@ -28,7 +28,7 @@ import valaxyLogoPng from '../assets/images/valaxy-logo.png'
28
28
  max-width: 350px;
29
29
  width: 150%;
30
30
  height: 150%;
31
- background-image: linear-gradient(-45deg, rgb(108, 34, 236) 50%, rgba(59,130,246,var(--un-to-opacity, 1)) 50%);
31
+ background-image: linear-gradient(-45deg, rgb(108 34 236) 50%, rgb(59 130 246 / var(--un-to-opacity, 1)) 50%);
32
32
  opacity: 0.3;
33
33
  transition: opacity var(--va-transition-duration-fast);
34
34
  }
@@ -74,7 +74,7 @@ function jumpTo(page: number) {
74
74
 
75
75
  <style lang="scss">
76
76
  :root {
77
- --page-btn-bg-color: rgba(255, 255, 255, 0.5);
77
+ --page-btn-bg-color: rgb(255 255 255 / 0.5);
78
78
  --page-btn-hover-bg-color: var(--va-c-primary-lighter);
79
79
  --page-btn-active-bg-color: var(--va-c-primary-light);
80
80
  }
@@ -166,7 +166,6 @@ export function mergeCollapsedCollections(
166
166
 
167
167
  /**
168
168
  * get post list in 'pages/posts' folder
169
- * todo: use vue provide/inject to global
170
169
  */
171
170
  export function usePostList(params: {
172
171
  type?: string
@@ -1 +1,2 @@
1
1
  export * from './useFuseSearch'
2
+ export * from './useLocalSearch'
@@ -0,0 +1,53 @@
1
+ import type MiniSearch from 'minisearch'
2
+ import type { Ref } from 'vue'
3
+ import { ref, shallowRef, watchEffect } from 'vue'
4
+
5
+ export interface LocalSearchResult {
6
+ id: string
7
+ score: number
8
+ terms: string[]
9
+ title: string
10
+ titles: string[]
11
+ }
12
+
13
+ export function useLocalSearch(query: Ref<string>) {
14
+ const results = shallowRef<LocalSearchResult[]>([])
15
+ const loading = ref(false)
16
+ let miniSearch: MiniSearch | null = null
17
+
18
+ async function load(locale = 'root') {
19
+ loading.value = true
20
+ try {
21
+ const searchIndex = (await import('@localSearchIndex')).default
22
+ const loader = searchIndex[locale] ?? searchIndex[Object.keys(searchIndex)[0]]
23
+ if (!loader) {
24
+ loading.value = false
25
+ return
26
+ }
27
+ const mod = await loader()
28
+ const data: string = JSON.parse(mod.default)
29
+ const { default: MiniSearchCtor } = await import('minisearch')
30
+ miniSearch = MiniSearchCtor.loadJSON(data, {
31
+ fields: ['title', 'titles', 'text'],
32
+ storeFields: ['title', 'titles'],
33
+ })
34
+ }
35
+ finally {
36
+ loading.value = false
37
+ }
38
+ }
39
+
40
+ watchEffect(() => {
41
+ if (!miniSearch || !query.value.trim()) {
42
+ results.value = []
43
+ return
44
+ }
45
+ results.value = miniSearch.search(query.value, {
46
+ prefix: true,
47
+ fuzzy: 0.2,
48
+ boost: { title: 4, text: 2, titles: 1 },
49
+ }) as unknown as LocalSearchResult[]
50
+ })
51
+
52
+ return { results, loading, load }
53
+ }
@@ -26,6 +26,6 @@ const { back } = useBack()
26
26
  // inspired by https://codepen.io/pgalor/pen/OeRWJQ
27
27
  .not-found {
28
28
  font-size: 10rem;
29
- text-shadow: 0 5px 10px rgba(0,0,0,.25), 0 20px 20px rgba(0,0,0,.15);
29
+ text-shadow: 0 5px 10px rgb(0 0 0 / .25), 0 20px 20px rgb(0 0 0 / .15);
30
30
  }
31
31
  </style>
@@ -92,9 +92,12 @@ category:
92
92
 
93
93
  search:
94
94
  placeholder: Searching...
95
+ loading: Loading...
95
96
  empty: 'We could not find any results for the search: {query}.'
96
97
  hits_time: '{hits} results found in {time} ms'
97
98
  hits: '{count} results found'
99
+ no_results: No results found
100
+ no_results_hint: Try adjusting your search terms
98
101
 
99
102
  symbol:
100
103
  comma: ', '
@@ -91,9 +91,12 @@ category:
91
91
 
92
92
  search:
93
93
  placeholder: 搜索...
94
+ loading: 加载中...
94
95
  empty: '找不到您查询的内容: {query}'
95
96
  hits_time: '找到 {hits} 条结果(用时 {time} 毫秒)'
96
97
  hits: '找到 {count} 条结果'
98
+ no_results: 未找到相关结果
99
+ no_results_hint: 请尝试调整搜索关键词
97
100
 
98
101
  symbol:
99
102
  comma: ,
@@ -1,6 +1,5 @@
1
1
  import type { ValaxySSGContext } from '../setups'
2
2
 
3
- import { defineAsyncComponent } from 'vue'
4
3
  import AppLink from '../components/AppLink.vue'
5
4
  import ValaxyTranslate from '../components/builtin/ValaxyTranslate.vue'
6
5
 
@@ -11,10 +10,4 @@ import ValaxyTranslate from '../components/builtin/ValaxyTranslate.vue'
11
10
  export function registerGlobalComponents(ctx: ValaxySSGContext) {
12
11
  ctx.app.component('AppLink', AppLink)
13
12
  ctx.app.component('VT', ValaxyTranslate)
14
-
15
- // DEV-only: register ValaxyDebug component (tree-shaken in production)
16
- if (import.meta.env.DEV) {
17
- const ValaxyDebug = defineAsyncComponent(() => import('../components/.exclude/ValaxyDebug.vue'))
18
- ctx.app.component('ValaxyDebug', ValaxyDebug)
19
- }
20
13
  }
package/client/shims.d.ts CHANGED
@@ -37,6 +37,11 @@ declare module '#valaxy/styles' {
37
37
  export default styles
38
38
  }
39
39
 
40
+ declare module '@localSearchIndex' {
41
+ const index: Record<string, () => Promise<{ default: string }>>
42
+ export default index
43
+ }
44
+
40
45
  // valaxy features
41
46
  declare module '#valaxy/blog/collections' {
42
47
  import type { CollectionConfig } from './types'
@@ -58,7 +58,7 @@ html:not(.dark) .vp-code-dark {
58
58
  white-space: pre;
59
59
  word-spacing: normal;
60
60
  word-break: normal;
61
- word-wrap: normal;
61
+ overflow-wrap: normal;
62
62
  tab-size: 4;
63
63
  hyphens: none;
64
64
  }
@@ -4,4 +4,4 @@
4
4
  @use "./transition.scss" as *;
5
5
 
6
6
  // markdown
7
- @use "./markdown.scss";
7
+ @use "./markdown";
@@ -1,7 +1,6 @@
1
1
  @use "sass:map";
2
2
 
3
3
  .markdown-body {
4
-
5
4
  h1,
6
5
  h2,
7
6
  h3,
@@ -52,27 +52,26 @@ html.dark {
52
52
  * - `text-3`: Used for subtle texts, such as "placeholders" or "caret icon".
53
53
  * -------------------------------------------------------------------------- */
54
54
  :root {
55
- --va-c-text-1: rgba(60, 60, 67);
56
- --va-c-text-2: rgba(60, 60, 67, 0.78);
57
- --va-c-text-3: rgba(60, 60, 67, 0.56);
55
+ --va-c-text-1: rgb(60 60 67);
56
+ --va-c-text-2: rgb(60 60 67 / 0.78);
57
+ --va-c-text-3: rgb(60 60 67 / 0.56);
58
58
  }
59
59
 
60
60
  .dark {
61
- --va-c-text-1: rgba(255, 255, 245, 0.86);
62
- --va-c-text-2: rgba(235, 235, 245, 0.6);
63
- --va-c-text-3: rgba(235, 235, 245, 0.38);
61
+ --va-c-text-1: rgb(255 255 245 / 0.86);
62
+ --va-c-text-2: rgb(235 235 245 / 0.6);
63
+ --va-c-text-3: rgb(235 235 245 / 0.38);
64
64
  }
65
65
 
66
66
  // bg
67
67
  :root {
68
- --va-c-bg: #ffffff;
69
- --va-c-bg-light: #ffffff;
68
+ --va-c-bg: #fff;
69
+ --va-c-bg-light: #fff;
70
70
  --va-c-bg-dark: #fafafa;
71
- --va-c-bg-opacity: rgba(255, 255, 255, 0.8);
71
+ --va-c-bg-opacity: rgb(255 255 255 / 0.8);
72
72
  --va-c-bg-soft: #f9f9f9;
73
73
  --va-c-bg-alt: #f9f9f9;
74
74
  --va-c-bg-mute: #f1f1f1;
75
-
76
75
  --va-c-bg-elevated: #f9f9f9;
77
76
  }
78
77
 
@@ -80,11 +79,10 @@ html.dark {
80
79
  --va-c-bg: #1a1a1d;
81
80
  --va-c-bg-light: #202127;
82
81
  --va-c-bg-dark: #1a1a1a;
83
- --va-c-bg-opacity: rgba(0, 0, 0, 0.8);
82
+ --va-c-bg-opacity: rgb(0 0 0 / 0.8);
84
83
  --va-c-bg-alt: #161618;
85
84
  --va-c-bg-soft: #202127;
86
85
  --va-c-bg-mute: #2f2f2f;
87
-
88
86
  --va-c-bg-elevated: #202127;
89
87
  }
90
88
 
@@ -1,4 +1,4 @@
1
- @forward './config.scss';
2
- @forward './media.scss';
3
- @forward './size.scss';
4
- @forward './variable.scss';
1
+ @forward './config';
2
+ @forward './media';
3
+ @forward './size';
4
+ @forward './variable';
@@ -1,6 +1,5 @@
1
1
  .katex-display {
2
- overflow-x: auto;
3
- overflow-y: visible;
2
+ overflow: auto visible;
4
3
  padding: 8px 0;
5
4
  }
6
5
 
@@ -1,7 +1,7 @@
1
1
  import 'node:process';
2
2
  import 'yargs';
3
3
  import 'yargs/helpers';
4
- export { c as cli, I as registerDevCommand, W as run, Z as startValaxyDev } from '../../shared/valaxy.DFTOADvQ.mjs';
4
+ export { c as cli, J as registerDevCommand, X as run, _ as startValaxyDev } from '../../shared/valaxy.Cbgd5gHB.mjs';
5
5
  import 'node:os';
6
6
  import 'node:path';
7
7
  import 'consola';
@@ -1,7 +1,7 @@
1
1
  import { ViteSSGOptions } from 'vite-ssg';
2
2
  import * as vite from 'vite';
3
3
  import { UserConfig, InlineConfig, ViteDevServer, PluginOption, Plugin } from 'vite';
4
- import { S as SiteConfig, D as DefaultTheme, R as RuntimeConfig, a as RedirectItem, V as ValaxyConfig, P as PartialDeep, b as ValaxyAddon, U as UserSiteConfig } from '../shared/valaxy.6MW2qn5T.mjs';
4
+ import { S as SiteConfig, D as DefaultTheme, R as RuntimeConfig, a as RedirectItem, V as ValaxyConfig, P as PartialDeep, b as ValaxyAddon, U as UserSiteConfig } from '../shared/valaxy.D8f6owDk.mjs';
5
5
  import Vue from '@vitejs/plugin-vue';
6
6
  import { Hookable } from 'hookable';
7
7
  import { PluginVisualizerOptions } from 'rollup-plugin-visualizer';
@@ -983,10 +983,17 @@ declare function build(valaxyApp: ValaxyNode, viteConfig?: InlineConfig): Promis
983
983
  */
984
984
  declare function ssgBuildLegacy(valaxyApp: ValaxyNode, viteConfig?: InlineConfig): Promise<void>;
985
985
  /**
986
- * post process for ssg fix extra string like `/html>` `ml>` `l>`
987
- * handle tasks after ssg build
988
- * todo find why
989
- * @param options
986
+ * Fix corrupted HTML produced by vite-ssg's JSDOM serialization under memory
987
+ * pressure. JSDOM.serialize() can emit truncated trailing fragments
988
+ * (e.g. `/html>`, `ml>`, `l>`) when heap is constrained during
989
+ * high-concurrency renders.
990
+ *
991
+ * Only needed for the legacy vite-ssg engine; the built-in Valaxy SSG
992
+ * engine uses pure string rendering and is not affected.
993
+ */
994
+ declare function fixViteSsgHtml(options: ResolvedValaxyOptions): Promise<void>;
995
+ /**
996
+ * Shared post-processing after SSG build (both engines).
990
997
  */
991
998
  declare function postProcessForSSG(options: ResolvedValaxyOptions): Promise<void>;
992
999
  declare function generateClientRedirects(options: ResolvedValaxyOptions): Promise<void>;
@@ -1210,5 +1217,5 @@ declare function toAtFS(path: string): string;
1210
1217
  declare function resolveImportPath(importName: string, ensure?: true): Promise<string>;
1211
1218
  declare function resolveImportPath(importName: string, ensure?: boolean): Promise<string | undefined>;
1212
1219
 
1213
- export { $t, ALL_ROUTE, EXCERPT_SEPARATOR, GLOBAL_STATE, PATHNAME_PROTOCOL_RE, ViteValaxyPlugins, build, createServer, createValaxyPlugin, customElements, defaultSiteConfig, defaultValaxyConfig, defaultViteConfig, defineAddon, defineConfig, defineContentLoader, defineSiteConfig, defineTheme, defineUnoSetup, defineValaxyAddon, defineValaxyConfig, defineValaxyTheme, encryptContent, generateClientRedirects, getGitTimestamp, getIndexHtml, getServerInfoText, isExternal, isInstalledGlobally, isKatexEnabled, isKatexPluginNeeded, isMathJaxEnabled, isPath, loadConfigFromFile, mergeValaxyConfig, mergeViteConfigs, postProcessForSSG, processValaxyOptions, resolveAddonsConfig, resolveImportPath, resolveImportUrl, resolveOptions, resolveSiteConfig, resolveSiteConfigFromRoot, resolveThemeConfigFromRoot, resolveThemeValaxyConfig, resolveUserThemeConfig, resolveValaxyConfig, resolveValaxyConfigFromRoot, ssgBuild, ssgBuildLegacy, toAtFS, transformObject, version };
1220
+ export { $t, ALL_ROUTE, EXCERPT_SEPARATOR, GLOBAL_STATE, PATHNAME_PROTOCOL_RE, ViteValaxyPlugins, build, createServer, createValaxyPlugin, customElements, defaultSiteConfig, defaultValaxyConfig, defaultViteConfig, defineAddon, defineConfig, defineContentLoader, defineSiteConfig, defineTheme, defineUnoSetup, defineValaxyAddon, defineValaxyConfig, defineValaxyTheme, encryptContent, fixViteSsgHtml, generateClientRedirects, getGitTimestamp, getIndexHtml, getServerInfoText, isExternal, isInstalledGlobally, isKatexEnabled, isKatexPluginNeeded, isMathJaxEnabled, isPath, loadConfigFromFile, mergeValaxyConfig, mergeViteConfigs, postProcessForSSG, processValaxyOptions, resolveAddonsConfig, resolveImportPath, resolveImportUrl, resolveOptions, resolveSiteConfig, resolveSiteConfigFromRoot, resolveThemeConfigFromRoot, resolveThemeValaxyConfig, resolveUserThemeConfig, resolveValaxyConfig, resolveValaxyConfigFromRoot, ssgBuild, ssgBuildLegacy, toAtFS, transformObject, version };
1214
1221
  export type { CdnModule, ContentItem, ContentLoader, ContentLoaderContext, HookResult, LoadConfigFromFileOptions, MdAfterRenderContext, ResolvedConfig, ResolvedValaxyOptions, UnoSetup, UserInputConfig, UserValaxyNodeConfig, ValaxyAddonExport, ValaxyAddonFn, ValaxyAddonLike, ValaxyAddonResolver, ValaxyAddons, ValaxyApp, ValaxyConfigExport, ValaxyConfigExtendKey, ValaxyConfigFn, ValaxyEntryOptions, ValaxyExtendConfig, ValaxyHooks, ValaxyNode, ValaxyNodeConfig, ValaxyPickConfig, ValaxyServerOptions, ValaxyTheme };
@@ -1,5 +1,6 @@
1
- export { A as ALL_ROUTE, E as EXCERPT_SEPARATOR, G as GLOBAL_STATE, P as PATHNAME_PROTOCOL_RE, V as ViteValaxyPlugins, b as build, c as cli, a as createServer, d as createValaxyPlugin, e as customElements, f as defaultSiteConfig, g as defaultValaxyConfig, h as defaultViteConfig, i as defineAddon, j as defineConfig, k as defineSiteConfig, l as defineTheme, m as defineValaxyAddon, n as defineValaxyConfig, o as defineValaxyTheme, p as encryptContent, q as generateClientRedirects, r as getGitTimestamp, s as getIndexHtml, t as getServerInfoText, u as isExternal, v as isInstalledGlobally, w as isKatexEnabled, x as isKatexPluginNeeded, y as isMathJaxEnabled, z as isPath, B as loadConfigFromFile, C as mergeValaxyConfig, D as mergeViteConfigs, F as postProcessForSSG, H as processValaxyOptions, I as registerDevCommand, J as resolveAddonsConfig, K as resolveImportPath, L as resolveImportUrl, M as resolveOptions, N as resolveSiteConfig, O as resolveSiteConfigFromRoot, Q as resolveThemeConfigFromRoot, R as resolveThemeValaxyConfig, S as resolveUserThemeConfig, T as resolveValaxyConfig, U as resolveValaxyConfigFromRoot, W as run, X as ssgBuild, Y as ssgBuildLegacy, Z as startValaxyDev, _ as toAtFS, $ as transformObject, a0 as version } from '../shared/valaxy.DFTOADvQ.mjs';
1
+ export { A as ALL_ROUTE, E as EXCERPT_SEPARATOR, G as GLOBAL_STATE, P as PATHNAME_PROTOCOL_RE, V as ViteValaxyPlugins, b as build, c as cli, a as createServer, d as createValaxyPlugin, e as customElements, f as defaultSiteConfig, g as defaultValaxyConfig, h as defaultViteConfig, i as defineAddon, j as defineConfig, k as defineSiteConfig, l as defineTheme, m as defineValaxyAddon, n as defineValaxyConfig, o as defineValaxyTheme, p as encryptContent, q as fixViteSsgHtml, r as generateClientRedirects, s as getGitTimestamp, t as getIndexHtml, u as getServerInfoText, v as isExternal, w as isInstalledGlobally, x as isKatexEnabled, y as isKatexPluginNeeded, z as isMathJaxEnabled, B as isPath, C as loadConfigFromFile, D as mergeValaxyConfig, F as mergeViteConfigs, H as postProcessForSSG, I as processValaxyOptions, J as registerDevCommand, K as resolveAddonsConfig, L as resolveImportPath, M as resolveImportUrl, N as resolveOptions, O as resolveSiteConfig, Q as resolveSiteConfigFromRoot, R as resolveThemeConfigFromRoot, S as resolveThemeValaxyConfig, T as resolveUserThemeConfig, U as resolveValaxyConfig, W as resolveValaxyConfigFromRoot, X as run, Y as ssgBuild, Z as ssgBuildLegacy, _ as startValaxyDev, $ as toAtFS, a0 as transformObject, a1 as version } from '../shared/valaxy.Cbgd5gHB.mjs';
2
2
  import 'node:path';
3
+ import 'consola';
3
4
  import 'fs-extra';
4
5
  import 'consola/utils';
5
6
  import 'node:process';
@@ -7,7 +8,6 @@ import 'define-config-ts';
7
8
  import 'yargs';
8
9
  import 'yargs/helpers';
9
10
  import 'node:os';
10
- import 'consola';
11
11
  import 'fast-glob';
12
12
  import 'gray-matter';
13
13
  import 'js-yaml';
@@ -177,10 +177,15 @@ const customElements = /* @__PURE__ */ new Set([
177
177
  const defaultViteConfig = {};
178
178
 
179
179
  const logger = consola.create({});
180
+ function setLogLevel(level) {
181
+ consola.level = level;
182
+ logger.level = level;
183
+ }
180
184
  const valaxyPrefix = colors.magenta("[valaxy]");
181
185
  const vLogger = {
182
186
  success: (...args) => logger.success(valaxyPrefix, ...args),
183
187
  info: (...args) => logger.info(valaxyPrefix, ...args),
188
+ debug: (...args) => logger.debug(valaxyPrefix, ...args),
184
189
  ready: (...args) => logger.ready(valaxyPrefix, ...args)
185
190
  };
186
191
  async function callHookWithLog(hookName, valaxyApp) {
@@ -690,9 +695,16 @@ function countPerformanceTime() {
690
695
  return () => {
691
696
  const end = performance.now();
692
697
  const duration = end - start;
698
+ let timeStr;
693
699
  if (duration > 1e3)
694
- return `${(duration / 1e3).toFixed(2)}s`;
695
- return `${duration.toFixed(2)}ms`;
700
+ timeStr = `${(duration / 1e3).toFixed(2)}s`;
701
+ else
702
+ timeStr = `${duration.toFixed(2)}ms`;
703
+ if (duration > 3e3)
704
+ return colors.red(timeStr);
705
+ if (duration > 500)
706
+ return colors.yellow(timeStr);
707
+ return colors.green(timeStr);
696
708
  };
697
709
  }
698
710
 
@@ -1721,7 +1733,7 @@ async function setupMarkdownPlugins(md, options, base = "/") {
1721
1733
  return md;
1722
1734
  }
1723
1735
 
1724
- const version = "0.28.1";
1736
+ const version = "0.28.2";
1725
1737
 
1726
1738
  const GLOBAL_STATE = {
1727
1739
  valaxyApp: void 0,
@@ -2333,9 +2345,6 @@ const EXCLUDE = [
2333
2345
  "@vueuse/shared",
2334
2346
  "@unocss/reset",
2335
2347
  "unocss",
2336
- // addon, todo add externals for addon
2337
- // main field error
2338
- "meting",
2339
2348
  // internal
2340
2349
  "valaxy",
2341
2350
  "virtual:valaxy-addons:empty",
@@ -2352,6 +2361,7 @@ const EXCLUDE = [
2352
2361
  "vue-router/experimental"
2353
2362
  ];
2354
2363
  function createConfigPlugin(options) {
2364
+ const addonNames = options.addons.map((a) => a.name);
2355
2365
  const addonDeps = options.addons.map((i) => Object.keys(i.pkg.dependencies || {})).flat();
2356
2366
  const cdnModuleNames = options.mode === "build" ? (options.config.cdn?.modules || []).map((m) => m.name) : [];
2357
2367
  const katexEnabled = isKatexPluginNeeded(options.config);
@@ -2401,7 +2411,7 @@ function createConfigPlugin(options) {
2401
2411
  entries: [resolve$1(options.clientRoot, "main.ts")],
2402
2412
  // must need it
2403
2413
  include: includedDeps,
2404
- exclude: EXCLUDE
2414
+ exclude: uniq([...EXCLUDE, ...addonNames])
2405
2415
  },
2406
2416
  server: {
2407
2417
  fs: {
@@ -3271,6 +3281,7 @@ function createScanDeadLinks(options) {
3271
3281
  };
3272
3282
  }
3273
3283
 
3284
+ let globalPasswordLoggedOnce = false;
3274
3285
  function createTransformEncrypt(options) {
3275
3286
  const { config: { siteConfig: { encrypt } } } = options;
3276
3287
  return async (code, id, pageData) => {
@@ -3283,9 +3294,17 @@ function createTransformEncrypt(options) {
3283
3294
  "</ClientOnly>"
3284
3295
  ].join("");
3285
3296
  };
3297
+ const globalPassword = process.env.VALAXY_ENCRYPT_PASSWORD;
3298
+ const password = frontmatter.password || frontmatter.encrypt === true && globalPassword || void 0;
3299
+ if (password && !frontmatter.password && globalPassword) {
3300
+ if (!globalPasswordLoggedOnce) {
3301
+ consola.info("Using global encrypt password from env `VALAXY_ENCRYPT_PASSWORD`");
3302
+ globalPasswordLoggedOnce = true;
3303
+ }
3304
+ }
3286
3305
  const encryptRegexp = /<!-- valaxy-encrypt-start:(?<password>\w+) -->(?<content>.*?)<!-- valaxy-encrypt-end -->/gs;
3287
3306
  const encryptCommentRegexp = /((<!-- valaxy-encrypt-start:\w+ -->)|(<!-- valaxy-encrypt-end -->))/g;
3288
- if (frontmatter.password) {
3307
+ if (password) {
3289
3308
  code = code.replaceAll(encryptCommentRegexp, "");
3290
3309
  } else {
3291
3310
  const partiallyEncryptedContents = [];
@@ -3311,12 +3330,12 @@ function createTransformEncrypt(options) {
3311
3330
  });
3312
3331
  }
3313
3332
  }
3314
- if (frontmatter.password) {
3333
+ if (password) {
3315
3334
  const templateStart = code.indexOf("<template>");
3316
3335
  const templateEnd = code.lastIndexOf("</template>");
3317
3336
  const content = code.slice(templateStart + 10, templateEnd);
3318
3337
  const encryptedContent = await encryptContent(content, {
3319
- password: frontmatter.password,
3338
+ password,
3320
3339
  iv: encrypt.iv,
3321
3340
  salt: encrypt.salt
3322
3341
  });
@@ -3765,12 +3784,14 @@ async function resolveAddonsConfig(addons, options) {
3765
3784
  let valaxyConfig = {};
3766
3785
  const results = await Promise.all(
3767
3786
  addons.map(async (addon) => {
3787
+ const addonTimer = countPerformanceTime();
3768
3788
  const addonConfigPath = path$1.resolve(addon.root, "valaxy.config.ts");
3769
3789
  if (!await fs.exists(addonConfigPath))
3770
3790
  return null;
3771
3791
  const { config, configFile } = await resolveValaxyConfigFromRoot(addon.root, options);
3772
3792
  if (!config)
3773
3793
  return null;
3794
+ consola.debug(` resolveAddonConfig(${addon.name}): ${addonTimer()}`);
3774
3795
  return { addon, config, configFile };
3775
3796
  })
3776
3797
  );
@@ -3831,13 +3852,17 @@ async function parseAddons(addons, userRoot = process.cwd()) {
3831
3852
  if (Array.isArray(addons)) {
3832
3853
  for (const addon of addons) {
3833
3854
  if (typeof addon === "string") {
3855
+ const addonTimer = countPerformanceTime();
3834
3856
  const resolver = await readAddonModule(addon, { cwd: userRoot });
3857
+ consola.debug(` readAddonModule(${addon}): ${addonTimer()}`);
3835
3858
  if (resolver)
3836
3859
  mergeResolver(resolver);
3837
3860
  continue;
3838
3861
  }
3839
3862
  if (typeof addon === "object") {
3863
+ const addonTimer = countPerformanceTime();
3840
3864
  const resolver = await readAddonModule(addon.name, { cwd: userRoot });
3865
+ consola.debug(` readAddonModule(${addon.name}): ${addonTimer()}`);
3841
3866
  if (!resolver)
3842
3867
  continue;
3843
3868
  const merged = defu(addon || {}, resolver);
@@ -3943,10 +3968,16 @@ async function processSiteConfig(options) {
3943
3968
  }
3944
3969
  async function processValaxyOptions(valaxyOptions, valaxyConfig) {
3945
3970
  const { clientRoot, themeRoot, userRoot } = valaxyOptions;
3971
+ const parseAddonsTimer = countPerformanceTime();
3946
3972
  const addons = await parseAddons(valaxyConfig.addons || [], valaxyOptions.userRoot);
3973
+ consola.debug(` \u251C\u2500 parseAddons: ${parseAddonsTimer()}`);
3974
+ const resolveAddonsTimer = countPerformanceTime();
3947
3975
  const addonsValaxyConfig = await resolveAddonsConfig(addons, valaxyOptions);
3976
+ consola.debug(` \u251C\u2500 resolveAddonsConfig: ${resolveAddonsTimer()}`);
3977
+ const mergeTimer = countPerformanceTime();
3948
3978
  valaxyConfig = mergeValaxyConfig(valaxyConfig, addonsValaxyConfig);
3949
3979
  const rolldownOutputOptions = getRolldownOutputOptions(valaxyOptions);
3980
+ consola.debug(` \u251C\u2500 mergeValaxyConfig + getRolldownOutputOptions: ${mergeTimer()}`);
3950
3981
  const buildConfig = defaultValaxyConfig.vite.build ??= {};
3951
3982
  buildConfig.rolldownOptions = {
3952
3983
  ...buildConfig.rolldownOptions,
@@ -3978,7 +4009,9 @@ async function processValaxyOptions(valaxyOptions, valaxyConfig) {
3978
4009
  ...resolvedBuild.rolldownOptions,
3979
4010
  external: external.filter((name) => !addonNames.includes(name))
3980
4011
  };
4012
+ const siteConfigTimer = countPerformanceTime();
3981
4013
  await processSiteConfig(valaxyOptions);
4014
+ consola.debug(` \u2514\u2500 processSiteConfig: ${siteConfigTimer()}`);
3982
4015
  return valaxyOptions;
3983
4016
  }
3984
4017
  async function resolveOptions(options = { userRoot: process.cwd() }, mode = "dev") {
@@ -3986,6 +4019,7 @@ async function resolveOptions(options = { userRoot: process.cwd() }, mode = "dev
3986
4019
  const clientRoot = resolve(pkgRoot, "client");
3987
4020
  const userRoot = resolve(options.userRoot || process.cwd());
3988
4021
  consola.start(`Resolve ${colors.magenta("valaxy")} config ...`);
4022
+ const configTimer = countPerformanceTime();
3989
4023
  const [resolvedValaxy, resolvedSite, resolvedTheme, pages] = await Promise.all([
3990
4024
  resolveValaxyConfig(options),
3991
4025
  resolveSiteConfig(options.userRoot),
@@ -3996,6 +4030,7 @@ async function resolveOptions(options = { userRoot: process.cwd() }, mode = "dev
3996
4030
  ignore: ["**/node_modules"]
3997
4031
  })
3998
4032
  ]);
4033
+ consola.debug(`Parallel config resolve: ${configTimer()}`);
3999
4034
  let { config: userValaxyConfig, configFile, theme } = resolvedValaxy;
4000
4035
  const themeRoot = await getThemeRoot(theme, options.userRoot);
4001
4036
  const { siteConfig, siteConfigFile } = resolvedSite;
@@ -4041,7 +4076,9 @@ async function resolveOptions(options = { userRoot: process.cwd() }, mode = "dev
4041
4076
  debug(valaxyOptions);
4042
4077
  const themeValaxyConfig = await resolveThemeValaxyConfig(valaxyOptions);
4043
4078
  const valaxyConfig = mergeValaxyConfig(userValaxyConfig, themeValaxyConfig);
4079
+ const processTimer = countPerformanceTime();
4044
4080
  valaxyOptions = await processValaxyOptions(valaxyOptions, valaxyConfig);
4081
+ consola.debug(`processValaxyOptions: ${processTimer()}`);
4045
4082
  fs.ensureDirSync(valaxyOptions.tempDir);
4046
4083
  return valaxyOptions;
4047
4084
  }
@@ -4391,6 +4428,10 @@ async function createRouterPlugin(valaxyApp) {
4391
4428
  ...valaxyConfig.loaders?.length ? [resolve(options.tempDir, "content", "pages")] : []
4392
4429
  ],
4393
4430
  dts: resolve(options.tempDir, "route-map.d.ts"),
4431
+ // Disable file watching during build to prevent chokidar from opening
4432
+ // too many file descriptors (EMFILE) in large monorepos.
4433
+ // vue-router defaults to `watch: !process.env.CI`, which is true locally.
4434
+ watch: options.mode !== "build",
4394
4435
  ...valaxyConfig.router,
4395
4436
  /**
4396
4437
  * @experimental See https://github.com/posva/unplugin-vue-router/issues/43 (now part of vue-router)
@@ -4401,7 +4442,7 @@ async function createRouterPlugin(valaxyApp) {
4401
4442
  _lastFrontmatterRef = valaxyConfig.siteConfig.frontmatter;
4402
4443
  _cachedFrontmatter = structuredClone(valaxyConfig.siteConfig.frontmatter);
4403
4444
  }
4404
- const defaultFrontmatter = structuredClone(_cachedFrontmatter) || {};
4445
+ const defaultFrontmatter = structuredClone(_cachedFrontmatter);
4405
4446
  if (route.meta && route.meta.frontmatter) {
4406
4447
  const { frontmatter: _, otherMeta } = route.meta;
4407
4448
  route.meta = otherMeta;
@@ -4470,6 +4511,8 @@ async function createRouterPlugin(valaxyApp) {
4470
4511
  "links",
4471
4512
  "photos"
4472
4513
  // @TODO defineBasicLoader for page
4514
+ // Waiting for upstream API to stabilize
4515
+ // https://github.com/YunYouJun/valaxy/issues/487
4473
4516
  // 'projects',
4474
4517
  ];
4475
4518
  const routerFM = {
@@ -4521,7 +4564,10 @@ async function createRouterPlugin(valaxyApp) {
4521
4564
  path
4522
4565
  });
4523
4566
  }
4567
+ const extendRouteTimer = countPerformanceTime();
4524
4568
  await valaxyApp.hooks.callHook("vue-router:extendRoute", route);
4569
+ const extendDuration = extendRouteTimer();
4570
+ vLogger.debug(` extendRoute(${route.fullPath}): ${extendDuration}`);
4525
4571
  return valaxyConfig.router?.extendRoute?.(route);
4526
4572
  },
4527
4573
  async beforeWriteFiles(root) {
@@ -4533,6 +4579,15 @@ async function createRouterPlugin(valaxyApp) {
4533
4579
  async function ViteValaxyPlugins(valaxyApp, serverOptions = {}) {
4534
4580
  const { options } = valaxyApp;
4535
4581
  const { roots, config: valaxyConfig } = options;
4582
+ const timers = {
4583
+ markdown: countPerformanceTime(),
4584
+ valaxy: countPerformanceTime(),
4585
+ vue: countPerformanceTime(),
4586
+ router: countPerformanceTime(),
4587
+ unocss: countPerformanceTime(),
4588
+ localSearch: countPerformanceTime(),
4589
+ scanTitles: countPerformanceTime()
4590
+ };
4536
4591
  const [
4537
4592
  MarkdownPlugin,
4538
4593
  ValaxyPlugin,
@@ -4542,8 +4597,14 @@ async function ViteValaxyPlugins(valaxyApp, serverOptions = {}) {
4542
4597
  LocalSearchPlugin,
4543
4598
  scannedTitles
4544
4599
  ] = await Promise.all([
4545
- createMarkdownPlugin(options),
4546
- createValaxyPlugin(options, serverOptions),
4600
+ createMarkdownPlugin(options).then((r) => {
4601
+ vLogger.debug(` \u251C\u2500 createMarkdownPlugin: ${timers.markdown()}`);
4602
+ return r;
4603
+ }),
4604
+ createValaxyPlugin(options, serverOptions).then((r) => {
4605
+ vLogger.debug(` \u251C\u2500 createValaxyPlugin: ${timers.valaxy()}`);
4606
+ return r;
4607
+ }),
4547
4608
  import('@vitejs/plugin-vue').then(
4548
4609
  (r) => r.default({
4549
4610
  include: /\.(?:vue|md)$/,
@@ -4563,11 +4624,26 @@ async function ViteValaxyPlugins(valaxyApp, serverOptions = {}) {
4563
4624
  }
4564
4625
  }
4565
4626
  })
4566
- ),
4567
- createRouterPlugin(valaxyApp),
4568
- createUnocssPlugin(options),
4569
- localSearchPlugin(options),
4570
- scanCodeBlockTitles(options)
4627
+ ).then((r) => {
4628
+ vLogger.debug(` \u251C\u2500 plugin-vue: ${timers.vue()}`);
4629
+ return r;
4630
+ }),
4631
+ createRouterPlugin(valaxyApp).then((r) => {
4632
+ vLogger.debug(` \u251C\u2500 createRouterPlugin: ${timers.router()}`);
4633
+ return r;
4634
+ }),
4635
+ createUnocssPlugin(options).then((r) => {
4636
+ vLogger.debug(` \u251C\u2500 createUnocssPlugin: ${timers.unocss()}`);
4637
+ return r;
4638
+ }),
4639
+ localSearchPlugin(options).then((r) => {
4640
+ vLogger.debug(` \u251C\u2500 localSearchPlugin: ${timers.localSearch()}`);
4641
+ return r;
4642
+ }),
4643
+ scanCodeBlockTitles(options).then((r) => {
4644
+ vLogger.debug(` \u2514\u2500 scanCodeBlockTitles: ${timers.scanTitles()}`);
4645
+ return r;
4646
+ })
4571
4647
  ]);
4572
4648
  const componentsDirs = [...roots.map((root) => `${root}/components`), ...["src/components", "components"]];
4573
4649
  const plugins = [
@@ -4875,7 +4951,10 @@ async function ssgBuild(valaxyApp, viteConfig = {}, userSsgOptions = {}) {
4875
4951
  noExternal: ["workbox-window", /vue-i18n/, "@vue/devtools-api", ...cdnModuleNames]
4876
4952
  },
4877
4953
  build: {
4878
- sourcemap: false
4954
+ sourcemap: false,
4955
+ // Explicitly disable watch to prevent chokidar from opening too many
4956
+ // file descriptors (EMFILE) on macOS in large monorepos.
4957
+ watch: null
4879
4958
  }
4880
4959
  };
4881
4960
  const inlineConfig = mergeConfig(defaultConfig, viteConfig);
@@ -5040,7 +5119,10 @@ async function ssgBuildLegacy(valaxyApp, viteConfig = {}) {
5040
5119
  noExternal: ["workbox-window", /vue-i18n/, "@vue/devtools-api", ...cdnModuleNames]
5041
5120
  },
5042
5121
  build: {
5043
- sourcemap: false
5122
+ sourcemap: false,
5123
+ // Explicitly disable watch to prevent chokidar from opening too many
5124
+ // file descriptors (EMFILE) on macOS in large monorepos.
5125
+ watch: null
5044
5126
  }
5045
5127
  };
5046
5128
  const inlineConfig = mergeConfig(defaultConfig, viteConfig);
@@ -5149,19 +5231,19 @@ async function ssgBuildLegacy(valaxyApp, viteConfig = {}) {
5149
5231
  }
5150
5232
  await viteSsgBuild(mergedSsgOptions, inlineConfig);
5151
5233
  }
5152
- async function postProcessForSSG(options) {
5153
- const { userRoot } = options;
5154
- const indexPath = resolve$1(userRoot, "dist/index.html");
5155
- if (fs.existsSync(indexPath)) {
5156
- consola.info("post process for ssg...");
5157
- const indexFile = await fs.readFile(indexPath, "utf-8");
5158
- const htmlTag = "</html>";
5159
- if (!indexFile.endsWith(htmlTag)) {
5160
- consola.warn("fix incomplete index.html...");
5161
- const htmlTagStart = indexFile.lastIndexOf(htmlTag);
5162
- await fs.writeFile(indexPath, indexFile.slice(0, htmlTagStart + htmlTag.length), "utf-8");
5163
- }
5234
+ async function fixViteSsgHtml(options) {
5235
+ const indexPath = resolve$1(options.userRoot, "dist/index.html");
5236
+ if (!fs.existsSync(indexPath))
5237
+ return;
5238
+ const indexFile = await fs.readFile(indexPath, "utf-8");
5239
+ const htmlTag = "</html>";
5240
+ if (!indexFile.endsWith(htmlTag)) {
5241
+ consola.warn("Fixing incomplete index.html generated by vite-ssg...");
5242
+ const htmlTagStart = indexFile.lastIndexOf(htmlTag);
5243
+ await fs.writeFile(indexPath, indexFile.slice(0, htmlTagStart + htmlTag.length), "utf-8");
5164
5244
  }
5245
+ }
5246
+ async function postProcessForSSG(options) {
5165
5247
  if (!options.config.siteConfig.redirects?.useVueRouter)
5166
5248
  await generateClientRedirects(options);
5167
5249
  }
@@ -5433,8 +5515,10 @@ async function getPosts(params, options) {
5433
5515
  return false;
5434
5516
  return true;
5435
5517
  });
5436
- if (draftPosts.length)
5437
- consola.log(`[rss] Skipped ${draftPosts.length} draft post(s): ${draftPosts.join(", ")}`);
5518
+ if (draftPosts.length) {
5519
+ consola.warn(`[rss] Skipped ${colors.yellow(String(draftPosts.length))} draft post(s):
5520
+ ${draftPosts.map((p) => ` ${colors.dim("-")} ${colors.dim(p)}`).join("\n")}`);
5521
+ }
5438
5522
  const posts = [];
5439
5523
  for (const rawPost of filteredPosts) {
5440
5524
  const { data, path, content, excerpt } = rawPost;
@@ -5861,12 +5945,15 @@ function getServerInfoText(msg) {
5861
5945
  async function createServer(valaxyApp, viteConfig = {}, serverOptions = {}) {
5862
5946
  process.env.EDITOR = process.env.EDITOR || "code";
5863
5947
  const { options } = valaxyApp;
5948
+ const pluginsTimer = countPerformanceTime();
5864
5949
  const plugins = await ViteValaxyPlugins(valaxyApp, serverOptions);
5950
+ vLogger.debug(`ViteValaxyPlugins: ${pluginsTimer()}`);
5865
5951
  const enableDevtools = options.config.devtools;
5866
5952
  const vitePlugins = [
5867
5953
  ...plugins
5868
5954
  ];
5869
5955
  if (enableDevtools) {
5956
+ const devtoolsTimer = countPerformanceTime();
5870
5957
  const [vueDevtools, valaxyDevtools] = await Promise.all([
5871
5958
  import('vite-plugin-vue-devtools'),
5872
5959
  import('@valaxyjs/devtools')
@@ -5877,6 +5964,7 @@ async function createServer(valaxyApp, viteConfig = {}, serverOptions = {}) {
5877
5964
  userRoot: options.userRoot
5878
5965
  })
5879
5966
  );
5967
+ vLogger.debug(`devtools plugins: ${devtoolsTimer()}`);
5880
5968
  }
5881
5969
  const mergedViteConfig = mergeConfig(
5882
5970
  viteConfig,
@@ -5884,7 +5972,9 @@ async function createServer(valaxyApp, viteConfig = {}, serverOptions = {}) {
5884
5972
  plugins: vitePlugins
5885
5973
  }
5886
5974
  );
5975
+ const viteServerTimer = countPerformanceTime();
5887
5976
  const server = await createServer$1(mergedViteConfig);
5977
+ vLogger.debug(`createViteServer: ${viteServerTimer()}`);
5888
5978
  return server;
5889
5979
  }
5890
5980
 
@@ -5926,10 +6016,12 @@ async function initServer(valaxyApp, viteConfig) {
5926
6016
  }
5927
6017
  const { options } = valaxyApp;
5928
6018
  serverSpinner.start();
6019
+ const mergeTimer = countPerformanceTime();
5929
6020
  const viteConfigs = mergeConfig(
5930
6021
  await mergeViteConfigs(options, "serve"),
5931
6022
  viteConfig
5932
6023
  );
6024
+ vLogger.debug(`mergeViteConfigs: ${mergeTimer()}`);
5933
6025
  try {
5934
6026
  GLOBAL_STATE.server = await createServer(valaxyApp, viteConfigs, {
5935
6027
  async onConfigReload(newConfig, config, force = false) {
@@ -5945,7 +6037,9 @@ async function initServer(valaxyApp, viteConfig) {
5945
6037
  }
5946
6038
  });
5947
6039
  const server = GLOBAL_STATE.server;
6040
+ const listenTimer = countPerformanceTime();
5948
6041
  await server.listen();
6042
+ vLogger.debug(`server.listen: ${listenTimer()}`);
5949
6043
  serverSpinner.succeed(`${valaxyPrefix} ${colors.green("server ready.")}`);
5950
6044
  return server;
5951
6045
  } catch (e) {
@@ -6003,6 +6097,7 @@ async function execBuild({ ssg, ssgEngine, root, output, log }) {
6003
6097
  consola.info(`use ${colors.yellow("vite-ssg")} (legacy) to do ssg build...`);
6004
6098
  try {
6005
6099
  await ssgBuildLegacy(valaxyApp, viteConfig);
6100
+ await fixViteSsgHtml(options);
6006
6101
  await postProcessForSSG(options);
6007
6102
  } catch (e) {
6008
6103
  consola.error("[vite-ssg] An internal error occurred.");
@@ -6387,16 +6482,24 @@ async function startValaxyDev({
6387
6482
  log,
6388
6483
  open
6389
6484
  }) {
6485
+ const totalTimer = countPerformanceTime();
6390
6486
  setEnv();
6487
+ if (log === "debug")
6488
+ setLogLevel(4);
6391
6489
  if (!await isPagesDirExist(root))
6392
6490
  process.exit(0);
6393
6491
  port = port || await findFreePort(4859);
6492
+ const resolveTimer = countPerformanceTime();
6394
6493
  const resolvedOptions = await resolveOptions({ userRoot: root });
6494
+ vLogger.debug(`resolveOptions: ${resolveTimer()}`);
6395
6495
  setTimezone(resolvedOptions.config.siteConfig.timezone);
6496
+ const createNodeTimer = countPerformanceTime();
6396
6497
  const valaxyApp = createValaxyNode(resolvedOptions);
6498
+ vLogger.debug(`createValaxyNode: ${createNodeTimer()}`);
6397
6499
  GLOBAL_STATE.valaxyApp = valaxyApp;
6398
6500
  const loaders = resolvedOptions.config.loaders;
6399
6501
  if (loaders?.length) {
6502
+ const contentTimer = countPerformanceTime();
6400
6503
  const { loadAllContent } = await Promise.resolve().then(function () { return content; });
6401
6504
  const { resolve } = await import('pathe');
6402
6505
  const cacheDir = resolve(resolvedOptions.tempDir, "content");
@@ -6409,6 +6512,7 @@ async function startValaxyDev({
6409
6512
  await loadAllContent(loaders, ctx);
6410
6513
  await valaxyApp.hooks.callHook("content:loaded");
6411
6514
  await validateTaxonomyI18n(resolvedOptions);
6515
+ vLogger.debug(`content loaders: ${contentTimer()}`);
6412
6516
  for (const loader of loaders) {
6413
6517
  if (loader.devPollInterval) {
6414
6518
  const poll = async () => {
@@ -6428,7 +6532,9 @@ async function startValaxyDev({
6428
6532
  }
6429
6533
  }
6430
6534
  } else {
6535
+ const taxonomyTimer = countPerformanceTime();
6431
6536
  await validateTaxonomyI18n(resolvedOptions);
6537
+ vLogger.debug(`validateTaxonomyI18n: ${taxonomyTimer()}`);
6432
6538
  }
6433
6539
  const viteConfig = mergeConfig({
6434
6540
  // initial vite config
@@ -6448,6 +6554,7 @@ async function startValaxyDev({
6448
6554
  logLevel: log
6449
6555
  }, resolvedOptions.config.vite || {});
6450
6556
  const server = await initServer(valaxyApp, viteConfig);
6557
+ vLogger.info(`total startup: ${totalTimer()}`);
6451
6558
  printInfo(resolvedOptions, port, remote);
6452
6559
  return server;
6453
6560
  }
@@ -6471,7 +6578,7 @@ function registerDevCommand(cli) {
6471
6578
  }).option("log", {
6472
6579
  default: "info",
6473
6580
  type: "string",
6474
- choices: ["error", "warn", "info", "silent"],
6581
+ choices: ["error", "warn", "info", "debug", "silent"],
6475
6582
  describe: "log level"
6476
6583
  }).strict().help(),
6477
6584
  async ({ root, port, open, remote, log }) => {
@@ -6607,4 +6714,4 @@ function run() {
6607
6714
  cli.parse();
6608
6715
  }
6609
6716
 
6610
- export { transformObject as $, ALL_ROUTE as A, loadConfigFromFile as B, mergeValaxyConfig as C, mergeViteConfigs as D, EXCERPT_SEPARATOR as E, postProcessForSSG as F, GLOBAL_STATE as G, processValaxyOptions as H, registerDevCommand as I, resolveAddonsConfig as J, resolveImportPath as K, resolveImportUrl as L, resolveOptions as M, resolveSiteConfig as N, resolveSiteConfigFromRoot as O, PATHNAME_PROTOCOL_RE as P, resolveThemeConfigFromRoot as Q, resolveThemeValaxyConfig as R, resolveUserThemeConfig as S, resolveValaxyConfig as T, resolveValaxyConfigFromRoot as U, ViteValaxyPlugins as V, run as W, ssgBuild as X, ssgBuildLegacy as Y, startValaxyDev as Z, toAtFS as _, createServer as a, version as a0, build$1 as b, cli as c, createValaxyPlugin as d, customElements as e, defaultSiteConfig as f, defaultValaxyConfig as g, defaultViteConfig as h, defineAddon as i, defineConfig as j, defineSiteConfig as k, defineTheme as l, defineValaxyAddon as m, defineValaxyConfig as n, defineValaxyTheme as o, encryptContent as p, generateClientRedirects as q, getGitTimestamp as r, getIndexHtml as s, getServerInfoText as t, isExternal as u, isInstalledGlobally as v, isKatexEnabled as w, isKatexPluginNeeded as x, isMathJaxEnabled as y, isPath as z };
6717
+ export { toAtFS as $, ALL_ROUTE as A, isPath as B, loadConfigFromFile as C, mergeValaxyConfig as D, EXCERPT_SEPARATOR as E, mergeViteConfigs as F, GLOBAL_STATE as G, postProcessForSSG as H, processValaxyOptions as I, registerDevCommand as J, resolveAddonsConfig as K, resolveImportPath as L, resolveImportUrl as M, resolveOptions as N, resolveSiteConfig as O, PATHNAME_PROTOCOL_RE as P, resolveSiteConfigFromRoot as Q, resolveThemeConfigFromRoot as R, resolveThemeValaxyConfig as S, resolveUserThemeConfig as T, resolveValaxyConfig as U, ViteValaxyPlugins as V, resolveValaxyConfigFromRoot as W, run as X, ssgBuild as Y, ssgBuildLegacy as Z, startValaxyDev as _, createServer as a, transformObject as a0, version as a1, build$1 as b, cli as c, createValaxyPlugin as d, customElements as e, defaultSiteConfig as f, defaultValaxyConfig as g, defaultViteConfig as h, defineAddon as i, defineConfig as j, defineSiteConfig as k, defineTheme as l, defineValaxyAddon as m, defineValaxyConfig as n, defineValaxyTheme as o, encryptContent as p, fixViteSsgHtml as q, generateClientRedirects as r, getGitTimestamp as s, getIndexHtml as t, getServerInfoText as u, isExternal as v, isInstalledGlobally as w, isKatexEnabled as x, isKatexPluginNeeded as y, isMathJaxEnabled as z };
@@ -655,7 +655,7 @@ interface SiteConfig {
655
655
  * - algolia: Algolia Search
656
656
  * - engine: Engine Search, like Google/Baidu
657
657
  * - fuse: Local Search by fuse.js
658
- * - local(todo): Local Search by MiniSearch
658
+ * - local: Local Search by MiniSearch
659
659
  */
660
660
  provider: 'algolia' | 'engine' | 'fuse' | 'local';
661
661
  };
@@ -1,5 +1,5 @@
1
- import { c as Post } from '../shared/valaxy.6MW2qn5T.mjs';
2
- export { A as Album, B as BaseFrontMatter, D as DefaultTheme, E as ExcerptType, F as FuseListItem, d as Page, e as PageFrontMatter, P as PartialDeep, f as Photo, g as Pkg, h as PostFrontMatter, a as RedirectItem, i as RedirectRule, R as RuntimeConfig, S as SiteConfig, j as SocialLink, U as UserSiteConfig, k as UserValaxyConfig, b as ValaxyAddon, V as ValaxyConfig } from '../shared/valaxy.6MW2qn5T.mjs';
1
+ import { c as Post } from '../shared/valaxy.D8f6owDk.mjs';
2
+ export { A as Album, B as BaseFrontMatter, D as DefaultTheme, E as ExcerptType, F as FuseListItem, d as Page, e as PageFrontMatter, P as PartialDeep, f as Photo, g as Pkg, h as PostFrontMatter, a as RedirectItem, i as RedirectRule, R as RuntimeConfig, S as SiteConfig, j as SocialLink, U as UserSiteConfig, k as UserValaxyConfig, b as ValaxyAddon, V as ValaxyConfig } from '../shared/valaxy.D8f6owDk.mjs';
3
3
  import { Header } from '@valaxyjs/utils';
4
4
  import '@vueuse/integrations/useFuse';
5
5
  import 'medium-zoom';
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "valaxy",
3
3
  "type": "module",
4
- "version": "0.28.1",
4
+ "version": "0.28.2",
5
5
  "description": "📄 Vite & Vue powered static blog generator.",
6
6
  "author": {
7
7
  "email": "me@yunyoujun.cn",
@@ -95,7 +95,7 @@
95
95
  "jiti": "^2.6.1",
96
96
  "js-base64": "^3.7.8",
97
97
  "js-yaml": "^4.1.1",
98
- "katex": "^0.16.42",
98
+ "katex": "^0.16.44",
99
99
  "lru-cache": "^11.2.7",
100
100
  "markdown-it": "^14.1.1",
101
101
  "markdown-it-anchor": "^9.2.0",
@@ -129,18 +129,18 @@
129
129
  "unplugin-vue-components": "28.0.0",
130
130
  "unplugin-vue-markdown": "^30.0.0",
131
131
  "vanilla-lazyload": "^19.1.3",
132
- "vite": "^8.0.2",
132
+ "vite": "^8.0.3",
133
133
  "vite-plugin-vue-devtools": "^8.1.1",
134
134
  "vite-plugin-vue-layouts-next": "^2.1.0",
135
135
  "vite-ssg": "^28.3.0",
136
136
  "vite-ssg-sitemap": "^0.10.0",
137
- "vitepress-plugin-group-icons": "^1.7.1",
137
+ "vitepress-plugin-group-icons": "^1.7.3",
138
138
  "vue": "3.5.22",
139
139
  "vue-i18n": "^11.3.0",
140
140
  "vue-router": "^5.0.4",
141
141
  "yargs": "^18.0.0",
142
- "@valaxyjs/devtools": "0.28.1",
143
- "@valaxyjs/utils": "0.28.1"
142
+ "@valaxyjs/devtools": "0.28.2",
143
+ "@valaxyjs/utils": "0.28.2"
144
144
  },
145
145
  "devDependencies": {
146
146
  "@mdit-vue/plugin-component": "^3.0.2",
package/types/config.ts CHANGED
@@ -177,7 +177,7 @@ export interface SiteConfig {
177
177
  * - algolia: Algolia Search
178
178
  * - engine: Engine Search, like Google/Baidu
179
179
  * - fuse: Local Search by fuse.js
180
- * - local(todo): Local Search by MiniSearch
180
+ * - local: Local Search by MiniSearch
181
181
  */
182
182
  provider: 'algolia' | 'engine' | 'fuse' | 'local'
183
183
  }
@@ -411,9 +411,14 @@ export interface SiteConfig {
411
411
  iv: Uint8Array
412
412
  salt: Uint8Array
413
413
  /**
414
- * @description:zh-CN 全局加密密码 todo
414
+ * @description:en-US Global encryption password, read from env `VALAXY_ENCRYPT_PASSWORD`.
415
+ * When a post has `encrypt: true` in frontmatter but no `password`, this is used.
416
+ * Do NOT put passwords in config files — use `.env` or CI secrets.
417
+ * @description:zh-CN 全局加密密码,从环境变量 `VALAXY_ENCRYPT_PASSWORD` 读取。
418
+ * 当文章 frontmatter 设置了 `encrypt: true` 但未指定 `password` 时使用。
419
+ * 请勿在配置文件中设置密码——请使用 `.env` 文件或 CI secrets。
415
420
  */
416
- // password: string
421
+ // password is read from process.env.VALAXY_ENCRYPT_PASSWORD at build time
417
422
  }
418
423
 
419
424
  /**