ppoffice / hexo-theme-hueman

A redesign of Alx's wordpress theme Hueman, ported to Hexo.
http://ppoffice.github.io/hexo-theme-hueman/
GNU General Public License v2.0
1.17k stars 335 forks source link

Insight Search loads `content.json` from a wrong place. #204

Closed ghost closed 6 years ago

ghost commented 6 years ago

I set the root directory as blog by putting root: /blog/ in the primary _config.yml, but Insight Search keeps obtaining the content.json from /(eg. https://....../content.json), not /blog/(eg. https://....../blog/content.json).

ppoffice commented 6 years ago

@wlzla000 Would you please post your _config.yaml and package.json here?

ghost commented 6 years ago

I read some code and I've just found...

The reason why this happened

My _config.yml

url: https://wlzla000.github.io
root: /blog/
relative_link: true

......

Generated CONTENT_URLs

The generated script for https://wlzla000.github.io/blog/index.html (the main page) was:

(function (window) {
    var INSIGHT_CONFIG = {
        TRANSLATION: {
            POSTS: 'Posts',
            PAGES: 'Pages',
            CATEGORIES: 'Categories',
            TAGS: 'Tags',
            UNTITLED: '(Untitled)',
        },
        ROOT_URL: '/blog/',
        CONTENT_URL: '/content.json',
    };
    window.INSIGHT_CONFIG = INSIGHT_CONFIG;
})(window);

, which loaded https://wlzla000.github.io/content.json (the wrong one).

And the generated script for https://wlzla000.github.io/blog/cjcgb6bwy00000k3416a3v59n/ (the Hello world article) was:

(function (window) {
    var INSIGHT_CONFIG = {
        TRANSLATION: {
            POSTS: 'Posts',
            PAGES: 'Pages',
            CATEGORIES: 'Categories',
            TAGS: 'Tags',
            UNTITLED: '(Untitled)',
        },
        ROOT_URL: '/blog/',
        CONTENT_URL: '../content.json',
    };
    window.INSIGHT_CONFIG = INSIGHT_CONFIG;
})(window);

, which loaded https://wlzla000.github.io/blog/cjcgb6bwy00000k3416a3v59n/../content.json (the right one).


The way in which they are generated

According to the hueman/layout/search/insight.ejs file that generates such scripts above:

<div class="ins-search">
    <div class="ins-search-mask"></div>
    <div class="ins-search-container">
        <div class="ins-input-wrapper">
            <input type="text" class="ins-search-input" placeholder="<%= __('insight.hint') %>" />
            <span class="ins-close ins-selectable"><i class="fa fa-times-circle"></i></span>
        </div>
        <div class="ins-section-wrapper">
            <div class="ins-section-container"></div>
        </div>
    </div>
</div>
<script>
(function (window) {
    var INSIGHT_CONFIG = {
        TRANSLATION: {
            POSTS: '<%= __("insight.posts") %>',
            PAGES: '<%= __("insight.pages") %>',
            CATEGORIES: '<%= __("insight.categories") %>',
            TAGS: '<%= __("insight.tags") %>',
            UNTITLED: '<%= __("insight.untitled") %>',
        },
        ROOT_URL: '<%= config.root %>',
        CONTENT_URL: '<%- url_for("/content.json")%>',
    };
    window.INSIGHT_CONFIG = INSIGHT_CONFIG;
})(window);
</script>
<%- js('js/insight') %>

, the CONTENT_URL is generated by url_for("/content.json"), which is one of the Hexo's helper functions.


And according to the hexo/lib/plugins/helper/url_for.js:

'use strict';

var url = require('url');
var _ = require('lodash');

function urlForHelper(path, options) {
  path = path || '/';

  if (path[0] === '#' || path.substring(0, 2) === '//') {
    return path;
  }

  var config = this.config;
  var root = config.root;
  var data = url.parse(path);

  options = _.assign({
    relative: config.relative_link
  }, options);

  // Exit if this is an external path
  if (data.protocol) {
    return path;
  }

  // Resolve relative url
  if (options.relative) {
    return this.relative_url(this.path, path);
  }

  // Prepend root path
  path = root + path;

  return path.replace(/\/{2,}/g, '/');
}

module.exports = urlForHelper;

and hexo/lib/plugins/helper/relative_url.js:

'use strict';

function relativeUrlHelper(from, to) {
  from = from || '';
  to = to || '';

  var fromParts = from.split('/');
  var toParts = to.split('/');
  var length = Math.min(fromParts.length, toParts.length);
  var i = 0;

  for (; i < length; i++) {
    if (fromParts[i] !== toParts[i]) break;
  }

  var out = toParts.slice(i);

  for (var j = fromParts.length - i - 1; j > 0; j--) {
    out.unshift('..');
  }

  var outLength = out.length;

  // If the last 2 elements of `out` is empty strings, replace them with `index.html`.
  if (outLength > 1 && !out[outLength - 1] && !out[outLength - 2]) {
    out = out.slice(0, outLength - 2).concat('index.html');
  }

  return out.join('/').replace(/\/{2,}/g, '/');
}

module.exports = relativeUrlHelper;

,

url_for("/content.json") is:

For relative_link: true in _config.yml relative_link: false in _config.yml
/blog/index.html relative_url("index.html" (root-relative path), "/content.json") → "/content.json" "/blog/" (root) +"/content.json" → "/blog/content.json"
/blog/cjcgb6bwy00000k3416a3v59n/ relative_url("cjcgb6bwy00000k3416a3v59n/" (root-relative path), "/content.json") → "../content.json" "/blog/" (root) +"/content.json" → "/blog/content.json"

So the problem here is that, url_for() returns its argument unchanged if you specify both relative_link: true and root: / in the _config.yml, and it returns a totally-messed-up URI if you set relative_link to be true and the root to be anything deeper than /. However, neither of them is desirable.


Conclusion

I'm not sure but it might be a bug of the relative_url() function. The possible solution that is currently available is to disable the relative_link option.

ppoffice commented 6 years ago

@wlzla000 Yes. This logic of url_for is quite obscure. You need to set relative_link to false, as it is in the example site: https://github.com/ppoffice/hexo-theme-hueman/blob/site/_config.yml#L38