背景

前几年搭建了博客,但是一直都没有投入编写内容,最近又捡起来重新折腾了一下,重新梳理了一下hexo的使用,加深了理解,在此记录一下做个备忘。

一、安装与使用

1. 安装 Hexo CLI

1
npm install -g hexo-cli

2. 初始化博客项目

1
2
3
hexo init blog
cd blog
npm install

3. 安装并启用主题

个人喜欢Next主题的样式,因此这里选用Next主题

1
2
3
4
# 使用npm安装主题
npm install hexo-theme-next
# 拷贝配置文件到根目录
cp node_modules/hexo-theme-next/_config.yml _config.next.yml

修改_config.yml中的theme,以启用next主题

Hexo config file
1
theme: next

可以在_config.next.yml中修改scheme以切换系统样式,个人喜欢gemini的设计

Next config file
1
scheme: Gemini

4. 创建文章

1
hexo new "文章标题"

生成文件位于:source/_posts/文章标题.md

5. 本地预览

1
hexo server

访问:http://localhost:4000 进行本地预览

二、推荐插件

1. hexo-generator-sitemap

部署/运行时会生成sitemap

执行npm i hexo-generator-sitemap安装

并在配置文件_config.yml中添加以下配置,重新编译运行并访问http://localhost:4000/sitemap.xml即可看到网站地图的输出了

Hexo config file
1
2
sitemap:
path: sitemap.xml

2. hexo-generator-searchdb

开启本地搜索功能

执行npm i hexo-generator-searchdb安装

并在配置文件_config.yml中添加以下配置,重新编译运行后点击菜单栏的“搜索”按钮,即可搜索站内博客

Hexo config file
1
2
search:
enable: true

三、部署与SEO优化

部署方案

一开始采用GitHub托管,有提交自动触发构建并部署,然后域名解析到GitHub部署页面的方案。但是由于gfw,墙内访问比较困难(公司破网挂不挂梯子都很难打开自己的博客),且添加评论时,会遇到跨域问题不好解决。遂改为在服务器上打包构建,用nginx部署。

在服务器上拉取仓库并执行npm i安装依赖,在仓库根目录创建部署脚本deploy.sh

deploy.sh
1
2
3
4
5
6
7
8
9
10
11
12
13
14
#!/bin/bash

echo "🔄 拉取最新代码..."
cd /home/webapps/blog
git pull origin main

echo "📦 安装依赖..."
npm install

echo "🧹 清理旧生成文件..."
npx hexo clean

echo "📝 生成静态文件..."
npx hexo generate

输入bash /path/to/deploy.sh即可执行部署脚本自动打包构建。

证书申请

配置nginx之前,还需要注册一下证书以开启https协议。

首先确保/etc/ssl/certs/etc/ssl/private目录存在,若不存在,执行以下命令创建目录并赋予权限

1
2
3
4
5
mkdir -p /etc/ssl/private
chmod 700 /etc/ssl/private

mkdir -p /etc/ssl/certs
chmod 700 /etc/ssl/certs

执行以下命令签发证书,指定letsencrypt服务可以不用注册邮箱,且支持自动续期

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 先停止nginx服务
bt stop nginx

# 签发证书
acme.sh --issue --standalone -d your.domain.com --ecc --server letsencrypt

# 安装证书,最后的reloadcmd修改为本机重载ng配置的指令,我用宝塔面板安装的,因此执行bt reload nginx
acme.sh --install-cert -d your.domain.com --ecc \
--key-file /etc/ssl/private/your.domain.com.key \
--fullchain-file /etc/ssl/certs/your.domain.com_bundle.crt \
--reloadcmd "bt reload nginx"

# 重载nginx
bt reload nginx

nginx配置

接下来在nginx配置中添加以下配置,再重载即可访问部署后的博客页面了

nginx.conf
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
server {
listen 80;
server_name your.domain.com;

# 强制跳转到 HTTPS
return 301 https://$host$request_uri;
}
server {
listen 443 ssl;
server_name your.domain.com;

# SSL 证书路径(你需要替换成自己的)
ssl_certificate /etc/ssl/certs/your.domain.com_bundle.crt;
ssl_certificate_key /etc/ssl/private/your.domain.com.key;
ssl_session_timeout 5m;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:HIGH:!aNULL:!MD5;
ssl_prefer_server_ciphers on;

root /path/to/博客仓库/public;
index index.html;

access_log /www/wwwlogs/access_blog.log;

location / {
try_files $uri $uri/ /index.html;
}
}

SEO优化

SEO优化比较复杂,只是记录下自己做过的操作,还在研究学习中。

以谷歌搜索为例,访问地址:https://search.google.com/search-console,输入要索引的域名,谷歌会返回一个校验码文件。创建一个静态文件目录source/static存放这个文件。

并在hexo配置文件中添加跳过渲染内容,避免部署后访问校验文件时出现内容嵌套在博客框架中,导致校验不通过的问题。重新打包并访问https://your.domain.com/googledxxxxxxxxxx应该能看到输出google-site-verification: googledxxxxxxxxxx.html

_config.yml
1
2
skip_render:
- static/**/*

站点验证成功后还需要添加一下sitemap,这样谷歌可以知道需要抓取的子页面有哪些。若安装了上文的sitemap插件,可在ng添加如下配置,访问https://your.domain.com/sitemap时即可直接重定向到https://your.domain.com/sitemap.xml

1
2
3
4
5
6
7
8
...
location / {
try_files $uri $uri/ /index.html;
}

location = /sitemap {
return 301 /sitemap.xml;
}

然后在谷歌控制台中找到并打开“站点地图”菜单栏,在“添加新的站点地图”中输入sitemap,点击提交即可。

四、开启站内评论

这里选用twikoo作为站内评论组件 (需要next主题8.x版本支持)

先在服务器上启动服务,访问ip:port若看到输出Twikoo 云函数运行正常,请参考 https://twikoo.js.org/frontend.html 完成前端的配置 则为启动成功了

1
2
3
4
5
6
7
8
docker run -d \
--name twikoo \
-e TZ=Asia/Shanghai \
-e TWIKOO_THROTTLE=10 \
-v /home/twikoo/data:/app/data \
-p 8080:8080 \
--restart=always \
imaegoo/twikoo

为了避免跨域,这里用nginx把twitoo代理转发到跟博客同域名下,在nginx博客配置部分添加如下内容

1
2
3
4
5
6
7
8
9
10
11
12
...
location / {
try_files $uri $uri/ /index.html;
}

# 👇 添加 Twikoo 的反向代理配置
location /twikoo/ {
proxy_pass http://127.0.0.1:8080/; # 修改为twikoo服务的端口
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}

然后在博客根目录执行npm i hexo-next-twikoo安装twikoo组件,在next配置文件中添加如下配置,重新打包部署后访问博客页面应该就能看到站内评论组件了

_config.next.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
# Multiple Comment System Support
comments:
# Available values: tabs | buttons
style: tabs
# Choose a comment system to be displayed by default.
# Available values: disqus | disqusjs | changyan | livere | gitalk | utterances
active: disqus
# Setting `true` means remembering the comment system selected by the visitor.
storage: true
# Lazyload all comment systems.
lazyload: false
# Modify texts or order for any naves, here are some examples.
nav:
twikoo:
order: -1
text: Twikoo 评论
disqus:
text: Load Disqus
order: -1
#gitalk:
# order: -2

twikoo:
enable: true
envId: https://your.domain.com/twikoo # 或 http://ip:port,改成你自己的地址
region: ''
path: window.location.pathname
visitor: true
commentCount: true

背景

最近在做的项目有老年人模式的需求——也就是动态切换字体大小、元素间距等。

解决方案

项目使用element-uisasssass-loader,在scss文件中定义变量,并利用:export导出变量,供JS使用。JS中读取变量,使用setProperty方法设置全局css变量。项目中所有需要动态改变大小的,都不直接使用px,而是使用css变量进行设置。

使用开关动态切换常规/老年人模式变量,以切换全局css变量值。

以下是代码的实现:

目录结构

1
2
3
4
5
6
src
├── styles
│ ├── index.scss
│ ├── variables.scss
│ └── variables-senior.scss
└── App.vue

关键代码

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
/* variables.scss */

/* 无需动态改变的常量 */
$main_color: #4077f4;
// ...

/* 差异化变量 */
$variables: (
// 字号
font_size_extra_large: 20px,
font_size_large: 18px,
font_size_medium: 16px,
font_size_base: 14px,
font_size_small: 13px,
font_size_extra_small: 12px,
// checkbox
checkbox_after_left: 4px,
checkbox_after_top: 1px,
// 表单项
form_item_margin_bottom: 16px,
search_btn_width: 70px,
search_btn_detail_width: 60px
);
:export {
/* 常量部分 */
main_color: $main_color;
// ...

/* 变量自动导出 */
@each $name, $value in $variables {
#{$name}: #{$value};
}
}
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
/* variables-senior.scss */

// 字体增量,可以统一控制放大倍率
$font_size_increment: 5px;

/* 差异化变量 */
$variables: (
// 字号
font_size_extra_large: 20px + $font_size_increment,
font_size_large: 18px + $font_size_increment,
font_size_medium: 16px + $font_size_increment,
font_size_base: 14px + $font_size_increment,
font_size_small: 13px + $font_size_increment,
font_size_extra_small: 12px + $font_size_increment,
// checkbox
checkbox_after_left: 6px,
checkbox_after_top: 3px,
// 表单项
form_item_margin_bottom: 24px,
search_btn_width: 80px,
search_btn_detail_width: 80px
);
:export {
/* 变量自动导出 */
@each $name, $value in $variables {
#{$name}: #{$value};
}
}
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
<!-- 有的元素不能仅用变量控制,这时候就需要使用class .senior-mode,调整元素在老年人模式下的表现 -->
<template>
<div id="app" :class="{ 'senior-mode': isSeniorMode }">
<el-switch v-model="isSeniorMode" @change="toggleMode">
老年人模式
</el-switch>
<router-view />
</div>
</template>
<script>
import normalVariables from "@/styles/variables.scss"
import seniorVariables from "@/styles/variables-senior.scss"
export default {
name: "app",
data() {
return {
isSeniorMode: false,
}
},
mounted() {
this.setMode()
},
methods: {
toggleMode() {
this.setMode(this.isSeniorMode)
},
setMode(isSenior = false) {
const vars = isSenior ? seniorVariables : normalVariables
for (const [key, value] of Object.entries(vars)) {
document.documentElement.style.setProperty(`--${key}`, value)
}
}
}
}
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
/* style/index.scss */
.el-button {
font-size: var(--font_size_base);
&--mini {
font-size: var(--font_size_extra_small);
}
&--small {
font-size: var(--font_size_base);
}
&--medium {
font-size: var(--font_size_medium);
}
}

结语

这个方案的效果还是比较满意的,衍生出来还可以封装成组件,实现大中小三种字号切换的模式

背景

最近在做一个项目,需要在弹窗里展示政策PDF内容。本来想着直接把PDF文件放在前端项目里,但一个文件大几十M,加载起来很慢。而且客户不想看到PDF在网页中的预览框。
考虑到只是展示内容,不需要交互功能,就想着把PDF转成图片,这样既能缩小文件体积,又能提升加载速度。

解决方案

经过一番搜索,发现 ImageMagick 是个不错的选择。它不仅能处理PDF转图片,还支持批量处理,正好符合我的需求。

工具准备

  1. 安装 ImageMagick

    • Windows: 下载安装包或使用 choco install imagemagick
    • 安装后记得重启命令行
  2. 验证安装

    1
    magick --version
  3. 安装ImageMagick底层依赖 Ghostscript

    • 下载适合系统版本的安装包(通常是 gswin64.exe
  4. 验证安装

    1
    gswin64c -version

批量转换脚本

为了方便使用,我写了个批处理脚本,支持批量转换PDF文件:

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
@echo off
setlocal enabledelayedexpansion

:: 设置目标 DPI,调整这里即可改变分辨率
set dpi=150

:: 设置输出图片的质量(范围:1-100
set quality=80

:: 定义 A4 的实际尺寸(单位:英寸)
set a4_width_inch=8.27
set a4_height_inch=11.69

:: 使用 PowerShell 动态计算 A4 分辨率(宽度和高度)
for /f "tokens=*" %%A in ('powershell -Command "[math]::Round(%a4_width_inch% * %dpi%)"') do set width=%%A
for /f "tokens=*" %%A in ('powershell -Command "[math]::Round(%a4_height_inch% * %dpi%)"') do set height=%%A

:: 输出宽高以及质量参数以供验证
echo DPI: %dpi%
echo Width: %width% pixels
echo Height: %height% pixels
echo Quality: %quality%%

:: 验证宽高是否正确
if "%width%"=="" (
echo 宽度计算失败,请检查 PowerShell 是否可用或计算逻辑是否正确。
pause
exit /b
)
if "%height%"=="" (
echo 高度计算失败,请检查 PowerShell 是否可用或计算逻辑是否正确。
pause
exit /b
)

:: 遍历当前目录中的所有 PDF 文件
for %%f in (*.pdf) do (
:: 获取文件名(不带扩展名)
set filename=%%~nf
:: 创建与 PDF 同名的输出目录
mkdir "!filename!"
:: 转换 PDF 为图片,确保背景为白色,大小统一,设置质量
magick -density %dpi% "%%f" -background white -alpha remove -alpha off -resize %width%x%height% -gravity center -extent %width%x%height% -quality %quality% "!filename!\page-%%d.webp"
)

echo 转换完成!
pause

使用心得

参数调优经验

  • DPI设置

    • 150 DPI:适合大多数场景,文件大小和质量比较平衡
    • 200 DPI:高清显示,文件稍大
    • 100 DPI:文件最小,但可能不够清晰
  • 质量设置

    • 80-90:推荐设置
    • 70以下:文件小但质量一般
    • 95以上:质量好但文件大

效果对比

转换后的文件结构:

1
2
3
4
5
6
7
项目/
├── convert_pdf_to_images.bat
├── 政策文件.pdf
└── 政策文件/
├── page-0.webp
├── page-1.webp
└── ...

文件大小对比

  • 原PDF:41.6MB
  • 转换后:约5.3M(WebP格式)
  • 压缩率:约87%

总结

这个方案在一定程度上解决了我的问题:

  • ✅ 1M以上的文件体积基本都大幅压缩了
  • ✅ 加载速度明显提升
  • ✅ 保持了良好的显示效果
  • ✅ 支持批量处理,效率高

对于类似的需求,我觉得这个方案还是挺实用的。如果只是展示内容,转成图片确实比直接使用PDF要好很多。


记录一下这个实用的解决方案,以后遇到类似需求可以直接用。

Welcome to Hexo! This is your very first post. Check documentation for more info. If you get any problems when using Hexo, you can find the answer in troubleshooting or you can ask me on GitHub.

Quick Start

Create a new post

1
hexo new "My New Post"

More info: Writing

Run server

1
hexo server

More info: Server

Generate static files

1
hexo generate

More info: Generating

Deploy to remote sites

1
hexo deploy

More info: Deployment

0%