如何优化博客

请注意、本篇文章介绍的只是如何优化、并不包含其中的原理、并且优化只做参考

我的博客是部署在 Github + Vercel、Jsdelivr加速静态资源的

在我的一番打磨下、博客的访问速度较为流畅、在谷歌测速网上的跑分也挺不错的(当然跑分只是一个参考)、在Butterfly主题作者dev的一次更新中:feat: 去除 jQuery (fancybox和圖庫 仍需要加載jQuery)、去除了jQuery。跑分也再一次提升。接下来介绍我是通过哪些方面来优化博客。使用cdn加速、压缩静态资源、异步加载。

CDN

CDN(内容发布网络)是一组分布在多个不同地理位置的Web服务器,用于更加有效地向用户发布内容。在优化性能时,向特定用户发布内容的服务器的选择基于对网络慕课拥堵的测量。例如,CDN 可能选择网络阶跃数最小的服务器,或者具有最短响应时间的服务器。

以Hexo博客(Butterfly)为例、通过hexo s生成的静态资源会存放在img、css、js目录下、托管在网站中直接访问静态资源速度要较慢点、所以我们会采取引入 CDN 来解决。推荐使用jsdelivr、具体如何使用可以通过搜索引擎来解决。

针对静态资源

例如我的配置文件、使用的是我博客里的地址:(自己可以改成自己的仓库地址)

_config.Butterfly.yml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# cdn
# Don't modify the following settings unless you know how they work
# 非必要請不要修改
cdn:
# main
main_css: https://cdn.jsdelivr.net/gh/zykjofficial/zykjofficial.github.io@master/css/index.css
jquery: https://cdn.jsdelivr.net/npm/jquery@latest/dist/jquery.min.js
main: https://cdn.jsdelivr.net/gh/zykjofficial/zykjofficial.github.io@master/js/main.js
utils: https://cdn.jsdelivr.net/gh/zykjofficial/zykjofficial.github.io@master/js/utils.js

# ...

# search
local_search: https://cdn.jsdelivr.net/gh/zykjofficial/zykjofficial.github.io@master/js/search/local-search.js
algolia_js: https://cdn.jsdelivr.net/gh/zykjofficial/zykjofficial.github.io@master/js/search/algolia.js

# ...

# Conversion between Traditional and Simplified Chinese
translate: https://cdn.jsdelivr.net/gh/zykjofficial/zykjresource@master/js/tw_cn.js

# ...

需要静态加速的有:main_css、main、utils、local_search 或者 algolia_js、translate。但是要注意、主题更新时静态资源不可能第一时间更新、如jsdelivr上的资源可能会有一天以上的缓存、这时可以强制刷新(purge)

例如:

1
https://cdn.jsdelivr.net/gh/zykjofficial/zykjofficial.github.io@master/js/main.js

通过将gcore替换成purge、带purge的链接只是用来刷新

1
https://purge.jsdelivr.net/gh/zykjofficial/zykjofficial.github.io@master/js/main.js

看到返回的json数据中显示的状态是OK、就可以重新访问https://cdn.jsdelivr.net/gh/zykjofficial/zykjofficial.github.io@master/js/main.js

针对全站加速

当然以上操作看起来有些麻烦。如果备案了可以使用又拍云等一系列CDN加速服务商、可以对全站进行加速。

压缩静态资源

  • 压缩CSS和JS用的是Gulp

    参考Butterfly作者的教程:https://butterfly.js.org/posts/4073eda/#Gulp%E5%A3%93%E7%B8%AE

    1. 安装Gulp

      1
      2
      npm install -g gulp-cli 
      npm install gulp --save-dev
    2. 安装压缩HTML、CSS、JS

      压缩HTML gulp-html-minifier-terser可以压缩HTML里的ES6语法

      1
      2
      npm install gulp-htmlclean --save-dev
      npm install gulp-html-minifier-terser --save-dev

      压缩CSS

      1
      npm install gulp-clean-css --save-dev

      压缩JS

      1
      2
      npm install --save-dev gulp-uglify
      npm install --save-dev gulp-babel @babel/core @babel/preset-env
    3. 创建 gulpfile 文件

      在博客根目录下创建gulpfile.js

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      31
      32
      33
      34
      35
      36
      37
      38
      39
      40
      41
      42
      43
      44
      45
      46
      47
      48
      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')

      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'))
      )

      gulp.task('minify-css', () => {
      return gulp.src(['./public/**/*.css'])
      .pipe(cleanCSS({
      compatibility: 'ie11'
      }))
      .pipe(gulp.dest('./public'));
      });

      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
      }))
      .pipe(gulp.dest('./public'))
      });

      // 执行 gulp 命令时执行的任务
      gulp.task('default', gulp.parallel(
      'compress', 'minify-css', 'minify-html'
      ))
    4. 运行

      在hexo g之后运行gulp就行

      1
      gulp

      完整命令:

      1
      hexo cl && hexo g && gulp
  • 压缩图片用的是 TinyPNGimagine 。前者无损压缩、后者是有损压缩

    例如我的博客的Banner、都是在150k以下的:https://cdn.jsdelivr.net/gh/zykjofficial/zykjimg@master/bangumi/png/bangumi5.png

异步加载

在浏览器解析HTML的时候,遇到<link>、<script>,这个过程会阻塞后面内容、这样就会增加加载时间。不建议将JS放到<head>里。

此时我们需要使用异步加载的形式缩短页面的加载时间。

异步加载CSS

例如

1
<link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/zykjofficial/zykjresource@master/css/zykjcss.min.css" media="all" onload='this.media="all",this.onload=null'>

修改themes\Butterfly\layout\includes\head.pug(部分内容)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// ...

//- main css
link(rel='stylesheet', href=url_for(theme.gcore.main_css))
link(rel='stylesheet', href=url_for(theme.gcore.fontawesome), media="print" onload='this.media="all",this.onload=null')

if (theme.snackbar && theme.snackbar.enable)
link(rel='stylesheet', href=url_for(theme.gcore.snackbar_css), media="print" onload='this.media="all",this.onload=null')

if theme.algolia_search.enable
link(rel='stylesheet' href=url_for(theme.gcore.algolia_search_css),media="print" onload='this.media="all",this.onload=null')
script(src=url_for(theme.gcore.algolia_search) defer)

// ...

异步加载js

1
<script defer src="xxx.js"></script>

修改themes\Butterfly\layout\includes\additional-js.pug (部分内容)

其实下面内容也修改不大、毕竟不是所有JS都能使用异步加载、可能会出现一些问题

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
div
script(src=url_for(theme.gcore.utils))
script(src=url_for(theme.gcore.main))

if theme.translate && theme.translate.enable
script(src=url_for(theme.gcore.translate))

if theme.medium_zoom
script(src=url_for(theme.gcore.medium_zoom))

if theme.instantpage
script(src=url_for(theme.gcore.instantpage) type="module")

if theme.lazyload.enable
script(src=url_for(theme.gcore.lazyload))

if (theme.snackbar && theme.snackbar.enable)
script(src=url_for(theme.gcore.snackbar))

if theme.pangu && theme.pangu.enable
!=partial('includes/third-party/pangu.pug', {}, {cache:theme.fragment_cache})

//- search
if theme.algolia_search.enable
script(src=url_for(theme.gcore.algolia_js) defer)
else if theme.local_search.enable
script(src=url_for(theme.gcore.local_search) defer)

// ...

PWA

渐进式网络应用程式(英语:Progressive Web Apps,简称:PWA)是一种普通网页或网站架构起来的网络应用程式,但它可以以传统应用程式或原生移动应用程式形式展示给用户。这种应用程式形态视图将目前最为现代化的浏览器提供的功能与行动装置的体验优势相结合。

我会把这个放在优化博客中个人只是喜欢那个更新提示、在我的使用中、PWA最大的作用是能将需要缓存的内容缓存在浏览器、刷新页面时会直接获取缓存

PWA教程: https://butterfly.js.org/posts/4073eda/#PWA

Pjax

通过ajax和pushState技术提供了极速的(无刷新ajax加载)浏览体验,并且保持了真实的地址、网页标题,浏览器的后退(前进)按钮也可以正常使用

这使得页面切换变得更加迅速、当然还是存在一些Bug

开启只需要在 _config.butterfly.yml中 开启pjax

1
2
3
4
5
pjax:
enable: true
exclude:
# - xxxx
# - xxxx

参考:

更多大佬的教程: