hexo-swpp 2.7.0-beta.0 → 2.7.0-beta.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.
package/index.js CHANGED
@@ -4,51 +4,15 @@
4
4
 
5
5
  const config = hexo.config
6
6
  const enable = (config.swpp ?? hexo.theme.config.swpp)?.enable
7
- const logger = require('hexo-log')()
7
+
8
8
 
9
9
  if (enable) {
10
- const rules = loadRules()
11
- const defConfig = require('./lib/defConfig')
12
- if (!rules.config) {
13
- logger.error("未在 sw-rules.js 中查找到插件配置!")
14
- throw '插件配置缺失'
15
- }
10
+ const configLoader = require('./lib/configLoader')
11
+ const rules = configLoader.load(hexo)
16
12
  // 排序
17
- require('./lib/sort.js')(defConfig, rules.config)
13
+ require('./lib/sort.js')(rules.config)
18
14
  // 生成 update.json
19
- require('./lib/jsonBuilder.js')(hexo, config, defConfig, rules)
15
+ require('./lib/jsonBuilder.js')(hexo, config, rules)
20
16
  // 生成 sw.js
21
- require('./lib/swBuilder.js')(hexo, config, defConfig, rules)
22
- }
23
-
24
- // 加载 sw-rules.js 文件
25
- function loadRules() {
26
- const nodePath = require('path')
27
- const fs = require('fs')
28
- const themeName = hexo.config.theme
29
- // 根目录下的文件
30
- const root = nodePath.resolve('./', 'sw-rules.js')
31
- // themes 文件夹下的文件
32
- const themes = nodePath.resolve('./themes/', themeName, 'sw-rules.js')
33
- // node_modules 文件下的文件
34
- const modules = nodePath.resolve('./node_modules/', `hexo-theme-${themeName}/sw-rules.js`)
35
- const exists = {
36
- root: fs.existsSync(root),
37
- themes: fs.existsSync(themes),
38
- modules: fs.existsSync(modules)
39
- }
40
- if (!(exists.root || exists.themes || exists.modules)) {
41
- const tip = "未找到 sw-rules.js 文件"
42
- logger.error(`[sw-rules]: ${tip}`)
43
- throw tip
44
- }
45
- let result = {}
46
- if (exists.themes)
47
- result = require(themes)
48
- else if (exists.modules) {
49
- result = require(modules)
50
- }
51
- if ('afterTheme' in result)
52
- logger.error("[sw-rules]: 主题目录下的 sw-rules.js 中不应当包含 afterTheme 函数!")
53
- return exists.root ? { ...result, ...require(root) } : result
17
+ require('./lib/swBuilder.js')(hexo, config, rules)
54
18
  }
@@ -0,0 +1,245 @@
1
+ // 配置加载器
2
+
3
+ const logger = require('hexo-log')()
4
+
5
+ // 加载 sw-rules.js
6
+ module.exports.load = hexo => {
7
+ const rules = loadRules(hexo)
8
+ const handle = (obj, def, list) => {
9
+ for (let key in def) {
10
+ const defValue = def[key]
11
+ const value = obj[key]
12
+ switch (typeof value) {
13
+ case 'undefined':
14
+ obj[key] = defValue
15
+ break
16
+ case 'object':
17
+ const defA = Array.isArray(defValue)
18
+ const objA = Array.isArray(value)
19
+ if (defA !== objA) {
20
+ logger.error(`[ConfigLoader] ${list.join('.')} 值与标准值类型不相同!已经使用默认配置项替代。`)
21
+ obj[key] = defValue
22
+ break
23
+ }
24
+ if (!defA) {
25
+ list.append(key)
26
+ handle(value, defValue, list)
27
+ list.pop()
28
+ }
29
+ break
30
+ }
31
+ }
32
+ }
33
+ if (!('config' in rules)) {
34
+ logger.error("[ConfigLoader] 未在 sw-rules.js 中查询到配置项!")
35
+ throw '配置项缺失!'
36
+ }
37
+ handle(rules.config, defConfig, [])
38
+ return rules
39
+ }
40
+
41
+ // 存储缺省配置
42
+ const defConfig = {
43
+ // sw 有关配置项
44
+ serviceWorker: {
45
+ /**
46
+ * 是否让插件自动生成 sw,为 false 该分类下所有配置项失效
47
+ * @type boolean
48
+ */
49
+ enable: true,
50
+ /**
51
+ * 逃生门
52
+ * @type number
53
+ * @see https://kmar.top/posts/73014407/#6c7c33f0
54
+ */
55
+ escape: 0,
56
+ /**
57
+ * 缓存库名称
58
+ * 发布网站后 **切勿修改** 该配置项!
59
+ * @type string
60
+ */
61
+ cacheName: 'kmarBlogCache',
62
+ /**
63
+ * 是否启用调试,启用后会在 sw 中插入一些辅助调试的代码,不建议开启
64
+ * @type boolean
65
+ */
66
+ debug: false
67
+ },
68
+ // 与 SW 注册有关的配置项
69
+ register: {
70
+ /**
71
+ * 是否让插件生成注册代码,为 false 时该分类下所有配置项失效
72
+ * @type boolean
73
+ */
74
+ enable: true,
75
+ /**
76
+ * sw 注册成功时的动作
77
+ * @type ?VoidFunction
78
+ * */
79
+ onsuccess: undefined,
80
+ /**
81
+ * sw 注册失败时的动作
82
+ * @type ?VoidFunction
83
+ */
84
+ onerror: undefined,
85
+ /**
86
+ * 生成注册 SW 的 HTML 代码片段
87
+ * @param root {string} 网页根目录的 URL
88
+ * @param hexoConfig {Object} Hexo 配置项
89
+ * @param pluginConfig {Object} SW 配置项
90
+ * @return {string} 一个 HTML 标签的字符串形式
91
+ */
92
+ builder: (root, hexoConfig, pluginConfig) => {
93
+ const {onerror, onsuccess} = pluginConfig
94
+ return `<script>
95
+ (() => {
96
+ const sw = navigator.serviceWorker
97
+ const error = () => ${onerror}
98
+ if (!sw?.register('${new URL(root).pathname}sw.js')
99
+ ${onsuccess ? '?.then(() => ' + onsuccess + ')' : ''}
100
+ ?.catch(error)
101
+ ) error()
102
+ })()
103
+ </script>`
104
+ }
105
+ },
106
+ // 与 DOM 端有关的配置项
107
+ dom: {
108
+ /**
109
+ * 是否让插件生成 DOM 端 JS,为 false 是该分类下所有配置项失效
110
+ * @type boolean
111
+ */
112
+ enable: true,
113
+ /**
114
+ * 版本更新完成后的动作
115
+ * @type VoidFunction
116
+ */
117
+ onsuccess: () => {}
118
+ },
119
+ /**
120
+ * 与插件生成的版本文件相关的配置项
121
+ * 该功能目前无法关闭
122
+ */
123
+ json: {
124
+ /**
125
+ * 更新缓存时允许更新的最大 HTML 页面数量,需要更新的 HTML 文件数量超过这个值后会清除所有 HTML 缓存
126
+ * @type number
127
+ */
128
+ maxHtml: 15,
129
+ /**
130
+ * 版本文件(update.json)字符数量限制,插件将保证版本文件的字符数量不超过该值
131
+ * @type number
132
+ */
133
+ charLimit: 1024,
134
+ /**
135
+ * 文件缓存匹配采取精确模式
136
+ * 关闭时更新缓存时仅匹配文件名称,如 https://kmar.top/simple/a/index.html 仅匹配 /a/index.html
137
+ * 开启后更新缓存时将会匹配完整名称,如 https://kmar.top/simple/a/index.html 将匹配 /simple/a/index.html
138
+ * 两种方式各有优劣,开启后会增加 update.json 的空间占用,但会提升精确度
139
+ * 如果网站内没有多级目录结构,就可以放心大胆的关闭了
140
+ * key 值为文件拓展名,default 用于指代所有未列出的拓展名以及没有拓展名的文件
141
+ */
142
+ precisionMode: {
143
+ default: false
144
+ },
145
+ /**
146
+ * 是否合并指定项目
147
+ * 例如当 tags 为 true 时(假设标签目录为 https://kmar.top/tags/...)
148
+ * 如果标签页存在更新,则直接匹配 https://kmar.top/tags/ 目录下的所有文件
149
+ * **推荐将此项开启**
150
+ */
151
+ merge: {
152
+ index: true,
153
+ tags: true,
154
+ archives: true,
155
+ categories: true,
156
+ /**
157
+ * 这里填写目录名称列表(不带两边的斜杠)
158
+ * @type string[]
159
+ */
160
+ custom: []
161
+ },
162
+ /**
163
+ * 生成版本文件时忽略的文件
164
+ * 注:匹配的时候不附带域名,只有 pathname,匹配的内容一定是博客本地的文件
165
+ * @type RegExp[]
166
+ */
167
+ exclude: [
168
+ /sw\.js$/
169
+ ]
170
+ },
171
+ /**
172
+ * 外部文件更新监听
173
+ * @see https://kmar.top/posts/73014407/#c60b3060
174
+ */
175
+ external: {
176
+ /**
177
+ * 是否启用外部文件的更新
178
+ * @type boolean
179
+ */
180
+ enable: false,
181
+ /**
182
+ * 拉取网络文件时的超时时间
183
+ * @type number
184
+ */
185
+ timeout: 1500,
186
+ /**
187
+ * 匹配 JS 代码中的 URL
188
+ * @see https://kmar.top/posts/73014407/#c60b3060
189
+ */
190
+ js: [],
191
+ /**
192
+ * 某些外链只要 URL 不变其内容就一定不会变
193
+ * 可以通过正则表达式排除这些外链的文件内容监控,加快构建速度
194
+ * 注意:当某一个文件被跳过拉取后,这个文件中包含的 URL 也会被跳过
195
+ * @type RegExp[]
196
+ */
197
+ skip: [],
198
+ /**
199
+ * 在构建过程中替换部分链接,该替换结果不会影响文件内容
200
+ * 该设置项是为了应对构建服务器在国外,但是网站内部分缓存资源无法在国外访问导致拉取时超时的问题
201
+ * @type Object[]
202
+ * @see https://kmar.top/posts/73014407/#4ea71e00
203
+ */
204
+ replace: []
205
+ },
206
+ /**
207
+ * 对 Hexo 中的变量进行排序
208
+ * 默认插件对 posts、tags、categories、pages 四个变量进行排序
209
+ * 排序规则为优先按照字符串长度排序,若长度一致按照字典序排序
210
+ */
211
+ sort: {}
212
+ }
213
+
214
+ // 加载 sw-rules.js 文件
215
+ const loadRules = hexo => {
216
+ const nodePath = require('path')
217
+ const fs = require('fs')
218
+ // noinspection JSUnresolvedReference
219
+ const themeName = hexo.config.theme
220
+ // 根目录下的文件
221
+ const root = nodePath.resolve('./', 'sw-rules.js')
222
+ // themes 文件夹下的文件
223
+ const themes = nodePath.resolve('./themes/', themeName, 'sw-rules.js')
224
+ // node_modules 文件下的文件
225
+ const modules = nodePath.resolve('./node_modules/', `hexo-theme-${themeName}/sw-rules.js`)
226
+ const exists = {
227
+ root: fs.existsSync(root),
228
+ themes: fs.existsSync(themes),
229
+ modules: fs.existsSync(modules)
230
+ }
231
+ if (!(exists.root || exists.themes || exists.modules)) {
232
+ const tip = "未找到 sw-rules.js 文件"
233
+ logger.error(`[sw-rules]: ${tip}`)
234
+ throw tip
235
+ }
236
+ let result = {}
237
+ if (exists.themes)
238
+ result = require(themes)
239
+ else if (exists.modules) {
240
+ result = require(modules)
241
+ }
242
+ if ('afterTheme' in result)
243
+ logger.error("[sw-rules]: 主题目录下的 sw-rules.js 中不应当包含 afterTheme 函数!")
244
+ return exists.root ? { ...result, ...require(root) } : result
245
+ }
@@ -1,4 +1,4 @@
1
- module.exports = (hexo, hexoConfig, defConfig, swRules) => {
1
+ module.exports = (hexo, hexoConfig, swRules) => {
2
2
  const logger = require('hexo-log')()
3
3
  const fs = require('fs')
4
4
  const fetch = require('node-fetch')
@@ -47,7 +47,7 @@ module.exports = (hexo, hexoConfig, defConfig, swRules) => {
47
47
  /** 判断指定文件是否需要排除 */
48
48
  const isExclude = pathname => {
49
49
  // noinspection JSUnresolvedVariable
50
- const exclude = config.json?.exclude ?? defConfig.json.exclude
50
+ const exclude = config.json?.exclude
51
51
  for (let reg of exclude) {
52
52
  if (pathname.match(reg)) return true
53
53
  }
@@ -56,7 +56,7 @@ module.exports = (hexo, hexoConfig, defConfig, swRules) => {
56
56
 
57
57
  /** 判断是否跳过网络拉取 */
58
58
  const isSkipFetch = url => {
59
- const skipList = config.external?.skip ?? defConfig.external.skip
59
+ const skipList = config.external.skip
60
60
  for (let reg of skipList) {
61
61
  if (url.match(reg)) return true
62
62
  }
@@ -96,7 +96,7 @@ module.exports = (hexo, hexoConfig, defConfig, swRules) => {
96
96
  result[key] = crypto.createHash('md5').update(content).digest('hex')
97
97
  }
98
98
  // 外链监控
99
- const external = config.external ?? defConfig.external
99
+ const external = config.external
100
100
  if (!external.enable) return
101
101
  const indexOf = (str, ...chars) => {
102
102
  let result = str.length
@@ -221,7 +221,7 @@ module.exports = (hexo, hexoConfig, defConfig, swRules) => {
221
221
  referer: new URL(link).hostname,
222
222
  'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.0.0 Safari/537.36 Edg/107.0.1418.62'
223
223
  },
224
- timeout: config.external?.timeout ?? defConfig.external.timeout
224
+ timeout: config.external.timeout
225
225
  }).then(response => {
226
226
  switch (response.status) {
227
227
  case 200: case 301: case 302: case 307: case 308:
@@ -356,7 +356,7 @@ module.exports = (hexo, hexoConfig, defConfig, swRules) => {
356
356
  info: [newInfo]
357
357
  }
358
358
  // noinspection JSUnresolvedVariable
359
- const charLimit = config.json?.charLimit ?? defConfig.json.charLimit
359
+ const charLimit = config.json.charLimit
360
360
  if (JSON.stringify(result).length > charLimit) {
361
361
  return {
362
362
  global: result.global,
@@ -411,7 +411,7 @@ module.exports = (hexo, hexoConfig, defConfig, swRules) => {
411
411
  const merges = [] // 要合并的更新
412
412
  // 推送页面更新
413
413
  // noinspection JSUnresolvedVariable
414
- if (tidied.page.size > (config.json?.maxHtml ?? defConfig.json.maxHtml)) {
414
+ if (tidied.page.size > (config.json.maxHtml)) {
415
415
  // 如果 html 数量超过阈值就直接清掉所有 html
416
416
  info.change.push({flag: 'html'})
417
417
  } else {
@@ -466,7 +466,7 @@ module.exports = (hexo, hexoConfig, defConfig, swRules) => {
466
466
  return tidied
467
467
  }
468
468
  // noinspection JSUnresolvedVariable
469
- const mode = config.json?.precisionMode ?? defConfig.json.precisionMode
469
+ const mode = config.json.precisionMode
470
470
  for (let it of dif) {
471
471
  const url = new URL(it.match(/^(https?|\/\/)/) ? it : nodePath.join(root, it)) // 当前文件的 URL
472
472
  const cache = findCache(url) // 查询缓存
@@ -510,7 +510,7 @@ module.exports = (hexo, hexoConfig, defConfig, swRules) => {
510
510
  }
511
511
 
512
512
  function replaceDevRequest(url) {
513
- const external = config.external ?? defConfig.external
513
+ const external = config.external
514
514
  if (!external.enable || !external.replace) return url
515
515
  for (let value of external.replace) {
516
516
  for (let source of value.source) {
package/lib/sort.js CHANGED
@@ -1,7 +1,7 @@
1
1
  const nodePath = require("path")
2
2
 
3
3
  /** 对 Hexo 内的属性进行排序 */
4
- module.exports = (defConfig, config) => {
4
+ module.exports = config => {
5
5
  const compare = (a, b) => {
6
6
  const result = a.length === b.length ? a < b : a.length < b.length
7
7
  return result ? -1 : 1
@@ -19,7 +19,7 @@ module.exports = (defConfig, config) => {
19
19
  tags: 'name',
20
20
  categories: 'name'
21
21
  }
22
- Object.assign(list, config.sort ?? defConfig.sort)
22
+ Object.assign(list, config.sort)
23
23
  const Locals = require(`${nodePath.resolve('./', 'node_modules/hexo/lib/hexo/locals')}`).prototype
24
24
  const get = Locals.get
25
25
  Locals.get = function(name) {
package/lib/swBuilder.js CHANGED
@@ -1,4 +1,4 @@
1
- module.exports = (hexo, hexoConfig, defConfig, rules) => {
1
+ module.exports = (hexo, hexoConfig, rules) => {
2
2
  const {
3
3
  modifyRequest,
4
4
  fetchNoCache,
@@ -12,7 +12,7 @@ module.exports = (hexo, hexoConfig, defConfig, rules) => {
12
12
  const logger = require('hexo-log')()
13
13
 
14
14
  const root = hexoConfig.url + (hexoConfig.root ?? '/')
15
- const serviceWorkerConfig = config.serviceWorker ?? defConfig.serviceWorker
15
+ const serviceWorkerConfig = config.serviceWorker
16
16
 
17
17
  // noinspection JSUnresolvedVariable
18
18
  hexo.extend.generator.register('buildSw', () => {
@@ -141,8 +141,8 @@ module.exports = (hexo, hexoConfig, defConfig, rules) => {
141
141
  // noinspection JSUnresolvedVariable
142
142
  let swContent = fs.readFileSync(relativePath, 'utf8')
143
143
  .replaceAll(keyword, cache)
144
- .replaceAll("'@$$[escape]'", (serviceWorkerConfig.escape ?? 0).toString())
145
- .replaceAll("'@$$[cacheName]'", `'${serviceWorkerConfig.cacheName ?? 'kmarBlogCache'}'`)
144
+ .replaceAll("'@$$[escape]'", (serviceWorkerConfig.escape).toString())
145
+ .replaceAll("'@$$[cacheName]'", `'${serviceWorkerConfig.cacheName}'`)
146
146
  if (modifyRequest) {
147
147
  swContent = swContent.replaceAll('// [modifyRequest call]', `
148
148
  const modify = modifyRequest(request)
@@ -176,14 +176,14 @@ module.exports = (hexo, hexoConfig, defConfig, rules) => {
176
176
  })
177
177
 
178
178
  // 生成注册 sw 的代码
179
- const registerConfig = config.register ?? defConfig.register
179
+ const registerConfig = config.register
180
180
  if (registerConfig.enable) {
181
181
  // noinspection JSUnresolvedVariable
182
182
  hexo.extend.injector.register('head_begin', () => registerConfig.builder(root, hexoConfig, config), "default")
183
183
  }
184
184
 
185
185
  // 插入 sw-dom.js
186
- const domConfig = config.dom ?? defConfig.dom
186
+ const domConfig = config.dom
187
187
  if (domConfig.enable) {
188
188
  // noinspection JSUnresolvedVariable,HtmlUnknownTarget
189
189
  hexo.extend.injector.register('body_begin', () => `<script src="/sw-dom.js"></script>`)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "hexo-swpp",
3
- "version": "2.7.0-beta.0",
3
+ "version": "2.7.0-beta.2",
4
4
  "main": "index.js",
5
5
  "dependencies": {
6
6
  "hexo-log": "^3.0.0",
@@ -14,7 +14,8 @@
14
14
  "lib/sw-dom.js",
15
15
  "lib/swBuilder.js",
16
16
  "lib/jsonBuilder.js",
17
- "lib/sort.js"
17
+ "lib/sort.js",
18
+ "lib/configLoader.js"
18
19
  ],
19
20
  "keywords": [
20
21
  "hexo",