Hexo 5.0.0 Released

Hexo is a Nodejs-powered static site generator. It offers powerful API to integrate existing npm packages for web development and programmatically inserts certain content into articles.

This is our biggest release to date with tons of new features, performance improvements and bugfixes. According to our benchmark (which we run in every pull request to detect regression), Hexo 5 processed 500 posts in 16 seconds, whereas 4.2.0 processed 300 posts at the same time. Hexo now requires Nodejs 10+, Nodejs has dropped support of version 8 since 31 Dec 2019; although Nodejs 10.x is still supported, but since it’s going to be deprecated in less than a year (April 2021), we recommend using Nodejs 12+.

Refer to our installation guide to install Hexo.

To upgrade to Hexo v5, change the following line in your package.json,

package.json
-  "hexo": "^4.2.1",
+ "hexo": "^5.0.0",

Breaking change

  • refactor(external_link): migrate config during load_config @SukkaW #4414 #4371

    • See Writing section for new options (introduced back in v4)

      _config.yml
      # Deprecated
      external_link: true|false

      # New option
      external_link:
      enable: true|false

      # Deprecated
      use_date_for_updated: true

      # New option
      # https://hexo.io/docs/configuration#Date-Time-format
      updated_option: date
    • If you check external_link for truthy value, since it’s now automatically converted to object, it will always be truthy:

    <% if (config.external_link) { %>
    • If you wish to maintain backward compatibility with past versions:
    <% if ((typeof config.external_link === 'boolean' && config.external_link === true) || (typeof config.external_link === 'object' && config.external_link.enable === true)) { %>
  • refactor(box): remove Bluebird.asCallback @SukkaW #4379

    • Callback syntax for Box is never documented nor utilized in Hexo’s internal.
    • This is also a reminder that we might drop callbacks from all Hexo API in future. #3328
  • feat: bring up config.updated_option @SukkaW #4278

    • This can be useful for a theme that prefers to display Updated: only when it’s set in the article’s front-matter.
  • feat(open_graph): drop ‘keywords’ option from front-matter @curbengh #4174

    • Search engines no longer support keywords.
  • fix: override site’s permalink using an article’s front-matter @SukkaW #4359

    • User config:

      _config.yml
      permalink: :year/:month/:day/:title/
    • Front-matter

      source/foo-bar.md
      ---
      title: foo bar
      permalink: breaking-news/
      ---
    • That post will be available on http://yourhexo.com/breaking-news/

    • A reminder that permalink must have a trailing .html or /

      permalink: :year/:month/:day/:title/ # default
      # or
      permalink: :year/:month/:day/:title.html
  • Remove lodash from global variable @SukkaW #4266

    • Lodash _ is no longer available in Hexo API.
    • // Dropped
      <% const arrayB = _.uniq(arrayA) %>
    • We encourage the use of native JS API over Lodash, we find this guide to be helpful.
    • If you prefer to use Lodash, you can always install it and make it available via Helper API
  • chore/ci: drop Node.js 8 and add Node.js 14 @SukkaW #4255

  • refactor: remove site config from theme config @SukkaW #4145

    • Previously hexo.theme.config is merged into hexo.config, they are now separated to avoid possible conflict in configuration.

New feature

  • feat(tag): show source of the error & beautify @SukkaW #4420
  • feat(post_link): better error message when a post could not be located #4426
    • The error message is now clearer when there is an incorrect filename.
  • skip assets of unpublished posts and delete them if exist @DaemondShu #3489
    • When there is an unpublished post:
      ---
      title: Still a draft....
      published: false
      ---
    • That post including its assets will not be generated into the public/ folder.
  • feat(extend/injector): bring up new extend Injector @SukkaW #4049
  • feat: add prism highlight support @SukkaW #4119
  • feat(tagcloud): new option class & level @stevenjoezhang #4370
    • Ability to add class name for CSS styling.
  • feat(config): validate config before processing posts @SukkaW #4381
  • feat(post_permalink): add :second attribute option for post permalink @kkocdko #4185
    • Example:
      permalink: :year/:month/:day/:hour/:minute/:second/:title.html
    • Refer to Permalinks for available attributes.
  • feat(youtube_tag): add cookie option @curbengh #4155
    • When disabled, cookie is not set/sent in the youtube video embed.
  • feat(youtube_tag): support playlist @SukkaW #4139
    • Ability to embed a playlist.
  • feat(load_theme_config): support alternate theme config @SukkaW #4120
    • Theme can be configured in a file _config.[name].yml, e.g. _config.landscape.yml for hexo-theme-landscape.
    • Placed the file in the root folder, same as the current _config.yml.
    • Refer to the documentation for configuration priority.
  • feat(feed_tag): support parsing config.feed @curbengh #4029
  • feat(tag): add unregister() method @SukkaW #4046
    • This means you can now unregister existing tag plugins and replace it with your own with the same name.
  • feat(filter): add _after_html_render filter @jiangtj #4051
    • perf(filter): set after_render:html as alias of _after_html_render @curbengh #4073
    • Existing after_render:html filter plugins automatically benefit from this improvement.
  • feat(load_config): support theme_dir in node_modules @SukkaW #4112
  • fix(list_tags): custom class for each element @noraj #4059
    • Customize the class name for each element <ul>, <li>, <a>, <span> for list_tags plugin.

Performance

Fix

  • fix(box): ignore .git and node modules in the theme folder @jiangtj #4306
  • fix: allow empty title @stevenjoezhang #4344
  • fix(#4236): don’t create “/index” directories when post_asset_folder is true @jiangtj #4258
  • fix(#4317): non-greedy regexp for tag escape @SukkaW #4358
  • fix(post): use non-greedy regular expressions @stevenjoezhang #4161
  • fix(post): properly escape swig tag inside post @SukkaW #4352
    • swig tag inside a single backtick is now interpreted as code embed.
    • `{% foo %}{{ bar }}{% endfoo %}`
  • fix(logging): log database only in relevant commands @curbengh #4387
    • Writing database to ${dbPath}/db.json message shouldn’t show up in hexo clean and hexo version.
  • fix(server-cache): must match exact alias @curbengh #4388
    • Improve compatibility with 3rd-party console plugins that may have a name that starts with an ‘s’.
  • fix(tag-code): parse ‘wrap’ option @curbengh #4391
  • fix: remove unused type check @Himself65 #4398
  • fix: access error code from error object directly @SukkaW #4280
    • Improve compatibility with native JS API
  • fix: load_plugin with extra line EOF @SukkaW #4256
  • fix: parsing code error in backticks @seaoak #4229
  • fix(toc_helper): escape class name and handle null id @curbengh #4009
  • fix(meta_generator): match existing <meta> with different order @SukkaW #4017
  • fix(excerpt): stricter regex @curbengh #4443
    • Now only the following variants of excerpt tag are valid.
    1. <!--more-->
    2. <!-- more-->
    3. <!--more -->
    4. <!-- more -->

Refactor

Misc

Refer to the release note for a complete changelog.