点击查看更新记录

更新记录

2020-12-08:内测版v0.01

  1. 将优化日记中的简略内容移至本帖。
  2. 对原内容进行拓展,讲解具体操作步骤。
  3. 拓展jsdelivr,imagine,gulp的使用方法。

2020-12-09:内测版v0.02

  1. 描述css的合并方式。
  2. 拓展利用defer异步加载自定义第三方js加载顺序。
点击查看参考教程
参考方向教程原贴
JsDelivr官网JsDelivr : A free CDN for Open Source
参考了jsdelivr的使用方案小康博客-优雅使用JsDeliver加速文件
参考了Gulp压缩的基本方案Butterfly主题文档-Gulp压缩
参考了gulp的优化方案卓越科技-如何优化博客
参考了Jsdelivr的刷新方案二兔-解决jsdelivr缓存问题的几个办法
待定,无法确定该方案是否存在优越性CC康纳百川-博客图片的 webp 之路
参考了stylus语法Stylus官方文档

CDN加速

jsdelivr是一个免费的CDN服务,可以利用它配合github来为页面静态资源提供加速,有效提升资源加载速度。

关于Jsdelivr的使用可以直接观看小康大佬的教程-优雅使用JsDeliver加速文件

图片资源加速

压缩图片

压缩图片分为有损压缩和无损压缩。无损压缩推荐Tinypng,有损压缩推荐imagine

TinyPNGImagine
特点无损压缩有损压缩,以牺牲图像质量,
降低图像色彩来达到缩减图像大小的目的。
优点能够完全保留图像色彩,不损伤图像质量1. 压缩程度高,支持转pngjpgwebp,进一步减少图片大小
2. 软件支持一次处理多张图片,无上限,处理完成支持直接批量覆盖原文件或重命名
缺点单次仅能上传20张图片,每张限制大小为5MB,无法处理更大图片。PNG转其他格式为不可逆操作(指覆盖保存后),且可能反而会增加图片大小。

使用建议:如果没有特别要求,直接使用Imagine进行有损压缩即可。虽然说是有损压缩,但是默认压缩会自主计算压缩程度,一般默认程度就能节省70%空间,且肉眼几乎发现不了图片压缩情况。

lighthouse评测推荐使用webp格式图片毕竟都是自家的标准当然要夹带点私活,但是对webp格式图片的浏览器支持依然没有完全普及,在一些未适配的浏览器上(IE:没错,就是老子还在坚持)可能出现无法查看图片的情况,请酌情使用。

Gulp压缩全站静态资源

gulp能够帮助用户自动压缩静态资源,配合各类下属插件,能够压缩包括css、js、html乃至各类格式的图片文件。(图片文件的压缩效果远远不如上文提到的imagine软件,所以此处不再写使用gulp压缩图片的内容)。

  1. 安装Gulp插件:在博客根目录[Blogroot]打开终端,输入:
    npm install --global gulp-cli
  2. 安装各个下属插件以实现对各类静态资源的压缩。在此高呼卓越科技NB!

    • 压缩HTML:
      npm install gulp-htmlclean --save-dev
      npm install gulp-html-minifier-terser --save-dev
      # 用gulp-html-minifier-terser可以压缩HTML中的ES6语法
    • 压缩CSS:
      npm install gulp-clean-css --save-dev
    • 压缩JS
      npm install --save-dev gulp-uglify
      npm install --save-dev gulp-babel @babel/core @babel/preset-env

      Butterfly主题文档还提供了另一种使用terser压缩JS的插件方案。两者的差别在于terser是ES6+的JavaScript解析器,而gulp-babel是一个JavaScript转换编译器,可以把ES6转换成ES5,两种方案都有效。考虑到有些浏览器不支持ES6,IE:没错,又是老子,此处选择gulp-babel

  3. 为Gulp创建gulpfile.js任务脚本。在博客根目录[Blogroot]下新建gulpfile.js,打开[Blogroot]\gulpfile.js,输入以下内容:

    //用到的各个插件
    var gulp = require('gulp');
    var cleanCSS = require('gulp-clean-css');
    var htmlmin = require('gulp-html-minifier-terser');
    var htmlclean = require('gulp-htmlclean');
    var uglify = require('gulp-uglify')
    var babel = require('gulp-babel')
    //压缩js
    gulp.task('compress', () =>
    gulp.src(['./public/**/*.js', '!./public/**/*.min.js'])
    .pipe(babel({
    presets: ['@babel/preset-env']
    }))
    .pipe(uglify().on('error', function (e) {
    console.log(e)
    }))
    .pipe(gulp.dest('./public'))
    )
    //压缩css
    gulp.task('minify-css', () => {
    return gulp.src(['./public/**/*.css'])
    .pipe(cleanCSS({
    compatibility: 'ie11'
    }))
    .pipe(gulp.dest('./public'));
    });
    //压缩html
    gulp.task('minify-html', () => {
    return gulp.src('./public/**/*.html')
    .pipe(htmlclean())
    .pipe(htmlmin({
    removeComments: true, //清除html注释
    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"
    minifyJS: true, //压缩页面 JS
    minifyCSS: true, //压缩页面 CSS
    minifyURLs: true //压缩页面URL
    }))
    .pipe(gulp.dest('./public'))
    });

    // 运行gulp命令时依次执行以下任务
    gulp.task('default', gulp.parallel(
    'compress', 'minify-css', 'minify-html'
    ))
  4. 在每次运行完hexo generate生成静态页面后,运行gulp对其进行压缩。指令流程如下:

    hexo clean
    hexo generate
    gulp
    hexo server 或 hexo deploy
  5. 可能出现的bug,毕竟是bug御三家,没点bug都不好意思出来混
    部分js经过gulp-babel的压缩加密后,可能无法正常使用,报错一般为提示该js中的某个变量未被声明。最快的解决方案就是干脆不要压缩它,对它设置压缩屏蔽。
    此处举例,假设使用gulp压缩后,位于/source/js/example.js无法正常使用。则在[Blogroot]\gulpfile.js中修改js压缩任务的相关配置

          //压缩js
    gulp.task('compress', () =>
    - gulp.src(['./public/**/*.js', '!./public/**/*.min.js'])
    + gulp.src(['./public/**/*.js', '!./public/**/*.min.js','!./public/js/example.js'])
    .pipe(babel({
    presets: ['@babel/preset-env']
    }))
    .pipe(uglify().on('error', function (e) {
    console.log(e)
    }))
    .pipe(gulp.dest('./public'))
    )

以下内容针对第三方魔改方案进行优化适配。原生主题用户无需在意。

合并CSS以减少请求次数

以下内容仅针对butterfly主题。其他主题可以理解原理后进行操作。实际上就是使用@import引入自定义样式。以下内容在Hexo异步加载方案中亦有提及。

将魔改样式整合到index.css文件内,减少对服务器的请求次数。能够节省大量加载时间。

我的做法如下:

  1. [Blogroot]\themes\butterfly\source\css\路径下新建_custom文件夹,然后把魔改样式的CSS文件拖动进去。文件目录层级可以表示为以下情况:

    source
    |__ css
    |__ _custom
    |__ custom1.css
    |__ custom2.css
    |__ custom3.css
    |__ index.styl
  2. [[Blogroot]\themes\butterfly\source\css\index.styl中新增一行代码:@import '_custom/*.css',表示引入_custom文件夹下的所有CSS文件。

        @import 'nib'
    @import '_third-party/*.css'
    + @import '_custom/*.css'
    // project
    @import 'var'
    @import '_global/*'
    @import '_highlight/highlight'
    @import '_page/*'
    @import '_layout/*'
    @import '_tags/*'
    @import '_mode/*'
  3. 如果是使用的外链css,也可以在这里引入。同样是修改 [Blogroot]\themes\butterfly\source\css\index.styl代码,使用@import逐行引入:
        @import 'nib'
    @import '_third-party/*.css'
    + @import 'https://cdn.jsdelivr.net/gh/username/repo/css/example.css'
    // project
    @import 'var'
    @import '_global/*'
    @import '_highlight/highlight'
    @import '_page/*'
    @import '_layout/*'
    @import '_tags/*'
    @import '_mode/*'
  4. 这样一来,每个魔改方案的CSS依然可以在独立的CSS文件中找到并修改(如果是手动添加整合的话,只能用注释分割,显然很不利于后续查找修改),而在每次提交时,运行hexo g的过程中就会将所有CSS文件都整合到index.css,可以在主题配置文件的CDN配置项里给index.css加上jsdelivr进一步提升加载速度(注意刷新jsdelivr的缓存)。

  5. 样式选择性加载方案:

    此条对部分魔改用户来说有画蛇添足之嫌,毕竟这里的操作通过移除相应css文件同样可以做到,只不过博主期望能够让魔改方案更加接近原生主题体验并为魔改方案插件化做准备,谨以此给更多魔改开发者以启发。

    若是单纯的整合,对于锱铢必较的我来说还是不够的。很多第三方魔改方案中都有涉及侧边栏改造的部分,当我们有一天想要暂时关闭一个侧栏,那么直接修改card_XXXX.enable的值为false,这么做确实可以不加载侧边栏结构了,但是CSS依然是引入的。此处参考butterfly原生主题的方案,可以将那个css转化成styl以后在最上方添加if hexo-config('aside.card_XXXX.enable')的判断,当enable的值为false,自然也就不会加载下方的样式。
    例如对侧栏电子钟的样式进行修改,clock.styl文件开头形似如下格式:

    if hexo-config('aside.card_clock.enable')
    #clock
    .clockdate
    font-family 'UnidreamLED'
    font-size 14px
    font-weight normal
    color #000000
    margin-block-start 0em

    注意观察index.styl中使用@import批量引入的写法。要注意将css文件和styl放在不同文件夹。css使用@import '[path]/*.css'引入,而styl则是使用@import '[path]/*'引入

    事实上,并不一定非要将css转为styl,毕竟stylus兼容css语法,只是出于对缩进的严格控制考虑才这么做。毕竟纯净而优雅的语法结构有助于后续开发。

调整第三方JS加载位置

在魔改过程中,不可避免的要加载诸多的第三方js,为了加快页面编译速度,可以用异步加载以减少HTML阻塞,也可以将多个js文件合并成一个以减少请求次数。但是这两种方法会有个弊端。

例如我在主页面放置了card_artitalk侧栏说说插件,而artitalkkey.js是在inject配置项中全局引入,那么,当我切换到文章页后,card_artitalkHTML结构不再出现,但是artitalkkey.js却依然引入,连带着让控制台抛出一堆找不到相应HTML结构的报错。

所以此处提供一种思路,将js添加到各自的插件pug下,即可确保js只在有相应页面结构出现的时候才会加载。

  1. 还是以card_artitalk为例,首先将修改akritalkkey.jscard_artitalk.js的引入方式:

        inject:
    head:
    bottom:
    - - <script defer src="https://cdn.jsdelivr.net/npm/artitalk"></script>
    - - <script defer src="/js/card_artitalk.js"></script>
    - - <script defer src="/js/akritalkkey.js"></script>
    CDN:
    + card_artitalk: "/js/card_artitalk.js
    + artitalkkey: /js/akritalkkey.js
    artitalk: https://cdn.jsdelivr.net/npm/artitalk
    # 最新版butterfly自带artitalk的CDN配置项
  2. 然后修改card_artitalk.pug,在文件末端添加:

        .card-widget.card-shuo
    .card-content(style='height:auto;min-height:280px;')
    .item-headline
    i.fas.fa-comments
    span= _p('aside.card_shuo')
    a#shuovisualchange(style='cursor:pointer;float:right', onclick='shuovisualchange()') 编辑
    #artitalk_main(style='width:100%;height:100%;padding:1px')
    + script(defer src=url_for(theme.CDN.artitalk))
    + script(defer src=url_for(theme.CDN.card_artitalk))
    + script(defer data-pjax src=url_for(theme.CDN.artitalkkey))

    引入顺序注意不要乱。

  3. 需要注意的是,由于这里还用可能用到jquery或者vue,可以仿照上面两步添加vue的引入。

    • [Blogroot]\_config.butterfly.yml添加vue的CDN配置项:
      CDN:
      vue: https://cdn.jsdelivr.net/npm/vue@2.6.11
    • 修改Blogroot\themes\butterfly\layout\includes\additional-js.pug
          div
      script(src=url_for(theme.CDN.jquery))
      + script(src=url_for(theme.CDN.vue))
      script(src=url_for(theme.CDN.utils))
      script(src=url_for(theme.CDN.main))

      切记,不要给这四个引入项添加任何异步加载标签。

  4. 注意此处的异步加载标签defer起到的作用。
    artitalk相关js引入项添加defer以后,虽然它们在页面的加载位置早于jqueryvue等依赖项,但是因为加了defer的缘故,它们的执行时间将晚于没加任何异步加载标签的jqueryvue等依赖项。从而保证了js的正确执行顺序。
    详情请参阅站内教程:Hexo异步加载方案

TO DO

给静态资源添加jsdelivr以实现CDN加速

对站内图片进行压缩

使用Gulp压缩全站静态资源

合并CSS以减少请求次数

调整第三方JS加载位置