原本应该显示的流程图效果

网页上始终是用PlainText给圈起来

在Typora中使用<pre class="mermaid">语法让Typora误判部分内容为代码块

📝 Comprehensive Summary: The Mermaid Renderer Saga

1. Timeline of Failures, Mistakes & The Final Fix

The diagram below illustrates the exact chronological order of how our configuration broken down, the technical blind spots we encountered, and the final "De-shelling" injection that fixed everything.

1
2
3
4
5
6
7
8
timeline
title The Mermaid Troubleshooting Journey
A "Initial State: The Broken Cloud" : Local Typora rendered perfectly <br> Online GitHub Pages showed a black PLAINTEXT box <br> Cause: Hexo server compiler stripped out the Mermaid syntax
B "Local Fix Attempts" : Attempted switching Hexo renderers <br> Added exclude rules to _config.yml <br> Mistake: GitHub Actions ran `npm install` blindly, completely ignoring local configurations
C "The Script Injection & Typora Fighting" : Tried injecting raw JavaScript into individual `.md` files <br> Fault: Typora's sensitive AST parser panicked at the sight of Javascript loops <br> Wrapped everything into ugly code-blocks locally
D "The Silent Config Mistake" : Moved script to Theme `inject` setting <br> Fault: The lines were left commented out with `#` <br> Incorrect 5-space indentation also broken the YAML compilation
E "The Cloud Squeeze Breakdown" : Un-commented the inject code <br> Result: A 'Syntax Error' bomb exploded online <br> Discovery: Hexo stripped all NEWLINE `\n` characters in the cloud, squeezing code into one flat line
F "The Perfect Resolution" : Upgraded script to use regex auto-healing <br> Reconstructed missing line-breaks in browser <br> Removed the outer `figure.highlight` black shell completely

2. All Faults, Mistakes, and Technical Root Causes

During our multi-round battle, we unmasked four major architectural blind spots spanning from your local text editor up to the Linux server operating in the cloud.

❌ The Typora Illusion (WYSIWYG Defense Mechanism)

  • What Happened: When pasting raw <script> tags or functions like for (const block of codeBlocks) into the Markdown file, Typora automatically quarantined them inside ugly grey code blocks.
  • The Mistake: Believing it was an issue with the Markdown syntax itself.
  • The Root Cause: Typora is a What You See Is What You Get editor. Its internal parser aggressively monitors inputs. To prevent complex Javascript from crashing the live editor UI, it forcefully wraps unauthorized scripts in a display-only code shell.

❌ The GitHub Actions Desync

  • What Happened: Changing local plugins or adding exclude: ['mermaid'] into your root _config.yml yielded absolutely zero changes online.
  • The Root Cause: Your automated deployment pipeline utilizes GitHub Actions. Every time you pushed code, the remote Linux instance ran a fresh npm install. It re-downloaded a generic Hexo environment, totally wiping out your specialized local rendering environment.

❌ YAML Syntax & Comment Blunders

  • What Happened: Modifying the _config.butterfly.yml file to include inject-mermaid.js initially returned a 0-result match in the online HTML source code.
  • The Mistake: Forgetting to strip the # comment flag, combined with an arbitrary 5-space indentation.
  • The Root Cause: YAML is strictly hyper-sensitive to spacing. If indentation elements do not align exactly with their parent arrays, the compiler quietly ignores the entire branch without throwing an error message.

❌ The Cloud String-Squeeze (The "Syntax Error" Bomb)

  • What Happened: Once the script successfully injected, the diagram turned into a Syntax error in text (mermaid version 10.9.6) bomb icon.
    image-20260709152210998
  • The Root Cause: Hexo's online compiler optimization compressed multi-line code into a singular flat string to save packet weight. Because Mermaid's engine relies strictly on NEWLINE indicators to parse nodes, flat-lining the text caused the structural layout to instantly choke.

3. The Final Architecture (How We Fixed It)

We ultimately moved past battling the compiler and applied a client-side injection approach. By decoupling the content from the rendering logic, we achieved maximum stability.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
┌─────────────────────────────────┐
│ Your Local Typora (.md) │ ──► Pure, standard ```mermaid code blocks.
└─────────────────────────────────┘
│ (git push)

┌─────────────────────────────────┐
│ GitHub Actions (Cloud) │ ──► Squeezes code into raw plaintext blocks.
└─────────────────────────────────┘
│ (Deploys to Web)

┌─────────────────────────────────┐
│ User Browser (Execution) │ ──► The `inject-mermaid.js` script awakens:
└─────────────────────────────────┘ 1. Intercepts the mangled plaintext block.
2. Auto-heals missing lines using regex.
3. Destroys Hexo's ugly black outer shell.
4. Draws a beautiful, 100%-wide canvas!

🏆 The Winning Code Sitting inside C:\Blogs\source\inject-mermaid.js:

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
document.addEventListener("DOMContentLoaded", async function() {
const tag = ['p', 'r', 'e'].join('');
const codeBlocks = document.querySelectorAll(tag);
let hasMermaid = false;

for (const block of codeBlocks) {
if (block.textContent.includes('graph TD') || block.className.includes('plaintext') || block.className.includes('mermaid')) {
try {
hasMermaid = true;

// 1. Regex Auto-Healing for flattened cloud strings
let rawCode = block.textContent;
if (!rawCode.includes('\n') || rawCode.match(/\n/g).length < 3) {
rawCode = rawCode
.replace(/graph TD\s*/g, 'graph TD\n')
.replace(/\s*([A-G](?=\[|\{))/g, '\n$1')
.replace(/\s*([A-G]\s*-->)/g, '\n$1')
.replace(/\s*(style\s+[A-G])/g, '\n$1');
}

// 2. Set up a clean, full-width container
const container = document.createElement('div');
container.className = 'mermaid';
container.style.width = '100%';
container.style.margin = '24px 0';
container.style.background = 'transparent';
container.style.display = 'flex';
container.style.justifyContent = 'center';
container.textContent = rawCode;

// 3. De-shelling: Find and rip out the outer Hexo black highlighters
let targetElement = block;
const figureShell = block.closest('figure.highlight');
if (figureShell) {
targetElement = figureShell;
} else if (block.parentNode && block.parentNode.tagName === 'DIV') {
targetElement = block.parentNode;
}

targetElement.parentNode.insertBefore(container, targetElement);
targetElement.remove();

} catch(e) {
console.error('De-shelling failed:', e);
}
}
}

// 4. Fire up the rendering engine asynchronously
if (hasMermaid) {
const { default: mermaid } = await import('[https://cdn.jsdelivr.net/npm/mermaid@10/dist/mermaid.esm.min.mjs](https://cdn.jsdelivr.net/npm/mermaid@10/dist/mermaid.esm.min.mjs)');
mermaid.initialize({
startOnLoad: false,
theme: 'default',
securityLevel: 'loose',
flowchart: { useMaxWidth: false, htmlLabels: true }
});
await mermaid.run();
}
});

And, declare and enable it in the theme configuration file

The newer version of the Butterfly theme is very user-friendly. It provides a dedicated interface called inject, which allows you to insert custom scripts at the top or bottom of a webpage without modifying the underlying .pug or .html templates.

Open your _config.butterfly.yml (the theme configuration file), search for inject:, and then add the path to the file you just created under bottom: (the bottom of the page):

1
2
3
4
5
6
7
# Inject
# Insert custom code in head on bottom
inject:
head:
# - <link rel="stylesheet" href="/xxx.css">
bottom:
- <script src="/inject-mermaid.js"></script> # 👈 牢牢钉死这一行,让它成为线上网站的隐形守护者

In Hexo, the source/ folder serves as the website’s root directory mapping. Any files placed under source/ will be directly flattened to the top level of the website when it is generated.

Therefore, you only need to use the relative path (the virtual path recognized by the website).

image-20260709152331509

The black background frame is still there: Hexo adds too many syntax-highlighting HTML wrappers around code blocks (such as tables with line numbers and nested code tags). Although our script successfully converted the innermost text into a diagram, it failed to completely strip away the heavy outer "black coat."

The diagram is too small: Its parent container is constraining it with a very rigid width or layout style.

Now that the core rendering is working correctly, let's move on to the final step: a complete cleanup and visual polish. We want the script not only to render diagrams, but also to behave like a perfectionist—removing the outer black frame and line numbers entirely, and enlarging the flowchart to 100% width so it fills the page!

🛠️ Ultimate Cleanup: Replace the Contents of inject-mermaid.js

Open your local file C:\Blogs\source\inject-mermaid.js again using EmEditor. Delete all existing content and replace it with the following ultimate version, which includes logic for perfect wrapper removal and adaptive scaling:

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
document.addEventListener("DOMContentLoaded", async function() {
const tag = ['p', 'r', 'e'].join('');
const codeBlocks = document.querySelectorAll(tag);
let hasMermaid = false;

for (const block of codeBlocks) {
if (block.textContent.includes('graph TD') || block.className.includes('plaintext') || block.className.includes('mermaid')) {
try {
hasMermaid = true;

// 1. 提取并修复被挤扁的代码
let rawCode = block.textContent;
if (!rawCode.includes('\n') || rawCode.match(/\n/g).length < 3) {
rawCode = rawCode
.replace(/graph TD\s*/g, 'graph TD\n')
.replace(/\s*([A-G](?=\[|\{))/g, '\n$1')
.replace(/\s*([A-G]\s*-->)/g, '\n$1')
.replace(/\s*(style\s+[A-G])/g, '\n$1');
}

// 2. 创建一个纯净的、无边框的、全宽的高级容器
const container = document.createElement('div');
container.className = 'mermaid';
container.style.width = '100%';
container.style.margin = '24px 0';
container.style.background = 'transparent'; // 彻底扔掉黑色背景
container.style.display = 'flex';
container.style.justifyContent = 'center'; // 图居中显示
container.textContent = rawCode;

// 🔍 3. 破壁脱壳:往上寻找 Hexo 的高亮外壳(把整个 PLAINTEXT 巨型黑框彻底连根拔起)
let targetElement = block;
const figureShell = block.closest('figure.highlight');
if (figureShell) {
targetElement = figureShell; // 如果有 Hexo 的标准高亮外壳,直接把整个外壳干掉
} else if (block.parentNode && block.parentNode.tagName === 'DIV') {
targetElement = block.parentNode;
}

// 4. 用纯净、全宽的图表,直接替换掉原本的黑框垃圾
targetElement.parentNode.insertBefore(container, targetElement);
targetElement.remove();

} catch(e) {
console.error('脱壳美化失败:', e);
}
}
}

if (hasMermaid) {
const { default: mermaid } = await import('https://cdn.jsdelivr.net/npm/mermaid@10/dist/mermaid.esm.min.mjs');
mermaid.initialize({
startOnLoad: false,
theme: 'default',
securityLevel: 'loose',
flowchart: {
useMaxWidth: false, // 禁用最大宽度限制,允许它自由放大
htmlLabels: true
}
});
await mermaid.run();
}
});

Now, your Markdown files remain completely standardized and free of hacky scripts, while the automated script safely corrects the structure directly inside the user's browser. Clean, scalable, and completely bulletproof!