天天看點

實作一個骨架屏webpack插件

一. 原理

在vue的首頁自動加上骨架屏代碼。類似于下面:

<div id="app">
    <app></app>
 </div>
           

加上骨架屏後:

<div id="app">
    <app></app>
    <div>骨架屏 code</div>
 </div>
           

在app沒有加載之前先看到的是骨架屏,加載完成之後骨架屏被替換。

由于直接寫在這裡面代碼不好管理,我們把它抽出來,在編譯階段插進去。

二、實作

1. 寫骨架skeleton.html

在index.html同級目錄下建立檔案skeleton.html

skeleton.html用于寫骨架屏頁面。

<style></style>
<div>骨架屏 code</div>
<script></script>
           

2. 在index.html裡面加入插入辨別

插辨別是為了編譯的時候識别

即為辨別标記。

<div id="app">
    <app></app>
    <!-- skeleton-outlet -->
 </div>
           

3. 寫骨架屏插件

在webpack.config.js同級目錄下建立Skeleton.js

Skeleton.js即骨架屏插件,骨架屏插件操作:把skeleton.html讀取插入index.html

代碼大緻如下:

const fs = require("fs");

let Skeleton = function (options) {
  this.template = options.template;
};

Skeleton.prototype.apply = function (compiler) {
  const skeletonpath = this.template;
  compiler.plugin('compilation', compilation => {
    compilation.plugin('html-webpack-plugin-before-html-processing', (htmlData, callback) => {
    // 讀取檔案
      fs.readFile(skeletonpath, "utf-8", function(error, data) {
        if (error) {
          callback(null, htmlData);
        } else {
        // 插入檔案
          htmlData.html = htmlData.html.replace('<!-- skeleton-outlet -->', data);
          callback(null, htmlData);
        }
      });
    });
  });
};
module.exports = Skeleton;
           

4. 使用骨架屏插件

在webpack.config.js中引入,再插件使用。

const Skeleton = require('../../build/Skeleton');

module.exports = {
  plugins: [
    new Skeleton({
      // 骨架路徑
      template: './skeleton.html'
    })
  ]
};

           

運作後即可用了。

5. 優化

我們希望可以把插入辨別可配置化。使用方式如下:

const Skeleton = require('../../build/Skeleton');

module.exports = {
  plugins: [
    new Skeleton({
      outlet: '<!-- skeleton-outlet -->', // 插入辨別
      template: './skeleton.html' // 骨架路徑
    })
  ]
};

           

則Skeleton可對應調整下:

const fs = require("fs");

let Skeleton = function (options) {
  this.template = options.template;
  // 接受辨別配置
  this.outlet = options.outlet;
};

Skeleton.prototype.apply = function (compiler) {
  const { template, outlet } = this;
  compiler.plugin('compilation', compilation => {
    compilation.plugin('html-webpack-plugin-before-html-processing', (htmlData, callback) => {
    // 讀取檔案
      fs.readFile(template, "utf-8", function(error, data) {
        if (error) {
          callback(null, htmlData);
        } else {
        // 插入檔案,采用動态辨別
          htmlData.html = htmlData.html.replace(outlet, data);
          callback(null, htmlData);
        }
      });
    });
  });
};
module.exports = Skeleton;