前言

将博客静态文件上传至 github,通过 github action 自动发包至 npm,使用 npmmirror cdn。

npm 命令

网址: https://www.npmjs.com/

切换源

1
2
3
4
5
# https://blog.anheyu.com/posts/sdxhu.html#npm-镜像

npm config set registry http://registry.npmmirror.com
# 切回源
npm config set registry https://registry.npmjs.org/

添加本地 npm 用户

1
2
3
4
# 仅第一次使用需要添加用户,之后会提示你输入你的npm账号密码以及注册邮箱
npm adduser
# 非第一次使用直接登录即可,之后会提示你输入你的npm账号密码以及注册邮箱
npm login

初始化

1
npm init

image-20240324233905199

发布

1
npm publish

生成 npm token

npm 官网 => 头像 => Access Tokens => Generate New Token => 勾选 Automation

image-20240324234307284

github 仓库新增 NPM_TOKEN 的 secrets

image-20240325002106180

示例

package.json

scripts/generate_package_json.js,生成 public/package.json

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
// 生成 public/.package.json
// https://blog.anheyu.com/posts/72ea.html

hexo.extend.generator.register('npmpackagejson', function(locals){
// Object
return {
path: '/package.json',
data: `{
"name": "mycpen-blog",
"version": "0.0.0",
"description": "mycpen blog static file",
"main": "index.js",
"directories": {
"lib": "lib"
},
"scripts": {
"test": "echo \\"Error: no test specified\\" && exit 1"
},
"repository": {
"type": "git",
"url": "git+https://github.com/mycpen/blog.git"
},
"author": "mycpen",
"license": "ISC",
"bugs": {
"url": "https://github.com/mycpen/blog/issues"
},
"homepage": "https://github.com/mycpen/blog#readme"
}
`};
});

npm push

scripts/npmpublish.js,生成 public/.github/workflows/autopublish.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
// 生成 public/.github/workflows/autopublish.yml
// 推送静态资源至 npm
// https://akilar.top/posts/e82444a6/#具体操作步骤

hexo.extend.generator.register('npmpush', function(locals){
// Object
return {
path: '/.github/workflows/autopublish.yml',
data: `name: Node.js Package
# 监测分支,2020年10月后github新建仓库默认分支改为main,记得更改
on:
push:
branches:
- main

jobs:
publish-npm:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/setup-node@v1
with:
node-version: "18.x"
registry-url: https://registry.npmjs.org/
- run: npm publish
env:
NODE_AUTH_TOKEN: `+ '${{secrets.npm_token}}' + `

- name: Wait for 3 minutes
run: sleep 180 # 等待 3 分钟,单位为秒

- name: Sync package from npm to npmmirror
run: |
npm install -g cnpm --registry=https://registry.npmmirror.com
cnpm sync mycpen-blog
`
};
});

.npmignore

scripts/npmignore.js,生成 public/.npmignore。目的 不提交 .html 这类文件至 npm

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// 生成 public/.npmignore
// https://akilar.top/posts/e82444a6/

hexo.extend.generator.register('npmignore', function(locals){
// Object
return {
path: '/.npmignore',
data: `**/*.html
.github/
download/
ads.txt
CNAME
robots.txt
`};
});

change version

.github/replace-localfile-url.py,修改 public/package.json version

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
#!/usr/bin/python
# -*- coding: UTF-8 -*-

# 源码参考 https://blog.csdn.net/qq_38150250/article/details/118026219

import os
import re
from datetime import datetime
import requests
import random

# 文件查找 find . -name file_name -type f
# 查找函数:search_path 查找根路径

# 获取文章路径
def search(search_path, search_result, search_fileType_list):
# 获取当前路径下地所有文件
all_file = os.listdir(search_path)
# 对于每一个文件
for each_file in all_file:
# 若文件为一个文件夹
if os.path.isdir(search_path + each_file):
# 递归查找
search(search_path + each_file + '/', search_result, search_fileType_list)
# 如果是需要被查找的文件
else:
for i in search_fileType_list:
if re.findall(f'.*\\{i}$', each_file) == [each_file]:
search_result.append(search_path + each_file)


# 替换 sed -i 's/old_str/new_str/'
# 文本替换 replace_file_name 需要替换的文件路径,replace_old_str 要替换的字符,replace_new_str 替换的字符
def replace(replace_file_name, replace_old_str, replace_new_str):
with open(replace_file_name, "r", encoding = "UTF-8") as f1:
content = f1.read()
f1.close()
t = content.replace(replace_old_str, replace_new_str)
with open(replace_file_name, "w", encoding = "UTF-8") as f2:
f2.write(t)
f2.close()

# ==================================================================


# npm time version | npm_converted_time
# ------------------------------------------------------------------
# 将数字和字母对应关系定义为字典
npm_num_mapping = {
'0': ['a', 'b', 'u'], '1': ['c', 'd', 'v'], '2': ['e', 'f', 'w'], '3': ['g', 'h', 'x'],
'4': ['i', 'j', 'y'], '5': ['k', 'l', 'z'], '6': ['m', 'n'], '7': ['o', 'p'],
'8': ['q', 'r'], '9': ['s', 't']
}
# 当前时间
npm_now = datetime.now()
# 格式化当前时间为指定格式 2403230741
npm_formatted_time = npm_now.strftime("%y%m%d%H%M")
# 数字替换为随机映射字母 ejugfhupjv
npm_converted_time = ''
for char in npm_formatted_time:
if char.isdigit():
npm_converted_time += ''.join(random.choice(npm_num_mapping[char]) if char in npm_num_mapping else char)
else:
npm_converted_time += char

# 替换 package.json 0.0.0
result_npmPackageJson = ['./public/package.json']
old_npmPackageJson_version = '0.0.0'
new_npmPackageJson_version = f'0.0.0-{npm_converted_time}'
count = 0
# json
for file_name in result_npmPackageJson:
replace(file_name, old_npmPackageJson_version, new_npmPackageJson_version)
count += 1
print("{} done {}".format(file_name, count))

.github/workflows/autodeploy.yml,执行上方 py 脚本 - name: Replace localFile URL

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
name: Auto deploy
# 当有改动推送到master分支时,启动Action
on:
workflow_dispatch:
push:
branches:
- main

jobs:
deploy:
runs-on: ubuntu-latest
steps:
- name: 检查分支
uses: actions/checkout@v2
with:
ref: main

- uses: szenius/set-timezone@v1.0 # 设置执行环境的时区
with:
timezoneLinux: "Asia/Shanghai"

- name: 安装 Node
uses: actions/setup-node@v1
with:
node-version: "18.x"

- name: 安装 Hexo
run: |
export TZ='Asia/Shanghai'
npm install hexo-cli -g

- name: 缓存 Hexo
uses: actions/cache@v1
id: cache
with:
path: node_modules
key: ${{runner.OS}}-${{hashFiles('**/package-lock.json')}}

- name: 安装依赖
if: steps.cache.outputs.cache-hit != 'true'
run: |
npm install gulp-cli -g #全局安装gulp
npm install --save

- name: Generate static file
run: |
hexo clean ; hexo generate ; gulp

- name: Set up Python 3.10
uses: actions/setup-python@v3
with:
python-version: "3.10"
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install requests
- name: Replace imageBed URL
run: |
python .github/replace-imgbed-url-v2.py
- name: Replace localFile URL
run: |
python .github/replace-localfile-url.py

- name: Delete static file repository tags
run: |
mkdir tmp_mycpen
cd tmp_mycpen
git clone https://github.com/mycpen/blog.git
cd blog
git push --force --quiet "https://mycpen:${{ secrets.GH_TOKEN }}@github.com/mycpen/blog.git" --delete $(git tag -l)
cd ../..
rm -rf tmp_mycpen

- name: Deploy static file
run: |
cd ./public
git init
git config --global user.email 'github-actions[bot]@users.noreply.github.com'
git config --global user.name 'github-actions[bot]'
git add .
git commit -m "$(date +'%Y/%m/%d')"
tag_name=$(date +'%y.%m.%d')
git tag $tag_name
git push --force --quiet "https://mycpen:${{ secrets.GH_TOKEN }}@github.com/mycpen/blog.git" $tag_name
git push --force --quiet "https://mycpen:${{ secrets.GH_TOKEN }}@github.com/mycpen/blog.git" master:main

- name: Purge JSD cache
run: |
jsd_purge_urls=("https://purge.jsdelivr.net/gh/mycpen/blog/" "https://purge.jsdelivr.net/gh/mycpen/blog@latest/" "https://purge.jsdelivr.net/gh/mycpen/blog@main/")
for url in "${jsd_purge_urls[@]}"; do curl -s $url; done

- name: 推送百度 url
run: |
hexo deploy

- name: Delete workflow runs
uses: Mattraks/delete-workflow-runs@v2
with:
token: ${{ secrets.GH_TOKEN }}
repository: ${{ github.repository }}
retain_days: 30
keep_minimum_runs: 6

参考

  1. akilar | github-action推送博客部署仓库至NPM
  2. akilar | npm图床
  3. 安知鱼 | hexo博客工作流CI
  4. 安知鱼 | npm图床
  5. EtherDream | 文件一键上传到 NPM
  6. npmmirror | 同步模块 cnpm sync cnpmcore
  7. github | CyanBlog/pkgpublish.js