Hexo博客优化


博客优化

当东西多了以后, 博客的运行速度就会被拖慢. 所以优化访问速度是非常有必要的. 本文参考了Yafine这篇博客Sky03博客对访问进行了优化.

图片懒加载

经过多次尝试, 懒加载虽然带来了访问速度的提升, 但即使加大了懒加载的范围, 还是能够看到Loading图, 总是会给人产生一种网速慢的感觉. 对于现在大家的网速来说, 似乎体验的重要性要大于性能的重要性, 建议不开启懒加载.

预加载和懒加载

图片预加载:顾名思义,图片预加载就是在网页全部加载之前,提前加载图片。当用户需要查看时可直接从本地缓存中渲染,以提供给用户更好的体验,减少等待的时间。否则,如果一个页面的内容过于庞大,没有使用预加载技术的页面就会长时间的展现为一片空白,这样浏览者可能以为图片预览慢而没兴趣浏览,把网页关掉,这时,就需要图片预加载。当然这种做法实际上牺牲了服务器的性能换取了更好的用户体验。
图片懒加载(缓载):延迟加载图片或符合某些条件时才加载某些图片。这样做的好处是减少不必要的访问数据库或延迟访问数据库的次数,因为每次访问数据库都是比较耗时的即只有真正使用该对象的数据时才会创建。懒加载的主要目的是作为服务器前端的优化,减少请求数或延迟请求数。

预加载会在用户没看到图片之前, 就将图片显示加载好. 而懒加载恰恰相反, 当用户快要看到图片之前(或满足某个触发条件时), 才会进行加载. 图片是一种非常吃流量的内容, 所以当点入一篇新文章时, 预加载会导致瞬间流量过大, 用户等待的时间会增加. 其实完全没必要让图片在用户看不见的时候就去加载, 最好是用户即将看到图片之前, 再对图片进行加载. 这样可以减缓访问的压力, 提高用户体验.

加入懒加载

懒加载需要安装hexo-lazyload-image插件. 在blog根目录命令行输入:

npm install hexo-lazyload-image --save

然后在Hexo配置文件末尾加入:

lazyload:
  enable: true  # 是否开启图片懒加载
  onlypost: false  # 是否只对文章的图片做懒加载
  loadingImg: # eg ./images/loading.gif

这里的loadingImg路径起始就从主题的source下开始算的.

最后执行hexo clean && hexo g && hexo s就能看到懒加载效果了.

Matery的bug

针对Matery主题这个插件有两个小bug, 感谢原博主的解决.

  1. 查看大图, 发现全是loading加载图:

    原因是因为懒加载插件与 lightgallery 插件冲突. 在 blog\themes\hexo-theme-matery\source\jsmatery.js中,在 108 行左右添加以下代码

    $(document).find('img[data-original]').each(function(){
        $(this).parent().attr("href", $(this).attr("data-original"));
    });
  2. 点击首页 logo 不是跳转到首页, 而是查看 logo 图片:

    修改blog\themes\hexo-theme-matery\layout\ header.ejs.

    <div class="brand-logo">
        <a href="<%- url_for() %>" class="waves-effect waves-light">
             <% if (theme.logo !== undefined && theme.logo.length > 0) { %>
             <img src="<%= theme.logo %>" class="logo-img" alt="LOGO">
             <% } %>
             <span class="logo-span"><%- config.title %></span>
        </a>
    </div>

    修改为:

    <div class="brand-logo">
        <a href="<%- url_for() %>" class="waves-effect waves-light">
            <div>
                <% if (theme.logo !== undefined && theme.logo.length > 0) { %>
                <img src="<%= theme.logo %>" class="logo-img" alt="LOGO">
                <% } %>
                <span class="logo-span"><%- config.title %></span>
            </div>
        </a>
    </div>

懒加载优化

每次加载完后本地应该都会有图片缓存, 但是还是会显示loading的logo. 所以需要对插件进行修改, 提前显示出图片. 打开blogtest\node_modules\hexo-lazyload-image\lib\simple-lazyload.js, 第九行修改为:

&& rect.top <= (window.innerHeight + 360 || document.documentElement.clientHeight + 360)

能够在图片前360个pix加载图片, 我这里试了试360效果比较好, 可以自行修改.

代码压缩

其实Hexo生成的所有html, css, js全是有空行和空格的, 但是空格和空行是需要占用空间的. 这就是为什么js总是发布一个完整版和一个min版, min版是压缩后的, 不利于代码的阅读, 但是使用起来会比原版快. 我这里网络问题很大, cnpm安装这个库有各种权限问题, 所以就没有采用gulp的方式. 如果没有条件建议尝试hexo-neat, 比较简单快捷. 我没有对比过二者的压缩效率, 但后者对某些比较大的文件能够压缩38.13%左右的空间, 效果已经很不错了.

gulp

利用gulp进行代码的压缩. 先在博客根目录下安装好gulp:

# 全局安装gulp模块
npm install gulp -g
# 安装各种小功能模块  执行这步的时候,可能会提示权限的问题,最好以管理员模式执行
npm install gulp gulp-htmlclean gulp-htmlmin gulp-minify-css gulp-uglify gulp-imagemin --save
# 额外的功能模块
npm install gulp-debug gulp-clean-css gulp-changed gulp-if gulp-plumber gulp-babel babel-preset-es2015 del @babel/core --save

在博客根目录下创建gulpfile.js(必须是这个文件名), 并复制以下内容:

var gulp = require("gulp");
var debug = require("gulp-debug");
var cleancss = require("gulp-clean-css"); //css压缩组件
var uglify = require("gulp-uglify"); //js压缩组件
var htmlmin = require("gulp-htmlmin"); //html压缩组件
var htmlclean = require("gulp-htmlclean"); //html清理组件
var imagemin = require("gulp-imagemin"); //图片压缩组件
var changed = require("gulp-changed"); //文件更改校验组件
var gulpif = require("gulp-if"); //任务 帮助调用组件
var plumber = require("gulp-plumber"); //容错组件(发生错误不跳出任务,并报出错误内容)
var isScriptAll = true; //是否处理所有文件,(true|处理所有文件)(false|只处理有更改的文件)
var isDebug = true; //是否调试显示 编译通过的文件
var gulpBabel = require("gulp-babel");
var es2015Preset = require("babel-preset-es2015");
var del = require("del");
var Hexo = require("hexo");
var hexo = new Hexo(process.cwd(), {}); // 初始化一个hexo对象

// 清除public文件夹
gulp.task("clean", function () {
    return del(["public/**/*"]);
});

// 下面几个跟hexo有关的操作,主要通过hexo.call()去执行,注意return
// 创建静态页面 (等同 hexo generate)
gulp.task("generate", function () {
    return hexo.init().then(function () {
        return hexo
            .call("generate", {
                watch: false
            })
            .then(function () {
                return hexo.exit();
            })
            .catch(function (err) {
                return hexo.exit(err);
            });
    });
});

// 启动Hexo服务器
gulp.task("server", function () {
    return hexo
        .init()
        .then(function () {
            return hexo.call("server", {});
        })
        .catch(function (err) {
            console.log(err);
        });
});

// 部署到服务器
gulp.task("deploy", function () {
    return hexo.init().then(function () {
        return hexo
            .call("deploy", {
                watch: false
            })
            .then(function () {
                return hexo.exit();
            })
            .catch(function (err) {
                return hexo.exit(err);
            });
    });
});

// 压缩public目录下的js文件
gulp.task("compressJs", function () {
    return gulp
        .src(["./public/**/*.js", "!./public/libs/**"]) //排除的js
        .pipe(gulpif(!isScriptAll, changed("./public")))
        .pipe(gulpif(isDebug, debug({ title: "Compress JS:" })))
        .pipe(plumber())
        .pipe(
            gulpBabel({
                presets: [es2015Preset] // es5检查机制
            })
        )
        .pipe(uglify()) //调用压缩组件方法uglify(),对合并的文件进行压缩
        .pipe(gulp.dest("./public")); //输出到目标目录
});

// 压缩public目录下的css文件
gulp.task("compressCss", function () {
    var option = {
        rebase: false,
        //advanced: true, //类型:Boolean 默认:true [是否开启高级优化(合并选择器等)]
        compatibility: "ie7" //保留ie7及以下兼容写法 类型:String 默认:''or'*' [启用兼容模式; 'ie7':IE7兼容模式,'ie8':IE8兼容模式,'*':IE9+兼容模式]
        //keepBreaks: true, //类型:Boolean 默认:false [是否保留换行]
        //keepSpecialComments: '*' //保留所有特殊前缀 当你用autoprefixer生成的浏览器前缀,如果不加这个参数,有可能将会删除你的部分前缀
    };
    return gulp
        .src(["./public/**/*.css", "!./public/**/*.min.css"]) //排除的css
        .pipe(gulpif(!isScriptAll, changed("./public")))
        .pipe(gulpif(isDebug, debug({ title: "Compress CSS:" })))
        .pipe(plumber())
        .pipe(cleancss(option))
        .pipe(gulp.dest("./public"));
});

// 压缩public目录下的html文件
gulp.task("compressHtml", function () {
    var cleanOptions = {
        protect: /<\!--%fooTemplate\b.*?%-->/g, //忽略处理
        unprotect: /<script [^>]*\btype="text\/x-handlebars-template"[\s\S]+?<\/script>/gi //特殊处理
    };
    var minOption = {
        collapseWhitespace: true, //压缩HTML
        collapseBooleanAttributes: true, //省略布尔属性的值 <input checked="true"/> ==> <input />
        removeEmptyAttributes: true, //删除所有空格作属性值 <input id="" /> ==> <input />
        removeScriptTypeAttributes: true, //删除<script>的type="text/javascript"
        removeStyleLinkTypeAttributes: true, //删除<style>和<link>的type="text/css"
        removeComments: true, //清除HTML注释
        minifyJS: true, //压缩页面JS
        minifyCSS: true, //压缩页面CSS
        minifyURLs: true //替换页面URL
    };
    return gulp
        .src("./public/**/*.html")
        .pipe(gulpif(isDebug, debug({ title: "Compress HTML:" })))
        .pipe(plumber())
        .pipe(htmlclean(cleanOptions))
        .pipe(htmlmin(minOption))
        .pipe(gulp.dest("./public"));
});

// 压缩 public/medias 目录内图片
gulp.task("compressImage", function () {
    var option = {
        optimizationLevel: 5, //类型:Number 默认:3 取值范围:0-7(优化等级)
        progressive: true, //类型:Boolean 默认:false 无损压缩jpg图片
        interlaced: false, //类型:Boolean 默认:false 隔行扫描gif进行渲染
        multipass: false //类型:Boolean 默认:false 多次优化svg直到完全优化
    };
    return gulp
        .src("./public/medias/**/*.*")
        .pipe(gulpif(!isScriptAll, changed("./public/medias")))
        .pipe(gulpif(isDebug, debug({ title: "Compress Images:" })))
        .pipe(plumber())
        .pipe(imagemin(option))
        .pipe(gulp.dest("./public"));
});
// 执行顺序: 清除public目录 -> 产生原始博客内容 -> 执行压缩混淆 -> 部署到服务器
gulp.task(
    "build",
    gulp.series(
        "clean",
        "generate",
        "compressHtml",
        "compressCss",
        "compressJs",
        "compressImage",
        gulp.parallel("deploy")
    )
);

// 默认任务
gulp.task(
    "default",
    gulp.series(
        "clean",
        "generate",
        gulp.parallel("compressHtml", "compressCss", "compressJs","compressImage")
    )
);
//Gulp4最大的一个改变就是gulp.task函数现在只支持两个参数,分别是任务名和运行任务的函数

最后在根目录下命令行输入gulp或者gulp default, 相当于输入了hexo cl && hexo g, 然后再压缩图片和代码.

hexo-neat

使用hexo-neat更为简单, 美中不足的是这个插件有俩小bug:

  • 压缩.md文件会使 markdown 语法的代码块消失.
  • 会删除全角空格.

但是它避免了国内npm的使用问题. 所以我推荐这种方式.

在博客根目录命令行输入:

npm install hexo-neat --save

然后在Hexo配置文件末尾加入(已针对matery的bug优化):

#hexo-neat 优化提速插件(去掉HTML、css、js的blank字符)
neat_enable: true
neat_html:
  enable: true
  exclude:
    - '**/*.md'
neat_css:
  enable: true
  exclude:
    - '**/*.min.css'
neat_js:
  enable: true
  mangle: true
  output:
  compress:
  exclude:
    - '**/*.min.js'
    - '**/**/instantpage.js'
    - '**/matery.js'

CDN加速

因为Github在国内访问速度比较慢, 所以用CDN加速来优化网站访问速度. jsDelivr + Github就能免费实现博客网站的访问加速.

CDN 的全称是 Content Delivery Network,即内容分发网络。CDN 是构建在网络之上的内容分发网络,依靠部署在各地的边缘服务器,通过中心平台的负载均衡、内容分发、调度等功能模块,使用户就近获取所需内容,降低网络拥塞,提高用户访问响应速度和命中率。

在Matery主题的配置文件末尾已经有相应的配置:

jsDelivr:
  url: #https://cdn.jsdelivr.net/gh//

配置文件中有关于jsDelivr相应的注释, 即在内容没有被部署到github仓库之前, 是没法使用cdn在本地查看效果的, 只有部署之后才能看到效果.

CDN访问加速
第一次使用本功能,一定要先配置url,再hexo cl && hexo g && hexo d部署到GitHub的仓库,注意!必须是GitHub的仓库!
如果必须要使用国内的coding或者gitee,可以采用双部署,同时将网站部署到两个仓库(其中一个必须是GitHub的仓库)
URL配置规则(例子如下): https://cdn.jsdelivr.net/gh/你的GitHub用户名/你的仓库名
如果想关闭此功能,将 url地址 注释或删除即可!

注:配置了此项,就代表着本地调试的时候,网站依然会去GitHub请求资源(原来的资源),本地调试的时候记得将 此项配置 注释或者删除掉.

jsDelivr 不支持加载超过 20M 的资源.


文章作者: DaNing
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 DaNing !
评论
 上一篇
操作系统常见问题整理 操作系统常见问题整理
操作系统操作系统问的比较多的就是进程线程的区别, 作业调度算法, 分页分段, 死锁很关键, 假脱机这部分也需要重视起来. 文中有部分算法的细节没有提到, 只是列出来名字, 需要自己补充. 当时整理的排版可能比较乱, 以后有空再整理. 计算机
2020-07-27
下一篇 
CSS样式覆盖 CSS样式覆盖
CSS样式覆盖覆盖今天下午想给博客配个在线Markdown的小工具, 按照教程搭配完了, 结果发现这行高简直欺骗感情. 明明这位博主的在线Markdown和editormd官方的行距就是正常的, 怎么到我这就开始变宽了呢? 在一轮乱搞
2020-07-25
  目录