prefetch 和 preload 及 webpack 的相關處理


使用預取和預加載是網站性能和用戶體驗提升的一個很好的途徑,本文介紹了使用 prefetch 和 prefetch 進行預取和預加載的方法,並使用 webpack 進行實現

<link> 標簽的 rel 屬性可以定義鏈接類型,prefetch 是其中的一種,與 href 配合使用可以預取或預加載對應資源

<link rel="prefetch" herf="URL">

preload 是另外一種類型,同樣用 href 定義資源地址,但其處理預取外,還會對資源進行解析,所以還要增加屬性 as,說明資源的類型

<link rel="preload" href="URL" as="MIME_TYPE">

預取資源

prefetch 表示用戶在接下來的瀏覽中(例如在下一個頁面),有可能用到對應資源,提示瀏覽器要在閑時獲取對應資源

先新建文件夾 prefetch-preload-demo(本文所有代碼將在此創建),安裝相關依賴,並新建文件夾 static

mkdir prefetch-preload-demo
cd prefetch-preload-demo
npm init -y
npm i -D http-server
mkdir static

在 static 中創建 prefetch.htmlmain.jsscript.js

prefetch.html 定義了一個 relprefetch 的鏈接

<html>
<head>
<title>Prefetch</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
<link rel="prefetch" href="script.js">
</head>
<body>
<script src="main.js"></script>
</body>
</html>

main.js 創建了一個按鈕,並綁定了點擊事件

let button = document.createElement('button');
button.innerHTML = 'Add Script';
button.addEventListener('click', e => {
  let script = document.createElement("script");
  script.src = "script.js";
  document.head.appendChild(script);
});
document.body.appendChild(button);

script.js 只是簡單的打印了一下

console.log('script run');

運行服務器(也可在 package.json 中增加 server 腳本)

npx http-server

訪問 http://localhost:8080 並導航至 static 中,點擊 prefetch.html,或者直接訪問線上頁面,初始狀態下,查看控制台的網絡選項卡下的內容如下(不要勾選 Disable Cache,點擊右側齒輪,勾選 Use large request rows

  • script.js 被 fetch 下來,size 列的兩個數字,275 B 表示下載的字節大小,0 B 表示解析的字節大小(即目前並沒有解析)
  • 控制台是空的,即腳本沒有運行

點擊頁面上的 Add Script,會在頁面增加地址為 script.js<script> 標簽,此時網絡選項卡會增加以下內容

  • 下載字節量為 (prefetch cache) ,即直接從預取緩存獲取資源,下面的解析后的字節不再為 0
  • 控制台打印出腳本中的調試內容,即這時腳本才被解析並運行

預加載資源

preload 表示用戶在當前的瀏覽中(往往是在當前頁面),極有可以可能用到對應資源,提示瀏覽器要優先獲取對應資源

將 prefetch.html 的 link 標簽的 prefetch 改為 preload,並增加資源類型 asscript,即得 preload.html

<link rel="preload" href="script.js" as="script">

訪問本地服務器對應的 prefetch.html,或者直接訪問線上頁面,初始狀態下,查看控制台的網絡選項卡下的內容如下

  • script.js 被優先下載, size 列的解壓字節不再為 0,即 preload 除了把腳本下載了下來,還進行了解析
  • 控制台目前仍為空,即腳本雖然被解析,但並沒有運行

點擊 Add Script,網絡選項卡並沒有增加任何記錄,但是控制台輸出了腳本的打印內容

  • 因為腳本已經解析完成,所以連從緩存獲取都不需要了,直接運行即可
  • 如果沒有在 3 秒內點擊 Add Script,控制台會進行警告,因為沒有及時使用應該優先加載的資源

The resource https://chanvinxiao.com/demo/html/script.js was preloaded using link preload but not used within a few seconds from the window's load event. Please make sure it has an appropriate as value and it is preloaded intentionally.

webpack 的相關處理

運行以下命令安裝相關依賴,並新建文件夾 src

npm i -D webpack webpack-cli html-webpack-plugin preload-webpack-plugin@3.0.0-beta.4
mkdir src

  • PreloadWebpackPlugin 的當前版本 2.x 與 webpack 當前版本 4.x 不兼容,所以需要指定版本號為最新的 3.x beta

main.jsscript.js 復制到 src 中,並將 main.js 的點擊事件處理更新為

button.addEventListener('click', e => {
  import(/* webpackChunkName: "script" */ './script.js');
});
  • import() 為動態加載腳本,webpack 會生成類似以上動態創建 script 標簽的代碼
  • import 里的注釋為特殊含義的魔法注釋,如果不設置 webpackChunkName,加載的腳本將被按數字次序命名

增加 webpack.config.js 如下

const HtmlWebpackPlugin = require('html-webpack-plugin');
const PreloadWebpackPlugin = require('preload-webpack-plugin');

module.exports = {
  entry: './src/main.js',
  plugins: [
    new HtmlWebpackPlugin({
      filename: 'preload.html'
    }),
    new PreloadWebpackPlugin()
  ]
}
  • HtmlWebpackPlugin 將自動生成相應的 html 文件,默認為 index.html,這里通過設置 filename 選項更改
  • PreloadWebpackPlugin 為 HtmlWebpackPlugin 的插件,默認為其動態加載資源增加鏈接類型為 preloadlink 標簽,其 as 的值可根據后綴自動判斷

PreloadWebpackPlugin 也支持 prefetch,需要增加 rel 選項為 prefetch

    new HtmlWebpackPlugin({
      filename: 'prefetch.html'
    }),
    new PreloadWebpackPlugin({
      rel: 'prefetch'
    })

不過要同時生成 preload.html 和 prefetch.html,需要在對應的 PreloadWebpackPlugin 中設置 excludeHtmlNames 排除對方,否則會同時產生 preload 和 prefetch 的 link 標簽

    new HtmlWebpackPlugin({
      filename: 'preload.html'
    }),
    new HtmlWebpackPlugin({
      filename: 'prefetch.html'
    }),
    new PreloadWebpackPlugin({
      excludeHtmlNames: ['prefetch.html']
    }),
    new PreloadWebpackPlugin({
      rel: 'prefetch',
      excludeHtmlNames: ['preload.html']
    })

構建文件(也可在 package.json 中增加 build 腳本)

npx webpack

dist 文件夾中將生成 prefetch.html 和 preload.html,訪問本地服務器對應地址,即可得到與以上靜態頁面同樣的效果

總結

此文使用靜態頁面和 webpack 打包兩種方式演示了預取和預加載的實現,完整代碼見 GitHub,主要技術點如下:

  • ELEMENT.appendChild 動態創建腳本
  • import() 動態加載腳本並設置魔法注釋
  • html-webpack-plugin 及其插件的配置


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM