Waline Upgrade Report

Published 2026-02-07 12:27 1704 words 9 min read

How to integrate the Waline v2 comment system into the Hexo Shoka theme

Hexo Shoka Theme Waline Comment System Upgrade Report

Project Overview

This report documents in detail how to integrate the Waline v2 comment system into the Hexo Shoka theme. The original theme only supported the MiniValine comment system; it has now been successfully extended to support both Waline and Valine, with dynamic switching implemented.

Upgrade Date: February 2026
Waline Version: v2 (UMD format)
Theme: Hexo Shoka
Server Address: https://waline.vull.top


Technical Decisions

Why Waline v2 Instead of v3?

During integration, we initially tried using Waline v3 but encountered module compatibility issues:

  • Issue: Waline v3 uses the ES Module format, which is incompatible with the Shoka theme’s UMD loader
  • Solution: Downgrade to Waline v2, which provides full UMD support
  • CDN Path: npm/@waline/client@v2/dist/waline.js

Architecture Design

A conditional loading strategy is used to dynamically select the comment system based on the config file:

if (CONFIG.waline && CONFIG.waline.enable) {
  // Load Waline
} else {
  // Load Valine (default)
}

Modified Files List

A total of 6 files were modified, adding approximately 97 lines of code:

1. themes/shoka/_config.yml (Config File)

Changes:

  • Added a Waline configuration block
  • Configured Waline CDN resource paths

Key Configuration:

# Waline comment system
waline:
  enable: true
  serverURL: https://waline.vull.top
  
  locale:
    placeholder: 请文明评论呀
  
  commentCount: false
  pageview: false
  lang: zh-CN
  search: false
  reaction: false
  imageUploader: false
  
  requiredMeta:
    - nick

vendors:
  css:
    waline: npm/@waline/client@v2/dist/waline.css
  js:
    waline: npm/@waline/client@v2/dist/waline.js

xxxxxxxxxx  cateCards:   - slug: Study     cover: Study/cover.jpg   - slug: Life     cover: Life/cover.jpgyml

  • enable: Enable/disable Waline (set to false to fall back to Valine)
  • serverURL: Waline server address
  • locale.placeholder: Comment box placeholder text
  • lang: Interface language (zh-CN/en-US)
  • search: Sticker search feature
  • reaction: Article reaction feature
  • imageUploader: Image upload feature
  • requiredMeta: Required fields (nick/mail/link)

2. themes/shoka/scripts/generaters/script.js (Backend Config Generation)

Changes:

  • Extended the CONFIG object to add Waline configuration
  • Added Waline resource paths to the js and css objects

Code Changes:

var siteConfig = {
  // ... other config
  js: {
    valine: theme.vendors.js.valine,
    waline: theme.vendors.js.waline,  // new
    // ...
  },
  css: {
    valine: theme.css + "/comment.css",
    waline: theme.vendors.css.waline,  // new
    // ...
  },
  valine: theme.valine,
  waline: theme.waline,  // new
};

Purpose: Passes the Waline configuration from _config.yml to the frontend JavaScript


3. themes/shoka/layout/_partials/layout.njk (Template File)

Changes:

  • Added a waline flag to the LOCAL object
  • Implemented conditional rendering logic

Code Changes:

{%- if theme.widgets.recent_comments or page.comment !== false  %}
{%- if theme.waline and theme.waline.enable %}
LOCAL.waline = {{ page.waline|safedump if page.waline else "true" }},
{%- else %}
LOCAL.valine = {{ page.valine|safedump if page.valine else "true" }},
{%- endif %}
{%- endif %}

Purpose: Determines whether to pass the waline or valine flag to the frontend based on the theme configuration


4. themes/shoka/source/js/_app/pjax.js (Core Initialization Logic)

Changes:

  • Implemented Waline initialization logic
  • Added error handling and debug logging
  • Maintained compatibility with Valine

Complete Code:

const siteRefresh = function (reload) {
  // ... other code
  
  // Support Waline and Valine
  if (CONFIG.waline && CONFIG.waline.enable) {
    vendorCss('waline');
    vendorJs('waline', function() {
      var options = Object.assign({}, CONFIG.waline);
      options = Object.assign(options, LOCAL.waline||{});
      
      // Waline v2 uses Waline.init()
      if (typeof Waline !== 'undefined') {
        try {
          Waline.init({
            el: '#comments',
            serverURL: options.serverURL,
            path: LOCAL.path,
            lang: options.lang || 'zh-CN',
            locale: options.locale,
            emoji: options.emoji,
            meta: options.meta || ['nick', 'mail', 'link'],
            requiredMeta: options.requiredMeta || [],
            pageSize: options.pageSize || 10,
            wordLimit: options.wordLimit,
            login: options.login || 'enable',
            pageview: options.pageview || false,
            comment: options.commentCount || false,
            search: options.search !== undefined ? options.search : false,
            reaction: options.reaction !== undefined ? options.reaction : false,
            imageUploader: options.imageUploader !== undefined ? options.imageUploader : false
          });
          console.log('Waline 初始化成功');
        } catch (e) {
          console.error('Waline 初始化失败:', e);
        }
      } else {
        console.error('Waline 未加载');
      }

      setTimeout(function(){
        positionInit(1);
        postFancybox('.wl-content');
      }, 1000);
    }, window.Waline);
  } else {
    // Valine initialization logic (unchanged)
    vendorJs('valine', function() {
      var options = Object.assign({}, CONFIG.valine);
      options = Object.assign(options, LOCAL.valine||{});
      options.el = '#comments';
      options.pathname = LOCAL.path;
      options.pjax = pjax;
      options.lazyload = lazyload;

      new MiniValine(options);

      setTimeout(function(){
        positionInit(1);
        postFancybox('.v');
      }, 1000);
    }, window.MiniValine);
  }
  
  // ... other code
}

Key Technical Points:

  1. Config merging: Uses Object.assign() to merge global and page-level configuration
  2. API call: Waline v2 uses Waline.init() instead of new Waline()
  3. Error handling: Added try-catch and type checks
  4. Delayed initialization: Uses setTimeout to ensure the DOM is fully loaded
  5. Fancybox integration: Enables the image lightbox for Waline comment content (.wl-content)

5. themes/shoka/source/js/_app/page.js (Comment Loading Logic)

Changes:

  • Modified the loadComments() function to support dynamic comment system detection
  • Used IntersectionObserver for lazy loading

Code Changes:

const loadComments = function () {
  var element = $('#comments');
  if (!element) {
    goToComment.display("none")
    return;
  } else {
    goToComment.display("")
  }

  // Support Waline and Valine
  var commentType = CONFIG.waline && CONFIG.waline.enable ? 'waline' : 'valine';

  if (!window.IntersectionObserver) {
    vendorCss(commentType);
  } else {
    var io = new IntersectionObserver(function(entries, observer) {
      var entry = entries[0];
      vendorCss(commentType);
      if (entry.isIntersecting || entry.intersectionRatio > 0) {
        transition($('#comments'), 'bounceUpIn');
        observer.disconnect();
      }
    });

    io.observe(element);
  }
}

Optimizations:

  • Dynamically detects the comment system type
  • Loads CSS only when the comment area enters the viewport
  • Falls back for browsers that don’t support IntersectionObserver

6. themes/shoka/source/css/comment.styl (Style File)

Changes:

  • Added Waline-specific styles

New Code:

// Waline style support
.wl-container
  margin-top: 2rem
  
.wl-content
  word-break: break-word
  
.wl-editor
  border-radius: 4px
  
.wl-panel
  border-radius: 4px

Style Description:

  • .wl-container: Top spacing of the comment container
  • .wl-content: Auto line wrapping for comment content
  • .wl-editor: Rounded corners for the editor
  • .wl-panel: Rounded corners for the panel

Features

✅ Implemented Features

  1. Dual comment system support

    • Waline v2
    • MiniValine (a Valine variant)
    • One-click switching via the config file
  2. Complete config passing

    • Backend config → frontend CONFIG object
    • Page-level config overrides global config
  3. Lazy loading optimization

    • CSS resources loaded on demand
    • Uses IntersectionObserver to watch the viewport
  4. Error handling

    • Catches initialization failures
    • Console debug logging
  5. Backward compatibility

    • Preserves the original Valine configuration
    • Seamless switching without affecting existing features
  6. Chinese localization

    • Custom placeholder text
    • Chinese interface language

🔧 Optional Features

Can be enabled/disabled via the config file:

  • Comment count (commentCount)
  • Page view count (pageview)
  • Sticker search (search)
  • Article reaction (reaction)
  • Image upload (imageUploader)
  • Custom stickers (emoji)

Usage Guide

Enabling Waline

Edit themes/shoka/_config.yml:

waline:
  enable: true  # Set to true to enable Waline
  serverURL: https://your-waline-server.com

Switching Back to Valine

waline:
  enable: false  # Set to false to disable Waline; Valine is used automatically

Page-Level Configuration

Override global config in the article’s Front Matter:

---
title: 我的文章
waline:
  locale:
    placeholder: 这篇文章欢迎评论!
---

Disabling Comments

---
title: 关于页面
comment: false  # Completely disable comments
---

Testing and Verification

Test Environment

  • Browsers: Chrome, Firefox, Safari
  • Devices: Desktop, Mobile
  • Test pages: Article pages, home page, archive pages

Test Results

✅ Functional testing

  • Waline comment box displays correctly
  • Comment submission succeeds
  • Comment list loads correctly
  • Sticker picker works correctly

✅ Compatibility testing

  • Switching to Valine works correctly
  • PJAX page navigation has no issues
  • Image lightbox (Fancybox) works correctly

✅ Performance testing

  • CSS/JS lazy loading takes effect
  • No blocking on first-screen load
  • No errors in the console

Known Issues

⚠️ Server-side issues (not frontend integration issues)

  • Occasional 500 errors when registering with the Waline server
  • Recommend checking the server configuration and database connection

Technical Challenges and Solutions

Challenge 1: Waline v3 Module Compatibility

Problem: Waline v3 uses ES Modules, while the Shoka theme uses a UMD loader

Solution:

# Use v2 version
vendors:
  js:
    waline: npm/@waline/client@v2/dist/waline.js

Challenge 2: Missing waline Flag in the LOCAL Object

Problem: The frontend cannot determine whether Waline is enabled

Solution: Add conditional logic in layout.njk

{%- if theme.waline and theme.waline.enable %}
waline: true,
{%- endif %}

Challenge 3: Waline.init() API Confusion

Problem: The documentation mixes v2 and v3 APIs

Solution:

// Correct usage for v2
Waline.init({ el: '#comments', ... })

// Incorrect usage (v3)
// new Waline({ el: '#comments', ... })

Code Statistics

FileLines AddedLines ModifiedLines Deleted
_config.yml3500
script.js320
layout.njk411
pjax.js4050
page.js320
comment.styl1200
Total97101

Maintenance Recommendations

Daily Maintenance

  1. Regularly update the Waline version

    vendors:
      js:
        waline: npm/@waline/[email protected]/dist/waline.js
  2. Monitor console logs

    • Check for the “Waline 初始化成功” message
    • Watch for error logs
  3. Back up config files

    • _config.yml
    • mcp.json (if used)

Upgrading to Waline v3 (Future)

When the Shoka theme supports ES Modules:

  1. Modify the CDN path:

    waline: npm/@waline/client@v3/dist/waline.js
  2. Update the initialization code:

    import { init } from '@waline/client';
    init({ el: '#comments', ... });

Reference Resources


Summary

This upgrade successfully integrated the Waline v2 comment system into the Hexo Shoka theme, achieving the following goals:

✅ Complete functionality: Supports all core Waline features
✅ Backward compatible: Retains Valine support, switchable at any time
✅ Performance optimized: Lazy loads CSS/JS resources
✅ Easy to maintain: Centralized config management with clear code structure
✅ User friendly: Chinese localization and custom placeholders

Upgrade impact: Minimally invasive, only 6 files modified, no breaking changes

User feedback: “The comment system is working properly now” ✅


Report date: February 7, 2026
Report version: 1.0
Maintainer: Vullfin

If you enjoyed this, leave a comment~

... Page views
© 2021 - 2026 Vullfin @VV
Powered by theme astro-koharu · Inspired by Shoka