Advanced Configuration

Learn how to configure advanced settings for the Solitude theme.

Word Count

# --------------------------- start ---------------------------
# Word count
# 字数统计
# warning: Please install the hexo-wordcount plugin first.
# 警告: 请先安装 hexo-wordcount 插件。
wordcount: false
# --------------------------- end ---------------------------

Install the hexo-wordcount plugin

npm
pnpm
bun
yarn
npm i hexo-wordcount

Math Formulas

# --------------------------- start ---------------------------
# Katex
# Latex formula support
# Latex 公式支持
katex:
  enable: false
  # Whether to load on each page
  # 是否在每个页面加载
  per_page: false
  # Whether to enable copy formula
  # 是否启用复制公式
  copytex: false
# --------------------------- end ---------------------------

Uninstall hexo-render-marked

npm un hexo-renderer-marked

Install hexo-renderer-markdown-it katex and @renbaoshuo/markdown-it-katex

npm
pnpm
bun
yarn
npm i hexo-renderer-markdown-it katex @renbaoshuo/markdown-it-katex

Add the following content to _config.yml

_config.yml
markdown:
  preset: 'default'
  render:
    html: true
    xhtmlOut: false
    langPrefix: 'language-'
    breaks: true
    linkify: true
    typographer: true
    quotes: '“”‘’'
  enable_rules:
  disable_rules:
  plugins:
    - '@renbaoshuo/markdown-it-katex'
  anchors:
    level: 2
    collisionSuffix: ''
    permalink: false
    permalinkClass: 'header-anchor'
    permalinkSide: 'left'
    permalinkSymbol: '¶'
    case: 0
    separator: '-'
  images:
    lazyload: false
    prepend_root: false
    post_asset: false
  inline: false  # https://markdown-it.github.io/markdown-it/#MarkdownIt.renderInline

Enable the configuration item

# --------------------------- start ---------------------------
# Katex
# Latex formula support
# Latex 公式支持
katex:
  enable: true
  # Whether to load on each page
  # 是否在每个页面加载
  per_page: true
  # Whether to enable copy formula
  # 是否启用复制公式
  copytex: false
# --------------------------- end ---------------------------

Website verification

# --------------------------- start ---------------------------
# verification
# 验证
verify_site:
  # - name: google-site-verification
  #   content: xxxxxx
  # - name: baidu-site-verification
  #   content: xxxxxxx
# --------------------------- end ---------------------------

Add verification codes for each platform

CSS Prefix

# --------------------------- start ---------------------------
# CSS Prefix
# CSS 前缀
# When turned on, it will automatically prefix the CSS (to get better browser support), but this will increase the size of the CSS file.
# 开启后会自动给 CSS 加前缀(以获得更好的浏览器支持),但这会增加 CSS 文件的大小。
css_prefix: false
# --------------------------- end ---------------------------

Extend

# --------------------------- start ---------------------------
# Extend
# 扩展
extends:
  # Insert in head
  # 插入到 head
  head:
  #  - <script src="https://cdn.bootcdn.net/ajax/libs/pace/1.2.4/pace.min.js"></script>

  # Insert in body
  # 插入到 body
  body:
  #  - <script src="https://cdn.bootcdn.net/ajax/libs/pace/1.2.4/pace.min.js"></script>
# --------------------------- end ---------------------------

可以插入自定义的网站文件

PWA

PWA is a means of web optimization. The theme has been adapted to some extent, but configuration is still required. The configuration tutorial is as follows:

Install hexo-swpp and swpp-backends plugins

Execute in the blog root directory:

npm
pnpm
bun
yarn
npm i hexo-swpp 
npm
pnpm
bun
yarn
npm i swpp-backends

Configure PWA

Enable the pwa option in the theme configuration file.

# 大约在773行
# --------------------------- start ---------------------------
# PWA
# Progressive Web App
pwa:
  enable: true
  manifest: /manifest.json # manifest.json
  theme_color: "#006a73" # Theme color
  mask_icon: /img/pwa/favicon.png # Mask icon
  apple_touch_icon: /img/pwa/favicon.png # Apple touch icon
  bookmark_icon: /img/pwa/favicon.png # Bookmark icon
  favicon_32_32: /img/pwa/favicon_32.png # 32x32 icon
  favicon_16_16: /img/pwa/favicon_16.png # 16x16 icon
# --------------------------- end ---------------------------

Create a manifest.json file in the source directory

{
    "name": "网站名称",
    "short_name": "网站名称缩写",
    "theme_color": "#006a73",
    "background_color": "#006a73",
    "display": "fullscreen",
    "scope": "/",
    "start_url": "/",
    "id": "/",
    "icons": [
      {
        "src": "/img/pwa/favicon_16.png",
        "sizes": "16x16",
        "type": "image/png",
        "purpose": "any"
      },
      {
        "src": "/img/pwa/favicon_16.png",
        "sizes": "16x16",
        "type": "image/png",
        "purpose": "maskable"
      },
      {
        "src": "/img/pwa/favicon_32.png",
        "sizes": "32x32",
        "type": "image/png",
        "purpose": "any"
      },
      {
        "src": "/img/pwa/favicon_32.png",
        "sizes": "32x32",
        "type": "image/png",
        "purpose": "maskable"
      },
      {
        "src": "/img/pwa/favicon.png",
        "sizes": "180x180",
        "type": "image/png",
        "purpose": "any"
      },
      {
        "src": "/img/pwa/favicon.png",
        "sizes": "180x180",
        "type": "image/png",
        "purpose": "maskable"
      }
    ],
    "splash_pages": null
}

Create a sw-rules.js file in the blog root directory

module.exports.config = {
  /** @type {?ServiceWorkerConfig|boolean} */
  serviceWorker: {
    escape: 1,
    cacheName: 'SolitudeCache',
    debug: false,
  },
  register: {
    onsuccess: undefined,
    onerror: () =>
      console.error(
        'Service Worker 注册失败!可能是由于您的浏览器不支持该功能!'
      ),
    builder: (root, framework, pluginConfig) => {
      const { onerror, onsuccess } = pluginConfig.register;
      return `
            <script>
                (() => {
                    const sw = navigator.serviceWorker;
                    const error = ${onerror && onerror.toString()};
                    if (!sw?.register('${new URL(root).pathname}sw.js')
                        ${onsuccess ? `?.then(${onsuccess.toString()})` : ""}
                        ?.catch(error)
                    ) error()
                })()
            </script>`;
    },
  },
  /** @type {?DomConfig|boolean} */
  dom: {
    /** @type {?VoidFunction} */
    onsuccess: () => {
      caches
        .match('https://id.v3/')
        .then((res) => {
          if (res)
            res.json().then((json) => {
              utils &&
                utils.snackbarShow(
                  `已刷新缓存,更新为${json.escape + '.' + json.global + '.' + json.local
                  }版本最新内容`,
                  false,
                  2500
                );
            });
          else console.info('未找到缓存');
        })
        .catch((error) => console.error('缓存匹配出错', error));
    },
  },
  /** @type {?VersionJsonConfig|boolean} */
  json: {
    /** @type {number} */
    maxHtml: 15,
    /** @type {number} */
    charLimit: 1024,
    /** @type {string[]} */
    merge: [],
    exclude: {
      /** @type {RegExp[]} */
      localhost: [],
      /** @type {RegExp[]} */
      other: [],
    },
  },
  /** @type {?ExternalMonitorConfig|boolean} */
  external: {
    /** @type {number} */
    timeout: 5000,
    /** 拉取文件时地并发限制 */
    concurrencyLimit: 100,
    /** @type {({head: string, tail: string}|function(string):string[])[]} */
    js: [],
    /** @type {RegExp[]} */
    stable: [
      /^https:\/\/npm\.elemecdn\.com\/[^/@]+\@[^/@]+\/[^/]+\/[^/]+$/,
      /^https:\/\/cdn\.cbd\.int\/[^/@]+\@[^/@]+\/[^/]+\/[^/]+$/,
      /^https:\/\/cdn\.jsdelivr\.net\/npm\/[^/@]+\@[^/@]+\/[^/]+\/[^/]+$/,
    ],
    replacer: (srcUrl) => {
      if (srcUrl.startsWith('https://cdn.jsdelivr.net/npm/')) {
        const pathname = new URL(srcUrl).pathname;
        return [
          srcUrl,
          `https://cdn.cbd.int/${pathname}`,
          `https://npm.elemecdn.com/${pathname}`,
          `https://fastly.jsdelivr.net/npm/${pathname}`,
        ];
      } else {
        return srcUrl;
      }
    },
  },
};

module.exports.cacheRules = {
  simple: {
    clean: true,
    search: false,
    match: (url, $eject) =>
      url.host === $eject.domain && ['/404.html'].includes(url.pathname),
  },
  cdn: {
    clean: true,
    match: (url) =>
      [
        'cdn.cbd.int',
        'lf26-cdn-tos.bytecdntp.com',
        'lf6-cdn-tos.bytecdntp.com',
        'lf3-cdn-tos.bytecdntp.com',
        'lf9-cdn-tos.bytecdntp.com',
        'cdn.staticfile.org',
        'npm.elemecdn.com',
      ].includes(url.host) &&
      url.pathname.match(/\.(js|css|woff2|woff|ttf|cur)$/),
  },
};

module.exports.getSpareUrls = (srcUrl) => {
  if (srcUrl.startsWith('https://npm.elemecdn.com')) {
    return {
      timeout: 3000,
      list: [
        srcUrl,
        `https://fastly.jsdelivr.net/${new URL(srcUrl).pathname}`,
      ],
    };
  }
};

module.exports.ejectValues = (hexo, rules) => {
  return {
    domain: {
      prefix: 'const',
      value: new URL(hexo.config.url).host,
    },
  };
};

module.exports.skipRequest = (request) => request.url.startsWith("https://i0.hdslb.com") ||
  request.url.startsWith('https://meting.qjqq.cn') ||
  request.url.startsWith('https://api.i-meto.com');

CDN

# --------------------------- start ---------------------------
# 非必要请勿修改
CDN:
  internal: local # local / cdnjs / jsdelivr / unpkg / custom
  third_party: custom # cdnjs / jsdelivr / unpkg / custom
  version: true # 是否使用版本号
  custom_format: https://fastly.jsdelivr.net/npm/${name}@${version}/${min_file} # 自定义格式
  # 直接覆盖默认 CDN 链接(优先级最高)
  options:
    # algolia_search:
    # aplayer_css:
    # aplayer_js:
    # artalk_css:
    # artalk_js:
    # blueimp_md5:
    # busuanzi_js:
    # chart_js:
    # color_thief:
    # fancyapps_css:
    # fancyapps_ui:
    # fontawesome:
    # instantsearch:
    # katex:
    # katex_copytex:
    # lazyload:
    # medium_zoom:
    # mermaid_js:
    # meting_js:
    # pace_js:
    # pjax:
    # qrcode:
    # snackbar:
    # swiper_css:
    # swiper_js:
    # twikoo:
    # typeit_js:
    # valine:
    # waline_css:
    # waline_js:
# --------------------------- end ---------------------------