#### # 前言

该篇文章介绍了如何对 shoka 主题进行 jsdelivr 聚合拆分，以便使用国内镜像源和异步加载，从而优化网站速度。具体操作包括更改模板、注册 helper 和更改配置。其中，推荐使用 advVendors 配置，可自定义加载源和 js 文件名，同时支持异步加载、pjax 刷新和 integrity 防 XXS 等特性。

众所周知，jsdelivr 在国内的速度可以用慢的一批来形容而 shoka 主题使用了 jsdelivr 的 combine 功能加载第三方 js, 而 combine 在国内没有镜像源并且阻断了使用 CDN 并发加速的道路，本篇博文会将 jsdelivr 聚合拆分为几个独立的 js, 以便使用国内镜像源和异步加载。

此方案相较于本地化而言有较大速度优势，尤其在 CDN 并发加持下

#### # 拆分 jsdelivr

1. 更改模板

打开 shoka\layout\_partials\layout.njk，找到第 144 行左右:

    1
    2
    3
    4

    <script src="https://cdn.polyfill.io/v3/polyfill.js"></script>
    &#123;&#123; _vendor_js() &#125;&#125;
    &#123;&#123; _js('app.js') &#125;&#125;
    &#123;&#123; partial('_partials/third-party/baidu-analytics.njk', &#123;&#125;, &#123;cache: true&#125;) &#125;&#125;

更改为如下内容:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10

    <script src="https://cdn.polyfill.io/v3/polyfill.js"></script>
    &#123;%- if theme.advVendors.enable %&#125;
    	&#123;% for i in _list_vendor_js() %&#125;
    		&#123;&#123; _adv_vendor_js(i) &#125;&#125;
    	&#123;% endfor %&#125;
    &#123;%- else %&#125;
    &#123;&#123; _vendor_js() &#125;&#125;
    &#123;%- endif %&#125;
    &#123;&#123; _js('app.js')&#125;&#125;
    &#123;&#123; partial('_partials/third-party/baidu-analytics.njk', &#123;&#125;, &#123;cache: true&#125;) &#125;&#125;

2. 注册 helper

打开 shoka\scripts\helpers\asset.js, 最后一行新建空行，增加如下内容:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31

    hexo.extend.helper.register('_list_vendor_js', () => {
        return hexo.theme.config.vendorsList.js;
    });

    hexo.extend.helper.register('_adv_vendor_js', function (js_name) {
        const config = hexo.theme.config.advVendors.js[js_name];
        const src = config["src"];
        let result;
        if (src.indexOf("http") !== -1) {
            result = src;
        } else if (src.indexOf("combine") !== -1) {
            console.log("The combine feature is not recommended!")
            result = hexo.theme.config.advVendors.combine + src;
        } else if (src.indexOf("npm") !== -1) {
            result = hexo.theme.config.advVendors.npm + src.slice(4);
        } else if (src.indexOf("gh") !== -1) {
            result = hexo.theme.config.advVendors.github + src.slice(3);
        } else {
            result = "/" + src;
        }
        let attr = {src: result};
        if (config["async"]) attr["async"] = "async";
        if (config["data-pjax"]) attr["data-pjax"] = "data-pjax";
        if (config["hash-value"]) attr["integrity"]=config["hash-value"];
        if (config["deferLoad"]) {
            return htmlTag('script', {"data-pjax": true}, `
            const script=document.createElement("script");script.src="${result}",script.async=true,document.body.appendChild(script)
            `)
        }
        return htmlTag('script', attr, '');
    })

3. 更改配置

在 shoka 目录下 _config.yml 增加如下内容:

推荐内容，可根据自己情况更改

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47

    advVendors:
      enable: true
      github: "https://cdn.jsdelivr.net/gh/"
      combine: "https://cdn.jsdelivr.net/"
      npm: "https://unpkg.com/"
      js:
        pace:
          src: https://lf9-cdn-tos.bytecdntp.com/cdn/expire-1-M/pace/1.0.2/pace.min.js
        pjax:
          src: https://lib.baomitu.com/pjax/0.2.8/pjax.min.js
        fetch:
          src: npm/whatwg-fetch@3.4.0/dist/fetch.umd.js
        anime:
          src: https://lf9-cdn-tos.bytecdntp.com/cdn/expire-1-M/animejs/3.2.0/anime.min.js
        algolia:
          src: https://lf9-cdn-tos.bytecdntp.com/cdn/expire-1-M/algoliasearch/4.12.1/algoliasearch-lite.umd.min.js
        instantsearch:
          src: https://lf9-cdn-tos.bytecdntp.com/cdn/expire-1-M/instantsearch.js/4.39.0/instantsearch.production.min.js
        lazyload:
          src: https://lf9-cdn-tos.bytecdntp.com/cdn/expire-1-M/lozad.js/1.16.0/lozad.min.js
        quicklink:
          src: https://lf9-cdn-tos.bytecdntp.com/cdn/expire-1-M/quicklink/2.2.0/quicklink.umd.min.js
        fancybox:
          src: https://lf26-cdn-tos.bytecdntp.com/cdn/expire-1-M/??jquery/3.5.1/jquery.min.js,fancybox/3.5.7/jquery.fancybox.min.js,justifiedGallery/3.8.1/js/jquery.justifiedGallery.min.js
          async: true
        valine:
          src: gh/amehime/MiniValine@4.2.2-beta10/dist/MiniValine.min.js
        copy_tex:
          src: https://lf9-cdn-tos.bytecdntp.com/cdn/expire-1-M/KaTeX/0.12.0/contrib/copy-tex.min.js
          async: true
        chart:
          src: npm/frappe-charts@1.5.0/dist/frappe-charts.min.iife.js

    vendorsList:
      js:
        - pace
        - pjax
        - fetch
        - anime
        - algolia
        - instantsearch
        - lazyload
        - quicklink
        - fancybox
        - valine
        - copy_tex
        - chart

下面为结构详解:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16

    advVendors:
    	enable: true #是否开启，关闭使用主题默认加载
    	github: #github 使用的加载源，需要协议头和末尾斜杠
    	combine: #聚合 js 使用的加载源 (不建议使用)
    	npm: #npm 的加载源
    	js:
    		jspackage: #js 名，可以与文件名不一致
    			src: "资源地址,详情见后面"
    			# async: true 异步加载此 js
    			# data-pjax: true 在 pjax 加载时刷新此 js
    			# hash-value: 这个资源的 integrity 值，用于防 XXS
    			# deferLoad: true 使用动态 DOM 节点添加延迟 js 加载 (实验性)

    vendorsList:
      js:
      	- jspackage #与上方 jspackage 一致即可

资源地址格式如下:

https://example.com/xxx.js 使用 http (s) 地址加载 js
combine/xxx.js,xxx.js 使用 jsdelivr 的 combine 功能加载 (不推荐)
npm/xxx/xxx.js 使用 npm 源加载 js
gh/xxx/xxx.js 使用 gh 源加载 js
xxx.js 从本地加载 js
优先级如下:
http>combine>npm>gh > 本地

Hexo Shoka jsdelivr