前言

solitude主题的配置项可以自定义外部调用的地址,但是一直用别人的加速,就怕有一天出现问题导致还需要重新替换

所以打算弄成本地话,本教程基于在 Solitude 上优雅的使用 CDN 加速静态资源文件修改

教程

本教程适用的版本为v3.0.20,若有不同,请自行修改脚本代码

首先就是在根目录创建一个名为plugins.js的文件,然后将如下代码放进去,其中的isNPMfoderName根据实际情况修改

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
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
#!/usr/bin/env node
/**
* plugins.js
* 用于下载 Hexo 主题 Solitude 中第三方的插件文件。
* 该脚本会读取主题目录下的 plugins.yml 文件,解析其中的插件信息,
* 并从 CDN 上下载相应的文件到指定的本地目录。
* node plugins.js
*/

// 变量
const isNPM = false; // 是否是 NPM 安装
const foderName = 'plugins'; // 存储文件夹名称

// 模块
const fs = require('fs');
const fsPromises = require('fs/promises');
const path = require('path');
const https = require('https');

const THEME_DIR = isNPM ? path.join(__dirname, 'node_modules', 'hexo-theme-solitude') : path.join(__dirname, 'themes', 'solitude');
const PLUGIN_FILE = path.join(THEME_DIR, 'plugins.yml');
const OUTPUT_DIR = path.join(__dirname, foderName);

function parsePluginsYml(text) {
const res = {};
let cur = null;
text.split(/\r?\n/).forEach(l => {
const ln = l.split('#')[0].trimEnd();
if (!ln) return;
const sec = ln.match(/^([a-zA-Z0-9_\-]+):\s*$/);
if (sec) {
cur = sec[1];
res[cur] = {};
return;
}
const kv = ln.match(/^ ([a-zA-Z0-9_\-]+):\s*(.*)$/);
if (kv && cur) {
res[cur][kv[1]] = kv[2].trim();
}
});
return res;
}

async function mkdirp(d) {
try {
await fsPromises.mkdir(d, { recursive: true });
} catch (e) {
if (e.code !== 'EEXIST') throw e;
}
}

function fetch(url, dest) {
return new Promise((resolve, reject) => {
const request = https.get(url, (response) => {
// 处理重定向
if (response.statusCode >= 300 && response.statusCode < 400 && response.headers.location) {
response.destroy();
return fetch(response.headers.location, dest).then(resolve, reject);
}

if (response.statusCode !== 200) {
response.destroy();
return reject(new Error(`${response.statusCode} ${url}`));
}

const fileStream = fs.createWriteStream(dest);
response.pipe(fileStream);

fileStream.on('finish', () => {
fileStream.close(resolve);
});

fileStream.on('error', (err) => {
fs.unlink(dest, () => reject(err));
});
}).on('error', (err) => {
reject(err);
});
});
}

function minFile(f) {
return f.replace(/(?<!\.min)\.(js|css)$/i, '.min.$1');
}

function stripDistSegments(f) {
// 移除任意位置的 dist/ 目录段(包含开头或中间)
return f.replace(/(^|\/)dist\//g, '$1');
}

(async () => {
try {
const pluginsText = await fsPromises.readFile(PLUGIN_FILE, 'utf8');
const plugins = parsePluginsYml(pluginsText);
await mkdirp(OUTPUT_DIR);

for (const [key, def] of Object.entries(plugins)) {
if (!def.name || !def.file || !def.version) {
console.warn(`[SKIP] ${key} 缺少 name/file/version`);
continue;
}

const { name, file, version, other_name } = def;

const dirName = `${other_name || name}@${version}`;

const cdnFilePath = minFile(stripDistSegments(file));
const url = `https://cdnjs.cloudflare.com/ajax/libs/${other_name || name}/${version}/${cdnFilePath}`;

const dest = path.join(OUTPUT_DIR, dirName, stripDistSegments(file));

try {
await fsPromises.access(dest);
console.log(`[SKIP] ${key}`);
continue;
} catch (e) {
if (e.code !== 'ENOENT') {
console.error(`[ERROR] ${key} 访问文件失败: ${e.message}`);
continue;
}
}

console.log(`[DOWN] ${key}${dest}`);
try {
await mkdirp(path.dirname(dest));
await fetch(url, dest);
console.log(`[OK] ${key}`);
} catch (e) {
console.error(`[FAIL] ${key}: ${e.message}`);
}
}
console.log('全部完成!');
} catch (error) {
console.error(`脚本执行失败: ${error.message}`);
}
})();

然后就是运行此脚本,在终端输入node plugins.js即可下载文件到plugins文件夹中

最后就是修改调用方式了

找到_config.solitude.yml中的CDN类,将third_party改成custom

然后将custom_format改成/plugins/${cdnjs_name}@${version}/${min_cdnjs_file}即可。

有些朋友就会发现控制台会报缺少字体文件,这时候我们需要手动下载这两个字体文件并且放到plugins\font-awesome@6.7.2\webfonts文件夹中

字体文件:fa-solid-900.woff2fa-brands-400.woff2

最后一键三连即可。