hexo + butterfuly 博客搭建
安装前置环境
版本信息
npm 9.5.1
nodo v19.8.1
hexo-cli: 4.3.0
hexo 7.0
两种安装方式本机安装, 另一种 docker 方式
正常安装
node: https://github.com/nodesource/distributions#debinstall
ubuntu 安装方式
通过 apt install npm 的方式版本比较低,hexo 版本最新的不支持
curl -fsSL https://deb.nodesource.com/setup_current.x | sudo -E bash - &&\
sudo apt-get install -y nodejs
1 安装 hexo
npm install -g hexo-cli
#初始化工作目录
hexo init hexo
cd hexo
npm install
2 通过 docker 安装 hexo
编写 dockerfile,构建镜像
FROM node:19
RUN npm install hexo@7.0.0-rc1 -g \
&& npm install hexo-renderer-pug hexo-renderer-stylus --save \
&& npm un hexo-renderer-marked --save \
&& npm i hexo-renderer-markdown-it-plus --save \
&& npm install hexo-admin --save \
&& npm install hexo-admin --save
构建镜像
docker build hexo:7.0 -t .
通过 docker-compose 启动
version: "3"
services:
hexo-cli:
image: "hexo:7.0"
#working_dir: /home/node/app
#环境变量
#environment:
# - NODE_ENV=production
volumes:
- /root/hexo/hexo:/hexo #映射目录
ports:
- 4000:4000 #映射端口
#启动命令
command: "hexo --debug --cwd /hexo s"
通过下面命令启动
docker compose up -d
#查看日志
docker compose logs -f
安装主题
git clone -b master https://github.com/jerryc127/hexo-theme-butterfly.git themes/butterfly
修改 Hexo 工作目录下的 _config.yml,把主題改為 butterfly
theme: butterfly
还需要安装 pug 以及 stylus 的渲染器
https://github.com/CHENXCHEN/hexo-renderer-markdown-it-plus
npm install hexo-renderer-pug hexo-renderer-stylus --save
npm un hexo-renderer-marked --save
npm i hexo-renderer-markdown-it-plus --save
修改配置文件_config.yml, 添加下面配置
markdown_it_plus:
highlight: true
html: true
xhtmlOut: true
breaks: true
langPrefix:
linkify: true
typographer:
quotes: “”‘’
pre_class: highlight
安装在线文章管理插件
在 hexo5.0 中这个插件已经被弃用,有部分问题,不过还是可以使用
通过 location/admin 访问使用
npm install hexo-admin --save
修改 hexo-amin 插件
1. 添加根据文档路径和名称保存图片
进入到 hexo-admin 目录
cd /hexo/node_modules/hexo-admin/www
修改 bundle.js
修改 api.js
cd /hexo/node_modules/hexo-admin/
在编辑文档的时候图片可能会没有显示,一般过一会刷新刷新一下就可以了
图片路径中含有 _posts 图片会无法显示
在路径中去掉 _posts
//相关代码
var settings = this.props.adminSettings
var reader = new FileReader();
reader.onload = function(event) {
var filename = null;
var filePath = null;
if (settings.options) {
if(!!settings.options.nineyaImageFilePath){
//var filePath = document.getElementsByClassName("editor_perma-link")[0].attributes["href"].nodeValue;
var divElement = document.querySelector('.fileRename_display'); // 获取包含属性值的 div 元素
filePath = divElement.textContent; // 获取 div 元素的 title 属性值
//var filename = prompt(("What would you like to name the photo? All files saved as pngs. Name will be relative to " + filePath + "."), 'image.png')
if(filePath.charAt(filePath.length-1)=='/'){
filePath=filePath.substr(0,filePath.length-2);
}else{
filePath=filePath.substring(0,filePath.lastIndexOf('.'));
}
filePath = filePath.replace("_posts", "images_dir");
}else{
filePath = !!settings.options.imagePath ? settings.options.imagePath : '/images'
}
if(!!settings.options.askImageFilename) {
filename = prompt(("What would you like to name the photo? All files saved as pngs. Name will be relative to " + filePath + "."), 'image.png')
}
}
console.log(filename)
api.uploadImage(event.target.result, filename, filePath).then(function(res)
{return this.cm.replaceSelection(("\n![" + res.msg + "](" + res.src + ")"));}.bind(this)
);
}.bind(this);
reader.readAsDataURL(blob);
},
var NineyaImageFilePath = SettingsCheckbox({
name: 'nineyaImageFilePath',
label: '图片存储在资源目录下',
style: {width: '300px', display: 'inline-block'}
});
//api.js
use('images/upload', function (req, res, next) {
hexo.log.d('uploading image')
if (req.method !== 'POST') return next()
if (!req.body) {
return res.send(400, 'No post body given');
}
if (!req.body.data) {
return res.send(400, 'No data given');
}
var settings = getSettings()
var imagePath = '/images'
var imagePrefix = 'pasted-'
var askImageFilename = false
var overwriteImages = false
// check for image settings and set them if they exist
if (settings.options) {
if(!!settings.options.nineyaImageFilePath){
if(req.body.filePath){
imagePath = req.body.filePath
}
}else{
imagePath = settings.options.imagePath ? settings.options.imagePath : imagePath
}
askImageFilename = !!settings.options.askImageFilename
overwriteImages = !!settings.options.overwriteImages
imagePrefix = settings.options.imagePrefix ? settings.options.imagePrefix : imagePrefix
}
var msg = 'upload successful'
var i = 0
while (fs.existsSync(path.join(hexo.source_dir, imagePath, imagePrefix + i +'.png'))) {
i +=1
}
var filename = path.join(imagePrefix + i +'.png')
if (req.body.filename) {
var givenFilename = req.body.filename
// check for png ending, add it if not there
var index = givenFilename.toLowerCase().indexOf('.png')
if (index < 0 || index != givenFilename.length - 4) {
givenFilename += '.png'
}
hexo.log.d('trying custom filename', givenFilename)
if (fs.existsSync(path.join(hexo.source_dir, imagePath, givenFilename))){
if (overwriteImages) {
hexo.log.d('file already exists, overwriting')
msg = 'overwrote existing file'
filename = givenFilename
} else {
hexo.log.d('file already exists, using', filename)
msg = 'filename already exists, renamed'
}
} else {
filename = givenFilename
}
}
hexo.log.d('==========================', imagePath)
filename = path.join(imagePath, filename)
var outpath = path.join(hexo.source_dir, filename)
var dataURI = req.body.data.slice('data:image/png;base64,'.length)
var buf = new Buffer(dataURI, 'base64')
hexo.log.d(`saving image to ${outpath}`)
fs.writeFile(outpath, buf, function (err) {
if (err) {
console.log(err)
}
hexo.log.d('++++++++++++++++++++++++++++++++++++', path.join(hexo.config.root + filename))
hexo.source.process().then(function () {
res.done({
src: path.join(hexo.config.root + filename),
// src: path.join(hexo.source_dir, filename),
msg: msg
})
});
})
});
nginx 反向代理
sudo apt install nginx
#新建配置文件
cd /etc/nginx/conf.d
-----------------------
server {
listen 80; #ipv4
listen [::]:80; #ipv6
server_name x.x.x.x; #域名或者ip
location / {
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header Host $http_host;
proxy_pass http://127.0.0.1:4000;
}
#location ~ \.well-known{
# allow all;
#}
client_max_body_size 50m;
}
hexo 部署到 github
https://hexo.io/zh-cn/docs/github-pages.html
通过上述方式储存图片需要修改_config.yml 配置
原因是开启 post_asset_folder 这个后,在部署时,路径会默认修改为 post/post/xxx.png, 所以会导致图片无法显示
还要设置 root 目录
root: /
post_asset_folder: false
#设置github
deploy:
type: 'git'
repo: git@github.com:xxxxxx/xxxxxx.github.io.git
branch: master
添加.github/workflows/pages.yml 文件,没有添加会出现 Uncaught SyntaxError: Unexpected token ‘<‘这个错误
查看 node -v 版本号 19 就该成 19
name: Pages
on:
push:
branches:
- master # default branch
jobs:
pages:
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- uses: actions/checkout@v2
- name: Use Node.js 16.x #此处
uses: actions/setup-node@v2
with:
node-version: "16" #此处
- name: Cache NPM dependencies
uses: actions/cache@v2
with:
path: node_modules
key: ${{ runner.OS }}-npm-cache
restore-keys: |
${{ runner.OS }}-npm-cache
- name: Install Dependencies
run: npm install
- name: Build
run: npm run build
- name: Deploy
uses: peaceiris/actions-gh-pages@v3
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
publish_dir: ./public
通过命令部署
hexo clean
hexo generate
hexo deploy
github 创建项目
xxxx 是自己 github 名称
- 创建 xxxxx.github.io 项目
- 设置 page
hexo 常用命令
hexo new [layout] <title>
hexo 安装相关插件
hexo-deployer-git git
部署插件
hexo-generator-search
本地搜索插件
hexo 主题优化
详细配置在下面这个网站
https://butterfly.js.org/posts/4aa8abbe/
壁纸网站
https://wall.alphacoders.com/
增加菜单
地址详细介绍
https://butterfly.js.org/posts/dc584b87/
# Menu 目錄
menu:
# Home: / || fas fa-home
# Archives: /archives/ || fas fa-archive
# Tags: /tags/ || fas fa-tags
# Categories: /categories/ || fas fa-folder-open
# List||fas fa-list:
# Music: /music/ || fas fa-music
# Movie: /movies/ || fas fa-video
# Link: /link/ || fas fa-link
# About: /about/ || fas fa-heart
首页: / || fas fa-home
归档: /archives/ || fas fa-archive
标签: /tags/ || fas fa-tags
分类: /categories/ || fas fa-folder-open
图片集: /Gallery/ || icon-images
#菜单||fas fa-list:
#音乐: /music/ || fas fa-music
#电影: /movies/ || fas fa-video
#友链: /link/ || fas fa-link
关于: /about/ || fas fa-heart
```yml
### 增加搜索
安装插件hexo-generator-search
https://github.com/wzpan/hexo-generator-search
```bash
npm install hexo-generator-search --save
search:
path: search.xml
field: post
content: true
template: ./search.xml
修改页脚
在主题配置文件中_config.yml 增加 js 文件
增加 hexo 配置_config.yml
先要 hexo clean && hexo genarate 生成 search.xml, 不然启动的时候会报 no search file search.xml
hexo config.yml
metadata:
author_id: tangtang
language: zh-CN
field: post
template: ./search.xml
author: tangtang
#文章封面
cover: 'http//123.com'
metadata:
author_id: tangtang
language: zh-CN
field: post
template: ./search.xml
author: tangtang
#文章封面
cover: 'http//123.com'
在 /themes/butterfly/source/js 目录下面创建 foot.js 文件
//$(document).ready(function(e){
// $('.copyright').html('©2022 <i class="fa-fw fas fa-heartbeat card-announcement-animation cc_pointer"></i> By tangtang');
//})
$(document).ready(function(e){
show_date_time();
})
function show_date_time(){
$('.framework-info').html('已经摸鱼<span id="span_dt_dt" style="color: #fff;"></span>');
window.setTimeout("show_date_time()", 1000);
BirthDay=new Date("4/20/2023 0:0:0");
today=new Date();
timeold=(today.getTime()-BirthDay.getTime());
sectimeold=timeold/1000
secondsold=Math.floor(sectimeold);
msPerDay=24*60*60*1000
e_daysold=timeold/msPerDay
daysold=Math.floor(e_daysold);
e_hrsold=(e_daysold-daysold)*24;
hrsold=Math.floor(e_hrsold);
e_minsold=(e_hrsold-hrsold)*60;
minsold=Math.floor((e_hrsold-hrsold)*60);
seconds=Math.floor((e_minsold-minsold)*60);
span_dt_dt.innerHTML='<font style=color:#afb4db>'+daysold+'</font> 天 <font style=color:#f391a9>'+hrsold+'</font> 时 <font style=color:#fdb933>'+minsold+'</font> 分 <font style=color:#a3cf62>'+seconds+'</font> 秒';
}
下载 jquery-3.6.1.min.js 到 /themes/butterfly/source/js
添加 js 时候注意文件名称
https://code.jquery.com/jquery-3.6.1.min.js