Extend Config

TIP

扩展配置是 Valaxy 提供的高阶配置,允许你自定义更多与底层/构建相关的配置。

以下是所有的扩展配置项与相关类型。

packages/valaxy/node/types/index.ts

package/valaxy/node/types/index.ts ValaxyExtendConfig
index.ts
ts
export * from './addon'
export * from './config'
export * from './hook'
export * from './options'
config.ts
ts
import type Vue from '@vitejs/plugin-vue'

import type { Options as BeastiesOptions } from 'beasties'
import type { Hookable } from 'hookable'
import type { PluginVisualizerOptions } from 'rollup-plugin-visualizer'
import type { presetAttributify, presetIcons, presetTypography, presetWind4 } from 'unocss'
import type { VitePluginConfig as UnoCSSConfig } from 'unocss/vite'

import type Components from 'unplugin-vue-components/vite'
import type Markdown from 'unplugin-vue-markdown/vite'
import type { UserConfig as ViteUserConfig } from 'vite'
import type Layouts from 'vite-plugin-vue-layouts'
import type { groupIconVitePlugin } from 'vitepress-plugin-group-icons'
import type { EditableTreeNode } from 'vue-router/unplugin'
import type Router from 'vue-router/vite'
import type { DefaultTheme, PartialDeep, ValaxyConfig } from '../../types'
import type { createValaxyNode } from '../app'
import type { MarkdownOptions } from '../plugins/markdown/types'

import type { ValaxyAddons } from './addon'
import type { ValaxyHooks } from './hook'

import type { ResolvedValaxyOptions } from './options'

/**
 * @experimental
 * A module to load from CDN instead of bundling
 */
export interface CdnModule {
  /**
   * npm package name to externalize
   * @example 'vue'
   */
  name: string
  /**
   * Global variable name the library exposes on `window`
   * Used for mapping imports to `window[global]`
   * @example 'Vue'
   */
  global: string
  /**
   * Full CDN URL to the UMD/IIFE script
   * @example 'https://cdn.jsdelivr.net/npm/vue@3.5.0/dist/vue.global.prod.js'
   */
  url: string
  /**
   * Optional CSS URL if the module requires stylesheet
   * @example 'https://cdn.jsdelivr.net/npm/katex@0.16.0/dist/katex.min.css'
   */
  css?: string
  /**
   * Named exports to re-export from the global variable.
   * Required for libraries that use named exports (e.g., `import { ref } from 'vue'`).
   * @example ['ref', 'computed', 'watch', 'createApp']
   */
  exports?: string[]
}

export type ValaxyNodeConfig<ThemeConfig = DefaultTheme.Config> = ValaxyConfig<ThemeConfig> & ValaxyExtendConfig
export type UserValaxyNodeConfig<ThemeConfig = DefaultTheme.Config> = PartialDeep<ValaxyNodeConfig<ThemeConfig>>
/**
 * fn with options for theme config
 */
export type ValaxyConfigFn<ThemeConfig = DefaultTheme.Config> = (options: ResolvedValaxyOptions<ThemeConfig>) => ValaxyNodeConfig | Promise<ValaxyNodeConfig>
export type ValaxyConfigExport<ThemeConfig = DefaultTheme.Config> = ValaxyNodeConfig<ThemeConfig> | ValaxyConfigFn<ThemeConfig>

export interface ValaxyNode {
  version: string

  hooks: Hookable<ValaxyHooks>
  hook: ValaxyNode['hooks']['hook']

  options: ResolvedValaxyOptions
}

export interface ValaxyExtendConfig {
  /**
   * Don't fail builds due to dead links.
   *
   * @default false
   * @deprecated use `build.ignoreDeadLinks` instead
   */
  ignoreDeadLinks?:
    | boolean
    | 'localhostLinks'
    | (string | RegExp | ((link: string) => boolean))[]

  /**
   * options for `valaxy build`
   */
  build: {
    /**
     * Don't fail builds due to dead links.
     * @zh 忽略死链
     * @default false
     */
    ignoreDeadLinks?:
      | boolean
      | 'localhostLinks'
      | (string | RegExp | ((link: string) => boolean))[]
    /**
     * Enable SSG for pagination
     * @en When enabled, it will generate pagination pages for you. `/page/1`, `/page/2`, ...
     * @zh 启用 SSG 分页,将单独构建分页页面 `/page/1`, `/page/2`, ...
     * @default false
     */
    ssgForPagination: boolean
  }

  /**
   * @experimental
   * Deploy to gh-pages/remote server
   */
  deploy: {
    /**
     * @zh 部署类型
     * @en deploy type
     */
    type?: 'gh-pages' | 'remote'
  }

  /**
   * internal modules
   */
  modules: {
    rss: {
      /**
       * enable rss
       */
      enable: boolean
      /**
       * @zh 全文输出
       * @en full text output
       * @default false
       */
      fullText: boolean
      /**
       * @zh 从构建后的 HTML 中提取图片路径(用于解析 Vite 打包后的 hash 文件名)
       * @en Extract image paths from built HTML files (to resolve Vite hashed filenames)
       * @default true
       */
      extractImagePathsFromHTML: boolean
    }
  }

  /**
   * Markdown Feature
   */
  features: {
    /**
     * enable katex for global
     * @see [Example | Valaxy](https://valaxy.site/examples/katex)
     * @see https://katex.org/
     * @default true
     */
    katex: boolean
  }
  /**
   * vite.config.ts options
   * @see https://vite.dev/
   */
  vite?: ViteUserConfig
  /**
   * @vitejs/plugin-vue options
   * @see https://github.com/vitejs/vite-plugin-vue/blob/main/packages/plugin-vue/README.md
   */
  vue?: Parameters<typeof Vue>[0] & {
    /**
     * @valaxy
     */
    isCustomElement?: ((tag: string) => boolean)[]
    /**
     * @valaxy
     * @see https://cn.vuejs.org/guide/scaling-up/tooling#note-on-in-browser-template-compilation
     * enable
     *
     * for runtime compile vue, encrypt and decrypt
     * for excerpt_type: html (runtime render)
     *
     * @default true
     *
     * browserTemplateCompilation
     * @description 支持浏览器内的模板编译
     */
    browserTemplateCompilation?: boolean
  }
  /**
   * @see https://github.com/unplugin/unplugin-vue-components
   *
   * exclude @default components/.exclude
   */
  components?: Parameters<typeof Components>[0]
  /**
   * @see https://github.com/JohnCampionJr/vite-plugin-vue-layouts
   */
  layouts?: Parameters<typeof Layouts>[0]
  /**
   * @see https://github.com/posva/unplugin-vue-router
   */
  router?: Parameters<typeof Router>[0]
  /**
   * @see https://unocss.dev/config/
   */
  unocss?: UnoCSSConfig
  /**
   * rollup-plugin-visualizer
   * @see https://github.com/btd/rollup-plugin-visualizer
   */
  visualizer?: PluginVisualizerOptions
  /**
   * @see https://github.com/yuyinws/vitepress-plugin-group-icons
   */
  groupIcons?: Partial<NonNullable<Parameters<typeof groupIconVitePlugin>[0]>>
  /**
   * unocss presets
   * @see https://unocss.dev/guide/presets
   */
  unocssPresets?: {
    /**
     * @deprecated use wind4 instead
     */
    uno?: Parameters<typeof presetWind4>[0]
    attributify?: Parameters<typeof presetAttributify>[0]
    icons?: Parameters<typeof presetIcons>[0]
    typography?: Parameters<typeof presetTypography>[0]
    wind4?: Parameters<typeof presetWind4>[0]
  }
  fuse?: {
    /**
     * @en_US Extends the metadata fields returned by the search
     * @zh_CN 扩展搜索返回的元数据字段
     * @default []
     * @description:en-US By default, returns the following fields: title, tags, categories, author, excerpt, link
     * @description:zh-CN 默认返回以下字段:title、tags、categories、author、excerpt、link
     */
    extendKeys?: string[]
  }
  /**
   * @experimental
   * Enable Vue Devtools & Valaxy Devtools
   * @see https://devtools-next.vuejs.org/
   */
  devtools?: boolean
  /**
   * @en config for markdown (include markdown-it plugins)
   * @zh markdown 相关配置
   * {@link MarkdownOptions}
   */
  markdown?: MarkdownOptions & Parameters<typeof Markdown>[0]
  /**
   * @en Extend markdown, you can modify the markdown content/excerpt
   * @zh 扩展 markdown
   */
  extendMd?: (ctx: {
    route: EditableTreeNode
    data: Readonly<Record<string, any>>
    content: string
    excerpt?: string
    path: string
  }) => void
  /**
   * @en Addons system
   * @zh 插件系统
   * @see 为什么需要插件? [Why Addon? | Valaxy](https://valaxy.site/addons/why)
   * @see 插件橱窗 [Addons Gallery | Valaxy](https://valaxy.site/addons/gallery)
   * @example
   * ```ts
   * import { defineValaxyConfig } from 'valaxy'
   * import { addonTest } from 'valaxy-addon-test'
   *
   * export default defineValaxyConfig({
   *   addons: [
   *     // we always recommend to use function, so that you can pass options
   *     addonTest(),
   *   ]
   * })
   * ```
   */
  addons?: ValaxyAddons

  /**
   * @en Hooks system, you can customize each stage of the lifecycle.
   * @zh 钩子系统,你可以对生命周期的各个阶段进行定制。
   * @see https://valaxy.site/guide/custom/hooks
   */
  hooks?: Partial<ValaxyHooks>

  /**
   * beastiesOptions
   * @see https://github.com/danielroe/beasties
   */
  beastiesOptions?: BeastiesOptions

  /**
   * @experimental
   * CDN externals configuration.
   * Specify modules to load from CDN instead of bundling them.
   * Only takes effect during `valaxy build`, not in dev mode.
   * @see https://github.com/YunYouJun/valaxy/issues/604
   */
  cdn?: {
    /**
     * Modules to load from CDN instead of bundling
     * @default []
     */
    modules?: CdnModule[]
  }
}

export type ValaxyApp = ReturnType<typeof createValaxyNode>

所以,你可以像这样使用:

So you can use it like this:

valaxy.config.ts
ts
import type { ThemeConfig } from 'valaxy-theme-yun'
import { defineValaxyConfig } from 'valaxy'
import { addonComponents } from 'valaxy-addon-components'
import { VitePWA } from 'vite-plugin-pwa'

const safelist = [
  'i-ri-home-line',
]

export default defineValaxyConfig<ThemeConfig>({
  // site config see site.config.ts or write in siteConfig
  siteConfig: {},

  theme: 'yun',
  themeConfig: {
    banner: {
      enable: true,
      title: '云游君的小站',
    },
  },

  vite: {
    // https://vite-pwa-org.netlify.app/
    plugins: [VitePWA()],
  },

  unocss: {
    safelist,
  },

  addons: [
    addonComponents()
  ],
})

@vitejs/plugin-vue

Valaxy 默认集成了 @vitejs/plugin-vue 插件,你可以通过 vue 配置项进行配置。

valaxy.config.ts
ts
import { defineValaxyConfig } from 'valaxy'

export default defineValaxyConfig({
  vue: {
    template: {
      compilerOptions: {
        isCustomElement: tag => tag.startsWith('my-')
      }
    }
  }
})

Vite

你可以参见 Vite 文档 自定义 Vite 相关配置。

valaxy.config.ts
ts
import { defineValaxyConfig } from 'valaxy'

export default defineValaxyConfig({
  vite: {
    plugins: []
  }
})

Markdown

可自定义 Markdown 相关配置,如代码主题、区块内容、添加 markdown-it 插件、transformer 等。

效果参见: Markdown

valaxy/node/plugins/markdown/types.ts
types.ts
ts
import type {
  HeadersPluginOptions,
} from '@mdit-vue/plugin-headers'

import type { SfcPluginOptions } from '@mdit-vue/plugin-sfc'
import type { TocPluginOptions } from '@mdit-vue/plugin-toc'
import type { KatexOptions } from 'katex'

import type MarkdownIt from 'markdown-it'
import type anchorPlugin from 'markdown-it-anchor'

import type { MarkdownItAsync, Options } from 'markdown-it-async'
import type {
  BuiltinTheme,
  Highlighter,
  LanguageInput,
  ShikiTransformer,
  ThemeRegistration,
} from 'shiki'

// import type { lazyloadOptions } from './plugins/markdown-it/lazyload'

import type { PageData } from '../../../types'
import type { BlockItem, Blocks, ContainerOptions } from './plugins/markdown-it/container'

export type ThemeOptions
  = | ThemeRegistration
    | BuiltinTheme
    | {
      light: ThemeRegistration | BuiltinTheme
      dark: ThemeRegistration | BuiltinTheme
    }

/**
 * Extend Markdown options
 * @zh 扩展 Markdown 配置,包含代码高亮、Markdown-it 和插件配置
 */
export interface MarkdownOptions extends Options {
  /**
   * Setup markdown-it instance before applying plugins
   */
  preConfig?: (md: MarkdownItAsync) => void
  /**
   * markdown-it options
   */
  options?: MarkdownIt['options']
  /**
   * config markdown-it
   */
  config?: (md: MarkdownItAsync) => void
  anchor?: anchorPlugin.AnchorOptions
  attrs?: {
    leftDelimiter?: string
    rightDelimiter?: string
    allowedAttributes?: string[]
    disable?: boolean
  }
  /* ==================== Syntax Highlighting ==================== */

  /**
   * Custom theme for syntax highlighting.
   *
   * You can also pass an object with `light` and `dark` themes to support dual themes.
   *
   * @see You can use an existing theme. https://shiki.style/themes
   * @see Or add your own theme. https://shiki.style/guide/load-theme
   *
   * @example { theme: 'github-dark' }
   * @example light and dark themes
   * ```js
   * { theme: { light: 'github-light', dark: 'github-dark' } }
   * ```
   */
  theme?: ThemeOptions
  /**
   * Languages for syntax highlighting.
   * @see https://shiki.style/languages
   */
  languages?: LanguageInput[]
  /**
   * Custom language aliases.
   *
   * @example { 'my-lang': 'js' }
   * @see https://shiki.style/guide/load-lang#custom-language-aliases
   */
  languageAlias?: Record<string, string>
  /**
   * Show line numbers in code blocks
   * @default false
   */
  lineNumbers?: boolean
  /**
   * Fallback language when the specified language is not available.
   */
  defaultHighlightLang?: string
  /**
   * Transformers applied to code blocks
   * @see https://shiki.style/guide/transformers
   */
  codeTransformers?: ShikiTransformer[]
  /**
   * Setup Shiki instance
   */
  shikiSetup?: (shiki: Highlighter) => void | Promise<void>

  /* ==================== Markdown It Plugins ==================== */
  // mdit-vue plugins
  /**
   * Options for `@mdit-vue/plugin-headers`
   * @see https://github.com/mdit-vue/mdit-vue/tree/main/packages/plugin-headers
   */
  headers?: HeadersPluginOptions | boolean
  /**
   * Options for `@mdit-vue/plugin-sfc`
   * @see https://github.com/mdit-vue/mdit-vue/tree/main/packages/plugin-sfc
   */
  sfc?: SfcPluginOptions
  /**
   * Options for `@mdit-vue/plugin-toc`
   * @see https://github.com/mdit-vue/mdit-vue/tree/main/packages/plugin-toc
   */
  toc?: TocPluginOptions
  /**
   * Options for `markdown-it-container`
   * @see https://github.com/markdown-it/markdown-it-container
   */
  container?: ContainerOptions
  /**
   * Custom block configurations based on `markdown-it-container`
   */
  blocks?: Record<string, BlockItem> | Blocks

  /**
   * @see [markdown-it-image-figures](https://www.npmjs.com/package/markdown-it-image-figures)
   */
  imageFigures?: {
    lazy: boolean
    removeSrc: boolean
    async: boolean
    classes: string
  }

  /**
   * @see https://katex.org/docs/options.html
   */
  katex?: KatexOptions

  externalLinks?: Record<string, string>
  /* lazyload?: {
    enabled?: boolean
    options: lazyloadOptions
  } */
}

export interface MarkdownCompileResult {
  vueSrc: string
  pageData: PageData
  deadLinks: { url: string, file: string }[]
  includes: string[]
}
valaxy.config.ts
ts
import { defineValaxyConfig } from 'valaxy'

export default defineValaxyConfig({
  markdown: {
    // default material-theme-palenight
    // theme: 'material-theme-palenight',
    theme: {
      // light: 'material-theme-lighter',
      light: 'github-light',
      // dark: 'material-theme-darker',
      dark: 'github-dark',
    },

    blocks: {
      tip: {
        icon: 'i-carbon-thumbs-up',
        text: 'ヒント',
        langs: {
          'zh-CN': '提示',
        },
      },
      warning: {
        icon: 'i-carbon-warning-alt',
        text: '注意',
      },
      danger: {
        icon: 'i-carbon-warning',
        text: '警告',
      },
      info: {
        text: 'información',
      },
    },

    codeTransformers: [
      // We use `[!code` in demo to prevent transformation, here we revert it back.
      {
        postprocess(code) {
          return code.replace(/\[!!code/g, '[!code')
        },
      },
    ],

    config(md) {
      // md.use(xxx)
    }
  },
})

DevTools

设置 devtools: false 以关闭 DevTools。

插件 addons

参见 使用插件

UnoCSS

参见 UnoCSS

Modules

RSS

Valaxy 内置了 RSS 模块,你可以在 valaxy.config.ts 中通过 modules.rss 配置项进行配置。

  • enable: 是否启用 RSS 模块。默认 true,启用。
  • fullText: 是否输出文章全文。默认 false,只输出摘要。
  • extractImagePathsFromHTML: 是否从构建后的 HTML 中提取图片路径(用于解析 Vite 打包后的 hash 文件名)。默认 true,启用。

Valaxy has a built-in RSS module, which can be configured in valaxy.config.ts through the modules.rss configuration item.

  • enable: Whether to enable the RSS module. Default is true, enabled.
  • fullText: Whether to output the full text of the article. Default is false, only the summary is output.
  • extractImagePathsFromHTML: Whether to extract image paths from built HTML files (to resolve Vite hashed filenames). Default is true, enabled.
valaxy.config.ts
ts
export default defineValaxyConfig({
  modules: {
    rss: {
      enable: true,
      fullText: false,
      // 当设置为 true 时,会从构建后的 HTML 中提取图片的实际路径(包含 hash)
      // When set to true, it will extract actual image paths (with hash) from built HTML
      extractImagePathsFromHTML: true,
    },
  },
})

关于 extractImagePathsFromHTML

当你在 Markdown 中使用相对路径引用图片时(如 ![pic](test.webp)),Vite 会将图片打包并生成带 hash 的文件名(如 /assets/test.zBFFFKJX.webp)。

  • 启用此选项(默认):RSS feed 中的图片 URL 将使用构建后的实际路径,如 https://example.com/assets/test.zBFFFKJX.webp
  • 禁用此选项:RSS feed 中的图片 URL 将基于文章目录构建,如 https://example.com/posts/article-name/test.webp

大多数情况下,你应该保持此选项为 true,以确保 RSS 阅读器能正确加载图片。

About extractImagePathsFromHTML

When you reference images with relative paths in Markdown (e.g., ![pic](test.webp)), Vite will bundle the image and generate a hashed filename (e.g., /assets/test.zBFFFKJX.webp).

  • When enabled (default): Image URLs in RSS feed will use the actual built paths, like https://example.com/assets/test.zBFFFKJX.webp
  • When disabled: Image URLs in RSS feed will be constructed based on the post directory, like https://example.com/posts/article-name/test.webp

In most cases, you should keep this option as true to ensure RSS readers can load images correctly.

CDN Externals

CDN 外部化

实验性功能

通过 cdn.modules 配置项,你可以指定某些 npm 包在构建时从 CDN 加载,而非打包到最终产物中。 这可以显著减小构建产物体积,并利用 CDN 加速资源加载。

该配置仅在 valaxy build 时生效,开发模式下不受影响。

Experimental

With the cdn.modules option, you can specify certain npm packages to be loaded from CDN at runtime instead of being bundled. This can significantly reduce bundle size and leverage CDN for faster resource loading.

This option only takes effect during valaxy build, not in dev mode.

TIP

cdn.modules 中的每个模块需要提供以下字段:

  • name: npm 包名(如 'katex'
  • global: 该库在 window 上暴露的全局变量名(如 'katex'
  • url: CDN 脚本的完整 URL
  • css(可选): CDN 样式表的完整 URL
  • exports(可选): 需要重新导出的命名导出列表(如 ['ref', 'computed']

Each module in cdn.modules requires the following fields:

  • name: npm package name (e.g., 'katex')
  • global: global variable name the library exposes on window (e.g., 'katex')
  • url: full CDN URL to the UMD/IIFE script
  • css (optional): full CDN URL to the stylesheet
  • exports (optional): named exports to re-export from the global variable (e.g., ['ref', 'computed'])

:::

示例:通过 CDN 加载 KaTeX

KaTeX 默认会被打包进构建产物。如果你希望通过 CDN 加载 KaTeX 以减小打包体积,可以如下配置:

Example: Load KaTeX from CDN

KaTeX is bundled into the build output by default. If you want to load it from CDN to reduce bundle size, you can configure it as follows:

valaxy.config.ts
ts
import { defineValaxyConfig } from 'valaxy'

export default defineValaxyConfig({
  cdn: {
    modules: [
      {
        name: 'katex',
        global: 'katex',
        url: 'https://cdn.jsdelivr.net/npm/katex@0.16.21/dist/katex.min.js',
        css: 'https://cdn.jsdelivr.net/npm/katex@0.16.21/dist/katex.min.css',
      },
    ],
  },
})

你也可以使用其他 CDN 源,只需替换 URL 即可。例如使用 unpkg:

You can also use other CDN providers by replacing the URL. For example, using unpkg:

valaxy.config.ts
ts
import { defineValaxyConfig } from 'valaxy'

export default defineValaxyConfig({
  cdn: {
    modules: [
      {
        name: 'katex',
        global: 'katex',
        url: 'https://unpkg.com/katex@0.16.21/dist/katex.min.js',
        css: 'https://unpkg.com/katex@0.16.21/dist/katex.min.css',
      },
    ],
  },
})

Contributors