Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

hexo g的效率问题 #13

Closed
lewky opened this issue Sep 18, 2018 · 10 comments
Closed

hexo g的效率问题 #13

lewky opened this issue Sep 18, 2018 · 10 comments

Comments

@lewky
Copy link

lewky commented Sep 18, 2018

大佬,我可以厚颜无耻地提个性能方面的issue吗?
是这样的,在使用hexo-neat进行压缩的时候,我需要花费至少三分钟的时间,如果不压缩的话只要几十秒就可以了。
我看hexo-neat在压缩页面时,分别压缩了html, swig, js, css, md等文件;这些花费了大量的时间,swig和md文件只是模板和初始文件而已,应该没有必要去压缩的吧,能不能改成只对生成后的html静态页面进行压缩呢?
因为我发现一旦使用了neat_html:里的exclude来排除掉md和swig文件,会导致最后的html是没有被压缩的,而且当md文件里使用到了next主题自带的tab标签,还会有语法错误导致压缩失败。。

@kainy
Copy link

kainy commented Mar 10, 2019

还有一个html首尾注释时间戳的问题,发布后会导致所有页面缓存失效。

@du33169
Copy link

du33169 commented Jun 13, 2019

一个比较土的解决方法:将_config.yml中的neat_enable设为false,然后将其复制一份(例如neat.yml),在neat.yml中将neat_enable设为true。

这样在平时hexo g的时候不会压缩保证效率,在需要部署的时候可以用hexo g --config neat.yml

缺点是要保持两个配置文件同步,可以用脚本实现。

@yansheng836
Copy link

(如果不执行hexo clean的话)好像原版的hexo g是只处理有变化的文件,但是添加插件后好像全部都处理,然后就导致速度慢,有没有办法改善啊?

@inkss
Copy link

inkss commented Dec 31, 2019

我重新分析了下,可以确定两点:

  • 在压缩主题中的模板时花费了大量的时间,多次的压缩。
  • 模板中,有些是重复的相同压缩,有些是因为页面变量的原因,内容不同。

重复压缩

内容不同的无法处理,因为确实是不同,所以就想办法让内容相同的,从多次压缩改成一次压缩,将压缩后的内容存储起来,下次遇见直接调用。所以这里的判断我是分两部分:1.判断当前被压缩的文件是否是模板文件,2.判断压缩的内容是否相同(这里是直接简单的判断了内容的长度),大致的代码如下:

var html_map = new Map(); // 全局变量
function logic_html(str, data) {
    //...
    var path = data.path == null ? "no_path_value.ejs" : data.path;
    var exclude = options.exclude;

    var tempMap;  // 临时变量
    var checkFlag = minimatch(path, "**/*.ejs");  // 模板文件
    if(checkFlag){  // 模板内容
        if(html_map.has(path)){ // 如果存在相同路径
            tempMap = new Map(html_map.get(path));  // 取值
            if(tempMap.has(str.length))  // 判断是相同的长度
                return tempMap.get(str.length);  // 直接返回值
        } else tempMap = new Map();
    }

    //...
    var log = hexo.log || console.log;
    var result = Htmlminifier(str, options);
    if(checkFlag){  // 只记录模板文件的内容
        tempMap.set(str.length,result);  // 存储压缩后的内容
        html_map.set(path,tempMap);  // 存放到全局变量中
    }
    var saved = ((str.length - result.length) / str.length * 100).toFixed(2);
    log.log('neat the html: %s [ %s saved]', path, saved + '%');
    return result;
};

这里,我只开启了 html 文件的压缩(jscss 可以用 jsdelivr 的 CDN),修改前生成用时:15s

image

修改后,生成用时:5.93s ,效果显著,啊哈哈。

image


好了,这次才算是完全修改,完结撒花~

@yansheng836
Copy link

@inkss 你好,能请教下你,具体是改哪个文件吗?

我的重复压缩模板文件,(大概100+博客)好像耗时半个小时以上了。

@ohroy
Copy link
Owner

ohroy commented Jul 22, 2020

今天抽空看了下这个问题。先说结论:这里其实是有两个问题:一是重复渲染,二是重复生成。重复渲染是hexo设计缺陷,重新生成是本插件画蛇添足。而这两者导致变慢的罪魁祸首是重复渲染。

问题分析记录

从名字上来看,本插件注册的filterafter_render:html,即为渲染后执行的意思。为什么一篇文章会被重复渲染呢?本文记录调试分析。

一,旧的检测检测资源是否被修改的方式

https://github.com/hexojs/hexo/blob/850ffbcb157c51268b0a4b9c88bd46cca56bbcc2/lib/plugins/console/generate.js#L41
插件只有在下面的 writeFile 函数里才会被调用,按道理说,这里假如不传递force,并且文件已经存在,并且文件没有被修改,就一定不会传递给插件,自然就没有后续问题了。

但实情是isModfied永远为true,除非将文件类型设置为skip。因此,所有文章就必定会经过渲染,无论使用本插件与否

二,生成文章与否的判断

上面有同学也提到了,假如不实用本插件的话,就没有问题。其实这个话是不严谨的,无论使用与否,都存在问题,只是本插件放大了此问题。(hexo原有体系在渲染时不会输出,所以用户无法感知。本插件在文章比较多时,压缩会比较慢。)

但无论如何,不使用本插件时,hexo不会重新生成文件。 这个结论是正确的,但是为什么会这样呢?继续往下分析
https://github.com/hexojs/hexo/blob/850ffbcb157c51268b0a4b9c88bd46cca56bbcc2/lib/plugins/console/generate.js#L76
这里可以清楚的看到,hexo使用hash对生成后的文件进行了hash校验,假如他们一致则不重新生成。
至此,问题已经一目了然了。那就是hexo在设计时并未考虑到插件可能会修改渲染后的内容,导致此处判断形同虚设。一个完整的流程是
hexo g -> 这里有缺陷,导致无条件渲染->hexo渲染后交由插件渲染->插件渲染后交由hexo生成->hexo判断渲染后的结果,发现与缓存的不一致->重新生成
而正常的流程是
hexo g -> 这里有缺陷,导致无条件渲染->hexo渲染后交由hexo生成->hexo判断渲染后的结果,发现与缓存一致->不重新生成

这里要想和保持和hexo的结果一致,就需要保证插件每次渲染后的结果要一致,而显然可能是结果不一致的。经过分析,最终发
https://github.com/rozbo/hexo-neat/blob/5819ebed6fc2a1104675b5c488aa3e56ed8779c6/lib/filter.js#L32
此处导致的每次生成的最终文件不一致,导致每次需要重新生成,去掉即可解决每次重新生成的问题

至于重复渲染,hexo并未提供相应的接口或者方式能解决此问题,我将尝试自行造轮子解决。

@inkss
Copy link

inkss commented Jul 22, 2020

没用的,hexo clean 后就全没了,我上面的观点也有不对的地方,主要是 不同页面间有可能传递参数(无法判断同一路径下的相同模板文件是否相同(接收参数的部分)

@inkss
Copy link

inkss commented Jul 22, 2020

除非是改变监听方式,对渲染完成后的完整的 html 文件执行压缩

@ohroy
Copy link
Owner

ohroy commented Jul 22, 2020

除非是改变监听方式,对渲染完成后的完整的 html 文件执行压缩

现在就是监听的渲染完成,但问题是hexo本身是无差别渲染的。

@ohroy
Copy link
Owner

ohroy commented Jul 22, 2020

为了解决这个问题,我又新造了一个轮子
https://github.com/rozbo/hexo-cute,
相关问题可以在那里讨论。

@ohroy ohroy closed this as completed Jul 22, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

6 participants