Blog Upgrade Log for Next Theme Version 7.7

I've been writing blogs for almost a year now, and the Next theme has gone through many updates. The addition of pjax is really fantastic, so I decided to update it. By the way, I also transferred my blog's local directory from Windows to macOS.

This post was translated from my Chinese blog post with the aid of ChatGpt.

Update Notes

The changes from Next theme version 7.1 to 7.7.2 are quite significant. Upgrading directly may lead to various minor issues. Therefore, this update involves a fresh installation.

Version Comparison

Hexo version before the upgrade:

1
2
3
4
5
hexo: 3.8.0
hexo-cli: 3.1.0
os: Windows_NT 10.0.17763 win32 x64
node: 12.14.1
next: 7.1

Hexo version after the upgrade:

1
2
3
4
5
hexo: 4.2.0
hexo-cli: 3.1.0
os: Darwin 18.7.0 darwin x64
node: 13.10.1
next: 7.7.2

New Features

  • PJAX (Partial Page Refresh Loading)
  • Dark Mode (Supports system-level dark mode like on Mac)
  • Gitalk Comments (Added a comment system after Gitment was discontinued)
  • Mediumzoom (Image plugin)
  • Language Switching (New)
  • CDN Integration
  • Echarts Integration

Removed Features

  • Dynamic Background (High resource consumption, causing lag, overheating, and fast battery drain on mobile and tablet devices)
  • i18n-generator (Haven’t written any English blogs for a year, and this solution had significant flaws)
  • NetEase Cloud Music Widget (Very low usage frequency, slowing down page loading)

Retained Features

  • Site Search
  • Word Count and Reading Time Statistics
  • Website Uptime
  • Loading Progress Bar
  • Crash Deception
  • Background Images
  • Mouse Click Effects
  • Busuanzi (Page view counter)
  • Live2D Virtual Assistant

MacOS Configuration Process

Install Software Dependencies

First, download and install git and node.js from the official websites:

Once installed, open the terminal and enter the following commands one by one to check if they were installed successfully:

1
2
git --version
node -v

A successful installation will display the software version numbers.

Configure Local Directory

  • Create a folder to store your blog files.
  • Open a terminal window at the location of the folder.
  • Enter npm install hexo -g to install Hexo.
    • This step might encounter errors. If so, use the command sudo npm install --unsafe-perm --verbose -g hexo to install Hexo.
  • Enter npm install to install other dependencies.
  • Enter npm install hexo-deployer-git --save to install the deployment plugin.
  • Enter hexo v to check if the installation was successful. A successful installation will return the Hexo version number.

Configure SSH

  • Open the terminal.
  • Enter ls -al ~/.ssh to check if you have previously generated SSH Keys. If not, continue.
  • Enter ssh-keygen -t rsa -C "YourGitHubEmailAddress" and press Enter three times.
  • The terminal will display the path where the files were generated. Find and open id_rsa.pub.
  • Copy all the contents from the file.
  • Open GitHub, click on your profile picture in the top right corner, and select Settings.
  • Open SSH and GPG keys, click on the top-right New SSH key button.
  • Fill in a Title (can be anything) and paste the copied key into Key.
  • Click Add SSH key.
  • Back in the Git bash, enter ssh -T git@github.com and press Enter.
  • The first time you enter, you may receive a prompt. Type yes and press Enter.
  • Success will display: Hi username! You've successfully authenticated, but GitHub does not provide shell access.
  • Enter git config --global user.name "YourUsername".
  • Enter git config --global user.email "YourEmailAddress".

Install the Next Theme

In the terminal, enter the following command to install the latest Next theme:

1
git clone https://github.com/theme-next/hexo-theme-next themes/next

Customizing the Next Theme

I won’t go into detail about configuring Hexo, as it can be done based on your existing _config.yml. Instead, let’s focus on customizing the Next theme.

Separating Configuration Files

Starting from Next theme version 7.3, configuration files have been separated from the main theme. For details, please refer to Xiao Ding’s Personal Blog.

  • Create a new folder: hexo/source/_data.
  • Copy ./themes/next/_config.yml to the hexo/source/_data directory and rename it to next.yml.
  • Set override to true within next.yml to use it as the theme’s configuration file.
  • In hexo/source/_data, create body-end.swig and styles.styl files.
  • Remove the # from the custom_file_path in next.yml to enable bodyEnd and style.
  • Depending on your needs, create and enable other files in the custom_file_path section of next.yml.

Pjax

Pjax is an Ajax-based plugin that enables partial page loading without full refresh, which sounds great. However, it has some minor issues:

  • When using Mediumzoom, images don’t load when navigating from the archive to a blog post. You need to refresh the page to load them.
  • Echarts charts don’t display until a page is refreshed; otherwise, they remain blank.

To install Pjax, use the following command:

1
git clone https://github.com/theme-next/theme-next-pjax source/lib/pjax

In your next.yml configuration file, search for pjax and set it to:

1
pjax: true

Dark Mode

The Next theme has introduced a dark mode feature that can be synchronized with your system’s dark theme settings.
In your next.yml configuration file, search for darkmode, and set it to auto. This setting will enable automatic switching between light and dark modes based on your system’s theme.

Gitalk Comments

Gitalk is a commenting system. Initially, I thought about using Valine, but it required real-name authentication, so I decided against it.
Here’s how to set up Gitalk comments:

  • Create a new GitHub repository named gitalk-comment to store issues generated for comments.
  • Click on your GitHub profile picture in the upper right, go to Settings, then Developer settings, and finally OAuth Apps.
  • Fill in the Application name field with any name.
  • For both Homepage URL and Authorization callback URL, enter your blog’s address.
  • Click Register application.
  • In your next.yml configuration file, search for gitalk.
  • Copy the obtained Client ID and Client Secret and paste them into their respective fields.
  • Set enable to true.
  • Set github_id and admin_user to your username.
  • Set repo to the name of the repository you created earlier, which is gitalk-comment.
  • distraction_free_mode is a feature similar to Facebook’s comment overlay.

The specific configuration in next.yml is as follows:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# Gitalk
# For more information: https://gitalk.github.io, https://github.com/gitalk/gitalk
gitalk:
enable: true
github_id: Siriusq # GitHub repo owner
repo: gitalk-commnet # Repository name to store issues
client_id: xxxxxxxx # GitHub Application Client ID
client_secret: xxxxxxxx # GitHub Application Client Secret
admin_user: Siriusq # GitHub repo owner and collaborators, only these guys can initialize gitHub issues
distraction_free_mode: false # Facebook-like distraction free mode
# Gitalk's display language depends on user's browser or system environment
# If you want everyone visiting your site to see a uniform language, you can set a force language value
# Available values: en | es-ES | fr | ru | zh-CN | zh-TW
language:

Mediumzoom

This plugin emulates the image viewing behavior found on Medium.com.
To install, run the following command:

1
npm install medium-zoom

In your next.yml configuration file, search for mediumzoom, and set it to:

1
mediumzoom: true

Bilingual Switching (Chinese and English)

Please refer to another blog post for information on enabling bilingual switching in Hexo Next 7.7: Hexo Next 7.7 Bilingual Switching

This feature allows you to search for content within your blog.
To install, run the following command:

1
npm install hexo-generator-searchdb

In your next.yml configuration file, search for local_search, and set it to:

1
enable: true

Word Count and Reading Time Statistics

To enable word count and reading time statistics, you can install the following plugin:

1
npm install hexo-symbols-count-time

In your root _config.yml file, add the following configuration:

1
2
3
4
5
6
7
8
9
symbols_count_time:
symbols: true
time: true
total_symbols: true
total_time: true
exclude_codeblock: false
awl: 4
wpm: 275
suffix: "mins."

Then, in your next.yml configuration file, search for symbols_count_time, and set it to:

1
2
3
4
symbols_count_time:
separated_meta: true
item_text_post: true
item_text_total: true

Adding jQuery

The newer version of the Next theme has removed jQuery, which may affect some of your custom settings. You can add jQuery back by following these steps:

  1. Copy the jQuery file from the older version of the Next theme or download it from the official jQuery website. The file path should be like this: ./hexo/themes/next/source/libs/jquery/jquery-2.2.0.min.js.
  2. Place the jQuery file in the ./hexo/source/js directory.
  3. In your ./hexo/source/_data/body-end.swig file, add the following code. Be sure to adjust the version if necessary:
    1
    2
    <!-- jQuery -->
    <script type="text/javascript" src="/js/jquery-2.2.0.min.js"></script>

Website Uptime

To display the website’s uptime, open the ./hexo/themes/next/layout/_partials/footer.swig file and add the following code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<div>
<span id="timeDate">Loading days...</span><span id="times">Loading hours, minutes, and seconds...</span>
<script>
var now = new Date();
function createtime() {
var grt= new Date("03/31/2019 00:00:00");
now.setTime(now.getTime()+250);
days = (now - grt ) / 1000 / 60 / 60 / 24;
dnum = Math.floor(days);
hours = (now - grt ) / 1000 / 60 / 60 - (24 * dnum);
hnum = Math.floor(hours);
if(String(hnum).length ==1 ){hnum = "0" + hnum;}
minutes = (now - grt ) / 1000 / 60 - (24 * 60 * dnum) - (60 * hnum);
mnum = Math.floor(minutes);
if(String(mnum).length ==1 ){mnum = "0" + mnum;}
seconds = (now - grt ) / 1000 - (24 * 60 * 60 * dnum) - (60 * 60 * hnum) - (60 * mnum);
snum = Math.round(seconds);
if(String(snum).length ==1 ){snum = "0" + snum;}
document.getElementById("timeDate").innerHTML = "This site has been running securely for "+dnum+" days ";
document.getElementById("times").innerHTML = hnum + " hours " + mnum + " minutes " + snum + " seconds";
}
setInterval("createtime()",250);
</script>
</div>

Loading Progress Bar

Display the loading progress bar for the current webpage.
Installation:

1
git clone https://github.com/theme-next/theme-next-pace source/lib/pace

In the next.yml file, search for Progress bar in the top during page loading and set it to:

1
2
pace:
enable: true

Crash Deception

Add a crash deception effect to the webpage title. The title will change when leaving the page and revert to normal when returning. This feature requires jquery.

Create a new file named crash_cheat in ./hexo/source/js and copy the following code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<!--Crash Deception-->
var OriginTitle = document.title;
var titleTime;
document.addEventListener('visibilitychange', function () {
if (document.hidden) {
$('[rel="icon"]').attr('href', "/img/TEP.ico");
document.title = '╭(°A°`)╮ The page has crashed ~';
clearTimeout(titleTime);
}
else {
$('[rel="icon"]').attr('href', "/favicon.ico");
document.title = '(ฅ>ω<*ฅ) Oops, it's back ~' + OriginTitle;
titleTime = setTimeout(function () {
document.title = OriginTitle;
}, 2000);
}
});

Then, add the following code to ./hexo/source/_data/body-end.swig:

1
2
<!--Crash Deception-->
<script type="text/javascript" src="/js/crash_cheat.js"></script>

Background Image

Place the background image in ./hexo/themes/next/source/images and name it background.jpg. Then, add the following code to ./hexo/source/_data/styles.styl:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
body {
background: url(/images/background.jpg); // Image path
background-repeat: no-repeat; // Whether to repeat
background-attachment: fixed; // Whether to scroll with the webpage
background-position: 50% 50%; // Image position
background-size: cover; // Image display size
-webkit-background-size: cover;
-o-background-size: cover;
-moz-background-size: cover;
-ms-background-size: cover;
opacity: 0.9;
footer > div > div {
color: #000000; // Footer text color
}
}

Mouse Click Effects

According to Xiaoding’s personal blog, the mouse click effect has been changed to be more friendly for low-performance devices. Create a new file named fireworks.js in ./hexo/themes/next/source/js/cursor and add the following code.

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
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
class Circle {
constructor({ origin, speed, color, angle, context }) {
this.origin = origin
this.position = { ...this.origin }
this.color = color
this.speed = speed
this.angle = angle
this.context = context
this.renderCount = 0
}

draw() {
this.context.fillStyle = this.color
this.context.beginPath()
this.context.arc(this.position.x, this.position.y, 2, 0, Math.PI * 2)
this.context.fill()
}

move() {
this.position.x = (Math.sin(this.angle) * this.speed) + this.position.x
this.position.y = (Math.cos(this.angle) * this.speed) + this.position.y + (this.renderCount * 0.3)
this.renderCount++
}
}

class Boom {
constructor ({ origin, context, circleCount = 16, area }) {
this.origin = origin
this.context = context
this.circleCount = circleCount
this.area = area
this.stop = false
this.circles = []
}

randomArray(range) {
const length = range.length
const randomIndex = Math.floor(length * Math.random())
return range[randomIndex]
}

randomColor() {
const range = ['8', '9', 'A', 'B', 'C', 'D', 'E', 'F']
return '#' + this.randomArray(range) + this.randomArray(range) + this.randomArray(range) + this.randomArray(range) + this.randomArray(range) + this.randomArray(range)
}

randomRange(start, end) {
return (end - start) * Math.random() + start
}

init() {
for(let i = 0; i < this.circleCount; i++) {
const circle = new Circle({
context: this.context,
origin: this.origin,
color: this.randomColor(),
angle: this.randomRange(Math.PI - 1, Math.PI + 1),
speed: this.randomRange(1, 6)
})
this.circles.push(circle)
}
}

move() {
this.circles.forEach((circle, index) => {
if (circle.position.x > this.area.width || circle.position.y > this.area.height) {
return this.circles.splice(index, 1)
}
circle.move()
})
if (this.circles.length == 0) {
this.stop = true
}
}

draw() {
this.circles.forEach(circle => circle.draw())
}
}

class CursorSpecialEffects {
constructor() {
this.computerCanvas = document.createElement('canvas')
this.renderCanvas = document.createElement('canvas')

this.computerContext = this.computerCanvas.getContext('2d')
this.renderContext = this.renderCanvas.getContext('2d')

this.globalWidth = window.innerWidth
this.globalHeight = window.innerHeight

this.booms = []
this.running = false
}

handleMouseDown(e) {
const boom = new Boom({
origin: { x: e.clientX, y: e.clientY },
context: this.computerContext,
area: {
width: this.globalWidth,
height: this.globalHeight
}
})
boom.init()
this.booms.push(boom)
this.running || this.run()
}

handlePageHide() {
this.booms = []
this.running = false
}

init() {
const style = this.renderCanvas.style
style.position = 'fixed'
style.top = style.left = 0
style.zIndex = '999999999999999999999999999999999999999999'
style.pointerEvents = 'none'

style.width = this.renderCanvas.width = this.computerCanvas.width = this.globalWidth
style.height = this.renderCanvas.height = this.computerCanvas.height = this.globalHeight

document.body.append(this.renderCanvas)

window.addEventListener('mousedown', this.handleMouseDown.bind(this))
window.addEventListener('pagehide', this.handlePageHide.bind(this))
}

run() {
this.running = true
if (this.booms.length == 0) {
return this.running = false
}

requestAnimationFrame(this.run.bind(this))

this.computerContext.clearRect(0, 0, this.globalWidth, this.globalHeight)
this.renderContext.clearRect(0, 0, this.globalWidth, this.globalHeight)

this.booms.forEach((boom, index) => {
if (boom.stop) {
return this.booms.splice(index, 1)
}
boom.move()
boom.draw()
})
this.renderContext.drawImage(this.computerCanvas, 0, 0, this.globalWidth, this.globalHeight)
}
}

const cursorSpecialEffects = new CursorSpecialEffects()
cursorSpecialEffects.init()

Then, add the following code to ./hexo/source/_data/body-end.swig:

1
2
3
4
{# Mouse Click Effects #}
{% if theme.cursor_effect == "fireworks" %}
<script async src="/js/cursor/fireworks.js"></script>
{% endif %}

In next.yml, add the following:

1
2
# Mouse Click Effects
cursor_effect: fireworks

Busuanzi

Next comes with built-in Busuanzi statistics. In next.yml, search for busuanzi_count and set it to:

1
enable: true

Customizing Single Line Code Color

To customize the color of single-line code in ./hexo/source/_data/styles.styl, add the following CSS code:

1
2
3
4
5
code {
color: #ff511A;
//background: #fbf7f8;
margin: 2px;
}

Live2D Virtual Assistant

Using the example of the tororo model I have installed, for other models, please refer to the official documentation.

Installation:

1
2
npm install --save hexo-helper-live2d
npm install live2d-widget-model-tororo

In your next.yml file, search for the section labeled “Progress bar in the top during page loading” and configure it as follows:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
live2d:
enable: true # Enable Live2D
scriptFrom: local # Plugin source
pluginRootPath: live2dw/ # Plugin root directory (relative path)
pluginJsPath: lib/ # Script file path (relative to the plugin root directory)
pluginModelPath: assets/ # Model file path (relative to the plugin root directory)
tagMode: false # Enable tag mode
debug: false # Enable debug mode
model:
use: live2d-widget-model-wanko # Choose the model
display:
position: right # Model's position on the page
width: 150 # Model width
height: 300 # Model height
mobile:
show: true # Show on mobile devices
react:
opacity: 1 # Set model opacity

This configuration will enable Live2D with the tororo model and display it on the right side of the page with the specified width and height. Adjust the configuration as needed for your specific use case or model.

Echarts

Echarts is a visualization chart library developed by Baidu. It’s important to note that there might be conflicts with Echarts when using PJAX, and a page refresh may be required to successfully load Echarts. Some Google search results suggest modifying PJAX to resolve this issue, but due to limited expertise, I was unable to successfully implement this solution.

If you have installed a plugin that uses Echarts 4.3, some charts may not display correctly. In such cases, manual modifications may be needed to update Echarts to the latest version. To do this, you can visit the ECharts official website and open any example. Then, use your browser’s console to find the URL of the latest JavaScript file and replace it.

To make these changes, open ./hexo/node_modules/hexo-tag-echarts4/template.html and modify the line <script src="https://cdn.bootcss.com/echarts/4.3.0/echarts.common.min.js"></script> to <script src="https://www.echartsjs.com/examples/vendors/echarts/echarts.min.js?_v_=1584687926098"></script>.

Additionally, some map-based charts may require the inclusion of map-related JavaScript files. You can find these URLs by inspecting the page with your browser’s console and then add them to ./hexo/node_modules/hexo-tag-echarts4/template.html. For example, for China map and world map:

1
2
<script src="https://www.echartsjs.com/examples/vendors/echarts/map/js/china.js?_v_=1584687926098"></script>
<script src="https://www.echartsjs.com/examples/vendors/echarts/map/js/world.js?_v_=1584687926098"></script>

In summary, you should add any missing components as needed.

Installation

1
npm install hexo-tag-echarts4 --save

Usage

You can specify the chart’s height and width in your content. For example, to create a chart with a height of 400px and a relative width of 85%, you can use the following syntax:

1
2
3
{% echarts 400 '85%' %}
\\TODO: Echarts contents go here
{% endecharts %}

If you don’t specify the dimensions, the default values are a height of 400px and a width of 81%.

Example:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
{% echarts %}
option = {
xAxis: {
type: 'category',
data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
},
yAxis: {
type: 'value'
},
series: [{
data: [820, 932, 901, 934, 1290, 1330, 1320],
type: 'line'
}]
};
{% endecharts %}

Abandoned on 2022.5.13

CDN

GitHub’s servers are located outside of China, which can result in significantly longer loading times when accessing websites from within China. However, you can effectively alleviate this issue by using CDN acceleration.

Here are the steps to set up CDN acceleration:

  1. Log in to Cloudflare.
  2. Enter your domain name and click on Add site.
  3. Choose a plan; the free plan is sufficient.
  4. Click Confirm plan.
  5. Cloudflare will scan your DNS records, and after a moment, it will display your domain’s current resolution records.
  6. Click Continue.
  7. Visit your domain name service provider’s website and replace the original servers with the two DNS servers provided by Cloudflare.
  8. Once you’ve completed this step, return to Cloudflare and click Done, check nameservers.
  9. Now, patiently wait for the changes to take effect. You will receive a notification email when they do.
  10. While waiting, you can configure some settings.
  11. SSL/TLS Options:
  • Set the Mode to the default Full.
  • Turn on Always Use HTTPS.
  • Turn on Opportunistic Encryption.
  • Turn on Authenticated Origin Pills.

┏(^0^)┛

Reference: Xiaoding’s Personal Blog