ลดขนาดและบีบอัดเพย์โหลดของเครือข่ายด้วย Brotli

Michael DiBlasio
Michael DiBlasio

Codelab นี้เป็นส่วนขยายของ Codelab การลดขนาดและบีบอัดเพย์โหลดเครือข่าย และถือว่าคุณคุ้นเคยกับแนวคิดพื้นฐานของการบีบอัด เมื่อเทียบกับอัลกอริทึมการบีบอัดอื่นๆ เช่น gzip Codelab นี้จะสำรวจว่าการบีบอัด Brotli (br) สามารถลดอัตราส่วนการบีบอัดและขนาดโดยรวมของแอปได้อย่างไร

ภาพหน้าจอแอป

วัดผล

ก่อนที่จะเริ่มเพิ่มการเพิ่มประสิทธิภาพ คุณควรวิเคราะห์สถานะปัจจุบันของแอปพลิเคชันก่อนเสมอ

  1. คลิกรีมิกซ์เพื่อแก้ไขเพื่อให้โปรเจ็กต์แก้ไขได้
  2. หากต้องการดูตัวอย่างเว็บไซต์ ให้กดดูแอป แล้วกดเต็มหน้าจอ เต็มหน้าจอ

ในCodelab การลดขนาดและบีบอัดเพย์โหลดของเครือข่ายก่อนหน้านี้ เราได้ลดขนาดของ main.js จาก 225 KB เหลือ 61.6 KB ใน Codelab นี้ คุณจะได้สำรวจว่าการบีบอัด Brotli ช่วยลดขนาดแพ็กเกจนี้ได้มากยิ่งขึ้นได้อย่างไร

การบีบอัด Brotli

Brotli เป็นอัลกอริทึมการบีบอัดที่ใหม่กว่าซึ่งให้ผลลัพธ์การบีบอัดข้อความที่ดีกว่า gzip CertSimple ระบุว่าประสิทธิภาพของ Brotli มีดังนี้

  • เล็กกว่า gzip 14% สำหรับ JavaScript
  • เล็กกว่า gzip สำหรับ HTML 21%
  • เล็กกว่า gzip สำหรับ CSS 17%

หากต้องการใช้ Brotli เซิร์ฟเวอร์ของคุณต้องรองรับ HTTPS Brotli รองรับในเบราว์เซอร์ที่ทันสมัยทั้งหมด เบราว์เซอร์ที่รองรับ Brotli จะมี br ในส่วนหัว Accept-Encoding:

Accept-Encoding: gzip, deflate, br

คุณสามารถระบุอัลกอริทึมการบีบอัดที่ใช้ได้โดยใช้ช่อง Content-Encoding ในแท็บเครือข่ายของเครื่องมือสำหรับนักพัฒนาซอฟต์แวร์ Chrome (Command+Option+I หรือ Ctrl+Alt+I)

แผงเครือข่าย คอลัมน์การเข้ารหัสเนื้อหาจะแสดงการเข้ารหัสที่ใช้สำหรับเนื้อหาต่างๆ รวมถึง gzip และ brotli (br)

วิธีเปิดใช้ Brotli

วิธีตั้งค่าเว็บเซิร์ฟเวอร์เพื่อส่งทรัพยากรที่เข้ารหัส Brotli จะขึ้นอยู่กับวิธีที่คุณวางแผนจะเข้ารหัส ตัวเลือกของคุณคือการบีบอัดทรัพยากรแบบไดนามิกด้วย Brotli ณ เวลาที่มีคำขอ (ไดนามิก) หรือเข้ารหัสทรัพยากรล่วงหน้าเพื่อให้ทรัพยากรได้รับการบีบอัดแล้วเมื่อผู้ใช้ส่งคำขอ (คงที่)

การบีบอัดแบบไดนามิก

การบีบอัดแบบไดนามิกเกี่ยวข้องกับการบีบอัดชิ้นงานแบบเรียลไทม์เมื่อเบราว์เซอร์ส่งคำขอ

ข้อดี

  • คุณไม่จำเป็นต้องสร้างและอัปเดตชิ้นงานเวอร์ชันบีบอัดที่บันทึกไว้
  • การบีบอัดแบบทันทีเหมาะอย่างยิ่งสำหรับหน้าเว็บที่สร้างขึ้นแบบไดนามิก

ข้อเสีย

  • การบีบอัดไฟล์ในระดับที่สูงขึ้นเพื่อให้ได้อัตราส่วนการบีบอัดที่ดีขึ้นจะใช้เวลานานขึ้น ซึ่งอาจส่งผลต่อประสิทธิภาพเนื่องจากผู้ใช้ต้องรอให้เนื้อหาบีบอัดก่อนที่เซิร์ฟเวอร์จะส่ง

การบีบอัดแบบไดนามิกด้วย Node และ Express

ไฟล์ server.js มีหน้าที่ตั้งค่าเซิร์ฟเวอร์ Node ที่โฮสต์แอปพลิเคชัน

const express = require('express');
const app = express();
app.use(express.static('public'));

const listener = app.listen(process.env.PORT, function() {
  console.log(`Your app is listening on port ${listener.address().port}`);
});

โค้ดนี้จะนำเข้า express และใช้มิดเดิลแวร์ express.static เพื่อโหลดไฟล์ HTML, JS และ CSS แบบคงที่ทั้งหมดใน public/directory (และไฟล์เหล่านั้นสร้างขึ้นโดย webpack ในทุกบิลด์)

คุณสามารถใช้โมดูล shrink-ray เพื่อให้มั่นใจว่าเนื้อหาทั้งหมดจะได้รับการบีบอัดโดยใช้ Brotli ทุกครั้งที่มีการส่งคำขอ เริ่มต้นด้วยการเพิ่มเป็น devDependency ใน package.json โดยทำดังนี้

"devDependencies": {
  // ...
  "shrink-ray": "^0.1.3"
},

และนำเข้าลงในไฟล์เซิร์ฟเวอร์ server.js ดังนี้

const express = require('express');
const shrinkRay = require('shrink-ray');

และเพิ่มเป็นมิดเดิลแวร์ก่อนที่จะต่อเชื่อม express.static ดังนี้

// ...
const app = express();

// Compress all requests
app.use(shrinkRay());
app.use(express.static('public'));

ตอนนี้ให้โหลดแอปซ้ำ แล้วดูขนาดแพ็กเกจในแผงเครือข่าย

ขนาดแพ็กเกจที่มีการบีบอัด Brotli แบบไดนามิก

ตอนนี้คุณจะเห็นว่ามีการใช้ brotli จาก bz ในส่วนหัว Content-Encoding main.bundle.js ลดลงจาก 225 KB เหลือ 53.1 KB ซึ่งมีขนาดเล็กลงประมาณ 14% เมื่อเทียบกับ gzip (61.6 KB)

การบีบอัดแบบคงที่

แนวคิดเบื้องหลังการบีบอัดแบบคงที่คือการบีบอัดและบันทึกเนื้อหาไว้ล่วงหน้า

ข้อดี

  • เวลาในการตอบสนองที่เกิดจากระดับการบีบอัดสูงจะไม่เป็นปัญหาอีกต่อไป ไม่จำเป็นต้องบีบอัดไฟล์แบบเรียลไทม์เนื่องจากสามารถดึงข้อมูลได้โดยตรงแล้ว

ข้อเสีย

  • ชิ้นงานต้องได้รับการบีบอัดทุกครั้งที่บิลด์ เวลาในการสร้างอาจเพิ่มขึ้นอย่างมากหากใช้การบีบอัดระดับสูง

การบีบอัดแบบคงที่ด้วย Node และ Express ที่มี webpack

เนื่องจากการบีบอัดแบบคงที่เกี่ยวข้องกับการบีบอัดไฟล์ล่วงหน้า คุณจึงแก้ไขการตั้งค่า webpack เพื่อบีบอัดเนื้อหาเป็นส่วนหนึ่งของขั้นตอนการบิลด์ได้ คุณใช้ brotli-webpack-plugin เพื่อดำเนินการนี้ได้

เริ่มต้นด้วยการเพิ่มเป็น devDependency ใน package.json โดยทำดังนี้

"devDependencies": {
  // ...
 "brotli-webpack-plugin": "^1.1.0"
},

นำเข้าปลั๊กอินในไฟล์การกำหนดค่าเช่นเดียวกับปลั๊กอิน webpack อื่นๆ webpack.config.js:

var path = require("path");

//...
var BrotliPlugin = require('brotli-webpack-plugin');

และรวมไว้ในอาร์เรย์ plugins ดังนี้

module.exports = {
  // ...
  plugins: [
    // ...
    new BrotliPlugin({
      asset: '[file].br',
      test: /\.(js)$/
    })
  ]
},

อาร์เรย์ปลั๊กอินใช้อาร์กิวเมนต์ต่อไปนี้

  • asset: ชื่อชิ้นงานเป้าหมาย
  • [file] จะแทนที่ด้วยชื่อไฟล์ชิ้นงานเดิม
  • test: ระบบจะประมวลผลชิ้นงานทั้งหมดที่ตรงกับ RegExp นี้ (ซึ่งก็คือชิ้นงาน JavaScript ที่ลงท้ายด้วย .js)

เช่น main.js จะเปลี่ยนชื่อเป็น main.js.br

เมื่อแอปโหลดซ้ำและสร้างใหม่ ระบบจะสร้างแพ็กเกจหลักเวอร์ชันที่บีบอัดแล้ว เปิด Glitch Console เพื่อดูสิ่งที่อยู่ภายในไดเรกทอรี public/ สุดท้ายที่เซิร์ฟเวอร์ Node แสดง

  1. คลิกปุ่มเครื่องมือ
  2. คลิกปุ่มคอนโซล
  3. ในคอนโซล ให้เรียกใช้คำสั่งต่อไปนี้เพื่อเปลี่ยนเป็นไดเรกทอรี public และดูไฟล์ทั้งหมด
cd public
ls -lh
ขนาดแพ็กเกจที่มีการบีบอัด Brotli แบบคงที่

ตอนนี้ระบบได้บันทึกแพ็กเกจเวอร์ชันที่บีบอัดด้วย Brotli (main.bundle.js.br) ไว้ที่นี่ด้วย และมีขนาดเล็กลงประมาณ 76% (225 KB เทียบกับ 53 KB) เมื่อเทียบกับ main.bundle.js

จากนั้นบอกให้เซิร์ฟเวอร์ส่งไฟล์ที่บีบอัดด้วย Brotli เหล่านี้เมื่อใดก็ตามที่มีการขอเวอร์ชัน JS ดั้งเดิม ซึ่งทำได้โดยกำหนดเส้นทางใหม่ใน server.js ก่อนที่จะแสดงไฟล์ด้วย express.static

const express = require('express');
const app = express();

app.get('*.js', (req, res, next) => {
  req.url = req.url + '.br';
  res.set('Content-Encoding', 'br');
  res.set('Content-Type', 'application/javascript; charset=UTF-8');
  next();
});

app.use(express.static('public'));

app.get ใช้เพื่อบอกเซิร์ฟเวอร์ถึงวิธีตอบสนองต่อคำขอ GET สำหรับปลายทางที่เฉพาะเจาะจง จากนั้นระบบจะใช้ฟังก์ชัน Callback เพื่อกำหนดวิธีจัดการคำขอนี้ เส้นทางจะทำงานดังนี้

  • การระบุ '*.js' เป็นอาร์กิวเมนต์แรกหมายความว่าวิธีนี้ใช้ได้กับทุกปลายทางที่เริ่มทำงานเพื่อดึงข้อมูลไฟล์ JS
  • ภายใน Callback ระบบจะแนบ .br ไว้กับ URL ของคำขอ และตั้งค่าส่วนหัวการตอบกลับ Content-Encoding เป็น br
  • ส่วนหัว Content-Type ตั้งค่าเป็น application/javascript; charset=UTF-8 เพื่อระบุประเภท MIME
  • สุดท้าย next() จะช่วยให้มั่นใจว่าลำดับจะดำเนินต่อไปยัง Callback ที่อาจเป็นลำดับถัดไป

เนื่องจากเบราว์เซอร์บางรายการอาจไม่รองรับการบีบอัด brotli โปรดยืนยันว่าระบบรองรับ brotli ก่อนที่จะแสดงผลไฟล์ที่บีบอัดด้วย brotli โดยตรวจสอบว่าส่วนหัวของคำขอ Accept-Encoding มี br:

const express = require('express');
const app = express();

app.get('*.js', (req, res, next) => {
  if (req.header('Accept-Encoding').includes('br')) {
    req.url = req.url + '.br';
    console.log(req.header('Accept-Encoding'));
    res.set('Content-Encoding', 'br');
    res.set('Content-Type', 'application/javascript; charset=UTF-8');
  }

  next();
});

app.use(express.static('public'));

เมื่อแอปโหลดซ้ำแล้ว ให้ดูที่แผงเครือข่ายอีกครั้ง

ขนาดแพ็กเกจ 53.1 KB (จาก 225 KB)

สำเร็จ! คุณได้ใช้การบีบอัด Brotli เพื่อบีบอัดชิ้นงานเพิ่มเติม

บทสรุป

Codelab นี้แสดงให้เห็นว่า brotli สามารถลดขนาดโดยรวมของแอปได้อีกอย่างไร ในกรณีที่รองรับ brotli เป็นอัลกอริทึมการบีบอัดที่มีประสิทธิภาพมากกว่า gzip