前言

网站加载速度不仅可以极大地提升用户体验感,还能对访问者的转化率起到一定的帮助,经过优化的网站文件下载与页面显示速度更快,因此网站加载优化是十分必要的。

本文参考了以下两篇大佬的文章

压缩静态资源

查看教程
  • 我是使用gulp来压缩静态资源的,被压缩的文件有HTML,CSS,JavaScript文件。

    • 1.插件安装

      在博客根目录打开终端,输入以下指令:

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      npm install --global gulp-cli
      npm install gulp --save

      # 压缩HTML
      npm install gulp-htmlclean --save-dev
      npm install gulp-html-minifier-terser --save-dev

      # 压缩CSS
      npm install gulp-clean-css --save-dev

      # 压缩JS
      npm install gulp-terser --save-dev
    • 2.在博客根目录创建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
      49
      50
      51
      const gulp = require("gulp")
      //用到的各个插件
      const htmlMin = require('gulp-html-minifier-terser')
      const htmlClean = require('gulp-htmlclean')
      const terser = require('gulp-terser')
      const cleanCSS = require('gulp-clean-css')

      // 压缩js
      gulp.task('minify-js', () =>
      gulp.src(['./public/**/*.js', '!./public/**/*.min.js'])
      .pipe(terser({}))
      .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', () =>
      gulp.src('./public/**/*.html')
      .pipe(htmlClean())
      .pipe(htmlMin({
      removeComments: true, //清除html注释
      collapseWhitespace: true, //压缩html
      collapseInlineTagWhitespace: true,
      collapseBooleanAttributes: true,
      noNewlinesBeforeTagClose: false,
      removeAttributeQuotes: true,
      removeRedundantAttributes: 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.task("default", gulp.parallel('minify-js', 'minify-css', 'minify-html'))
    • 在执行hexo g后执行gulp即可压缩

  • 字体与图片的压缩,可以自行百度,网上有很多工具,压缩完后再引入进文章与网页

PWA本地缓存

查看教程

1.PWA是一种理念,使用多种技术来增强WEB APP的功能,可以让网站的体验变得更好,能够模拟一些原生功能,比如通知推送。在移动端利用标准化框架,让网页应用呈现和原生应用相似的体验。PWA可以利用 Service Worker 的缓存特点,极大地加速博客。

2.因为我们最终目的是要制作一个全平台的WEB APP,所以对于图标的大小、类型适配显得格外重要。可以访问realfavicongenerator进行图标制作及manifest的生成。

查看教程

1.进入页面后点击 Select your Favicon image,选择一个图标上传,我这里使用的小火箭是在阿里巴巴矢量图标库下载的

2.找到选项Favicon for Android Chrome,选择Assets→create all documented icons

3.找到选项Windows Metro,点击图标,使得背景图片使用图标配色

4.找到选项Favicon generator options:选择path调整图片存放的相对路径例如我这里输入/img/siteicon;选择App name,设置你网站app的名字;选择additional files,勾选生成一个readme.md

5.最终选择生成Generator your Favicons and HTML code

6.下载资源包Favicon package

7.将资源包里面的全部内容放入网站根目录的source\img文件内,方便后面的引入

3.PWA配置

查看教程
  • 插件安装

    1
    npm install workbox-build --save
  • 在博客根目录创建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
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    const gulp = require("gulp")
    //用到的各个插件
    const htmlMin = require('gulp-html-minifier-terser')
    const htmlClean = require('gulp-htmlclean')
    const terser = require('gulp-terser')
    const cssnano = require('gulp-cssnano')
    const workbox = require("workbox-build")

    //pwa
    gulp.task("generate-service-worker", () => {
    return workbox.injectManifest({
    swSrc: "./sw-template.js",
    swDest: "./public/sw.js",
    globDirectory: "./public",
    globPatterns: [
    // 缓存所有以下类型的文件,极端不推荐
    // "**/*.{html,css,js,json,woff2,xml}"
    // 推荐只缓存404,主页和主要样式和脚本。
    "404.html",
    "index.html",
    "js/main.js",
    "css/index.css",
    ],
    modifyURLPrefix: {
    "": "./",
    },
    });
    });

    // 压缩js
    gulp.task('minify-js', () =>
    gulp.src(['./public/**/*.js', '!./public/**/*.min.js'])
    .pipe(terser({}))
    .pipe(gulp.dest('./public'))
    )

    //压缩css
    gulp.task('minify-css', () =>
    gulp.src(['./public/**/*.css'])
    .pipe(cssnano({
    mergeIdents: false,
    reduceIdents: false,
    discardUnused: false,
    zIndex: false
    })).pipe(gulp.dest('./public'))
    )

    //压缩html
    gulp.task('minify-html', () =>
    gulp.src('./public/**/*.html')
    .pipe(htmlClean())
    .pipe(htmlMin({
    removeComments: true, //清除html注释
    collapseWhitespace: true, //压缩html
    collapseInlineTagWhitespace: true,
    collapseBooleanAttributes: true,
    noNewlinesBeforeTagClose: false,
    removeAttributeQuotes: true,
    removeRedundantAttributes: 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.task(
    "default",
    gulp.series("generate-service-worker", gulp.parallel("minify-js", "minify-html", "minify-css",))
    );

  • 在博客根目录创建sw-template.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
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    const workboxVersion = '5.1.3';

    importScripts(`https://storage.googleapis.com/workbox-cdn/releases/${workboxVersion}/workbox-sw.js`);

    workbox.core.setCacheNameDetails({
    prefix: "your name"
    });

    workbox.core.skipWaiting();

    workbox.core.clientsClaim();

    // 注册成功后要立即缓存的资源列表
    // 具体缓存列表在gulpfile.js中配置,见下文
    workbox.precaching.precacheAndRoute(self.__WB_MANIFEST,{
    directoryIndex: null
    });

    // 清空过期缓存
    workbox.precaching.cleanupOutdatedCaches();

    // 图片资源(可选,不需要就注释掉)
    workbox.routing.registerRoute(
    /\.(?:png|jpg|jpeg|gif|bmp|webp|svg|ico)$/,
    new workbox.strategies.CacheFirst({
    cacheName: "images",
    plugins: [
    new workbox.expiration.ExpirationPlugin({
    maxEntries: 1000,
    maxAgeSeconds: 60 * 60 * 24 * 30
    }),
    new workbox.cacheableResponse.CacheableResponsePlugin({
    statuses: [0, 200]
    })
    ]
    })
    );

    // 字体文件(可选,不需要就注释掉)
    workbox.routing.registerRoute(
    /\.(?:eot|ttf|woff|woff2)$/,
    new workbox.strategies.CacheFirst({
    cacheName: "fonts",
    plugins: [
    new workbox.expiration.ExpirationPlugin({
    maxEntries: 1000,
    maxAgeSeconds: 60 * 60 * 24 * 30
    }),
    new workbox.cacheableResponse.CacheableResponsePlugin({
    statuses: [0, 200]
    })
    ]
    })
    );

    // 谷歌字体(可选,不需要就注释掉)
    workbox.routing.registerRoute(
    /^https:\/\/fonts\.googleapis\.com/,
    new workbox.strategies.StaleWhileRevalidate({
    cacheName: "google-fonts-stylesheets"
    })
    );
    workbox.routing.registerRoute(
    /^https:\/\/fonts\.gstatic\.com/,
    new workbox.strategies.CacheFirst({
    cacheName: 'google-fonts-webfonts',
    plugins: [
    new workbox.expiration.ExpirationPlugin({
    maxEntries: 1000,
    maxAgeSeconds: 60 * 60 * 24 * 30
    }),
    new workbox.cacheableResponse.CacheableResponsePlugin({
    statuses: [0, 200]
    })
    ]
    })
    );

    // jsdelivr的CDN资源(可选,不需要就注释掉)
    workbox.routing.registerRoute(
    /^https:\/\/cdn\.jsdelivr\.net/,
    new workbox.strategies.CacheFirst({
    cacheName: "static-libs",
    plugins: [
    new workbox.expiration.ExpirationPlugin({
    maxEntries: 1000,
    maxAgeSeconds: 60 * 60 * 24 * 30
    }),
    new workbox.cacheableResponse.CacheableResponsePlugin({
    statuses: [0, 200]
    })
    ]
    })
    );

    workbox.googleAnalytics.initialize();
  • [Blogroot]\themes\butterfly\layout\includes\third-party\目录下新建pwanotice.pug文件

    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
    #app-refresh.app-refresh(style='position: fixed;top: -2.2rem;left: 0;right: 0;z-index: 99999;padding: 0 1rem;font-size: 15px;height: 2.2rem;transition: all 0.3s ease;')
    .app-refresh-wrap(style=' display: flex;color: #fff;height: 100%;align-items: center;justify-content: center;')
    label ✨ 有新文章啦! 👉
    a(href='javascript:void(0)' onclick='location.reload()')
    span(style='color: #fff;text-decoration: underline;cursor: pointer;') 点击打开🚀
    script.
    if ('serviceWorker' in navigator) {
    if (navigator.serviceWorker.controller) {
    navigator.serviceWorker.addEventListener('controllerchange', function() {
    showNotification()
    })
    }
    window.addEventListener('load', function() {
    navigator.serviceWorker.register('/sw.js')
    })
    }
    function showNotification() {
    if (GLOBAL_CONFIG.Snackbar) {
    var snackbarBg =
    document.documentElement.getAttribute('data-theme') === 'light' ?
    GLOBAL_CONFIG.Snackbar.bgLight :
    GLOBAL_CONFIG.Snackbar.bgDark
    var snackbarPos = GLOBAL_CONFIG.Snackbar.position
    Snackbar.show({
    text: '✨ 有新文章啦! 👉',
    backgroundColor: snackbarBg,
    duration: 500000,
    pos: snackbarPos,
    actionText: '点击打开🚀',
    actionTextColor: '#fff',
    onActionClick: function(e) {
    location.reload()
    },
    })
    } else {
    var showBg =
    document.documentElement.getAttribute('data-theme') === 'light' ?
    '#3b70fc' :
    '#1f1f1f'
    var cssText = `top: 0; background: ${showBg};`
    document.getElementById('app-refresh').style.cssText = cssText
    }
    }
  • 修改[Blogroot]\themes\butterfly\layout\includes\additional-js.pug,在文件底部添加以下内容,注意缩进

    1
    2
    +     if theme.pwa.enable
    + !=partial('includes/third-party/pwanotice', {}, {cache:theme.fragment_cache})
  • 打开图标包内的site.webmanifest,建议修改文件名为manifest.json并将其放到网站根目录的source文件夹下,此时还不能直接用,需要添加一些内容,以下是我的manifest.json配置内容,作为参考,其中的theme_color建议用取色器取设计的图标的主色调,同时务必配置start_url和name的配置项,这关系到你之后能否看到浏览器的应用安装按钮。:

    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
    {
    "name": "MYAN's Blog",
    "short_name": "MYAN",
    "theme_color": "#b8d7ed",
    "background_color": "#b8d7ed",
    "display": "standalone",
    "scope": "/",
    "start_url": "/",
    "icons": [
    {
    "src": "/img/siteicon/android-chrome-36x36.png",
    "sizes": "36x36",
    "type": "image/png"
    },
    {
    "src": "/img/siteicon/android-chrome-48x48.png",
    "sizes": "48x48",
    "type": "image/png"
    },
    {
    "src": "/img/siteicon/android-chrome-72x72.png",
    "sizes": "72x72",
    "type": "image/png"
    },
    {
    "src": "/img/siteicon/android-chrome-96x96.png",
    "sizes": "96x96",
    "type": "image/png"
    },
    {
    "src": "/img/siteicon/android-chrome-144x144.png",
    "sizes": "144x144",
    "type": "image/png"
    },
    {
    "src": "/img/siteicon/android-chrome-192x192.png",
    "sizes": "192x192",
    "type": "image/png"
    }
    ],
    "splash_pages": null
    }
  • 打开主题配置文件themes\hexo-theme-butterfly\_config.yml,找到PWA配置项。添加图标路径

    1
    2
    3
    4
    5
    6
    7
    8
    pwa:
    enable: true
    manifest: /manifest.json
    theme_color: '#b8d7ed'
    apple_touch_icon: /img/siteicon/apple-touch-icon.png
    favicon_32_32: /img/siteicon/favicon-32x32.png
    favicon_16_16: /img/siteicon/favicon-16x16.png
    mask_icon: /img/siteicon/safari-pinned-tab.svg
  • 在执行hexo g后执行gulp即可

CDN加速

CDN 利用全局负载均衡技术将用户的访问指向离用户最近的工作正常的流媒体服务器上,由流媒体服务器直接响应用户的请求。服务器中如果没有用户要访问的内容,会根据配置自动从原服务器抓取相应的内容并提供给用户。

使用CDN的前提是有自己的域名,如果要白嫖国内的CDN的话还需要进行备案,一切准备就绪后挑选心仪的CDN供应商即可,CDN我使用的是又拍云,每个月有免费的存储与流量。