Giảm thiểu và nén tải trọng mạng bằng brotli

Michael DiBlasio
Michael DiBlasio

Lớp học lập trình này là phần mở rộng của Lớp học lập trình Giảm thiểu và nén tải trọng mạng và giả định rằng bạn đã quen thuộc với các khái niệm cơ bản về nén. So với các thuật toán nén khác như gzip, lớp học lập trình này sẽ khám phá cách nén Brotli (br) có thể giảm thêm tỷ lệ nén và kích thước tổng thể của ứng dụng.

Ảnh chụp màn hình ứng dụng

Đo lường

Trước khi bắt đầu thêm các hoạt động tối ưu hoá, bạn nên phân tích trạng thái hiện tại của ứng dụng.

  1. Nhấp vào Trộn để chỉnh sửa để có thể chỉnh sửa dự án.
  2. Để xem trước trang web, hãy nhấn vào Xem ứng dụng, rồi nhấn vào Toàn màn hình toàn màn hình.

Trong Lớp học lập trình Giảm thiểu và nén tải trọng mạng trước đó, chúng ta đã giảm kích thước của main.js từ 225 KB xuống 61,6 KB. Trong lớp học lập trình này, bạn sẽ khám phá cách tính năng nén Brotli có thể giảm kích thước gói này hơn nữa.

Nén Brotli

Brotli là một thuật toán nén mới hơn, có thể mang lại kết quả nén văn bản tốt hơn cả gzip. Theo CertSimple, hiệu suất của Brotli là:

  • Nhỏ hơn 14% so với gzip đối với JavaScript
  • Nhỏ hơn gzip 21% đối với HTML
  • Nhỏ hơn 17% so với gzip đối với CSS

Để sử dụng Brotli, máy chủ của bạn phải hỗ trợ HTTPS. Brotli được hỗ trợ trong tất cả các trình duyệt hiện đại. Những trình duyệt hỗ trợ Brotli sẽ thêm br vào tiêu đề Accept-Encoding:

Accept-Encoding: gzip, deflate, br

Bạn có thể xác định thuật toán nén nào được sử dụng bằng cách sử dụng trường Content-Encoding trong thẻ Mạng của Công cụ cho nhà phát triển Chrome (Command+Option+I hoặc Ctrl+Alt+I):

Bảng điều khiển Mạng. Cột Mã hoá nội dung cho biết các phương thức mã hoá được dùng cho nhiều thành phần, bao gồm cả gzip và brotli (br).

Cách bật Brotli

Cách bạn thiết lập một máy chủ web để gửi tài nguyên được mã hoá bằng Brotli phụ thuộc vào cách bạn dự định mã hoá các tài nguyên đó. Bạn có thể chọn nén tài nguyên một cách linh hoạt bằng Brotli tại thời điểm yêu cầu (động) hoặc mã hoá trước để tài nguyên đã được nén vào thời điểm người dùng yêu cầu (tĩnh).

Nén động

Nén linh động liên quan đến việc nén nội dung ngay lập tức khi trình duyệt yêu cầu.

Ưu điểm

  • Bạn không cần tạo và cập nhật các phiên bản nén đã lưu của tài sản.
  • Việc nén tức thì đặc biệt hiệu quả đối với những trang web được tạo động.

Nhược điểm

  • Việc nén tệp ở cấp độ cao hơn để đạt được tỷ lệ nén tốt hơn sẽ mất nhiều thời gian hơn. Điều này có thể gây ảnh hưởng đến hiệu suất vì người dùng phải đợi các thành phần nén trước khi được máy chủ gửi.

Nén động bằng Node và Express

Tệp server.js chịu trách nhiệm thiết lập máy chủ Node lưu trữ ứng dụng.

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}`);
});

Tất cả những gì bạn cần làm là nhập express và sử dụng express.staticmiddleware để tải tất cả các tệp HTML, JS và CSS tĩnh trong public/directory (và những tệp đó được webpack tạo ra trong mỗi bản dựng).

Để đảm bảo tất cả tài sản đều được nén bằng brotli mỗi khi được yêu cầu, bạn có thể sử dụng mô-đun shrink-ray. Bắt đầu bằng cách thêm thành phần này dưới dạng devDependency trong package.json:

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

Và nhập tệp này vào tệp máy chủ, server.js:

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

Và thêm nó làm phần mềm trung gian trước khi express.static được gắn:

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

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

Bây giờ, hãy tải lại ứng dụng và xem kích thước gói trong bảng điều khiển Mạng:

Kích thước gói có tính năng nén Brotli linh hoạt.

Giờ đây, bạn có thể thấy brotli được áp dụng từ bz trong tiêu đề Content-Encoding. main.bundle.js đã giảm từ 225 KB xuống 53,1 KB! Kích thước này nhỏ hơn khoảng 14% so với gzip (61,6 KB).

Nén tĩnh

Ý tưởng đằng sau việc nén tĩnh là nén và lưu tài sản trước thời hạn.

Ưu điểm

  • Độ trễ do mức độ nén cao không còn là vấn đề nữa. Không cần phải nén tệp ngay lập tức vì giờ đây, bạn có thể tìm nạp trực tiếp các tệp.

Nhược điểm

  • Bạn cần nén các thành phần bằng mọi bản dựng. Thời gian tạo có thể tăng lên đáng kể nếu bạn sử dụng các mức nén cao.

Nén tĩnh bằng Node và Express với webpack

nén tĩnh liên quan đến việc nén tệp trước thời hạn, nên bạn có thể sửa đổi chế độ cài đặt webpack để nén tài sản trong bước tạo. Bạn có thể sử dụng brotli-webpack-plugin cho việc này.

Bắt đầu bằng cách thêm thành phần này dưới dạng devDependency trong package.json:

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

Giống như mọi trình bổ trợ webpack khác, hãy nhập trình bổ trợ này vào tệp cấu hình, webpack.config.js:

var path = require("path");

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

Và thêm nó vào mảng trình bổ trợ:

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

Mảng trình bổ trợ sử dụng các đối số sau:

  • asset: Tên thành phần mục tiêu.
  • [file] được thay thế bằng tên tệp gốc của thành phần.
  • test: Tất cả các thành phần khớp với RegExp này (tức là các thành phần JavaScript kết thúc bằng .js) đều được xử lý.

Ví dụ: main.js sẽ được đổi tên thành main.js.br.

Khi ứng dụng tải lại và xây dựng lại, một phiên bản nén của gói chính sẽ được tạo. Mở Glitch Console để xem nội dung bên trong thư mục public/ cuối cùng do máy chủ Node cung cấp.

  1. Nhấp vào nút Công cụ.
  2. Nhấp vào nút Bảng điều khiển.
  3. Trong bảng điều khiển, hãy chạy các lệnh sau để chuyển sang thư mục public và xem tất cả các tệp của thư mục này:
cd public
ls -lh
Kích thước gói có tính năng nén Brotli tĩnh

Phiên bản nén brotli của gói, main.bundle.js.br, hiện cũng được lưu tại đây và có kích thước nhỏ hơn khoảng 76% (225 KB so với 53 KB) so với main.bundle.js.

Tiếp theo, hãy yêu cầu máy chủ gửi những tệp được nén bằng brotli này bất cứ khi nào các phiên bản JS gốc của chúng được yêu cầu. Bạn có thể thực hiện việc này bằng cách xác định một tuyến đường mới trong server.js trước khi các tệp được phân phát bằng 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 được dùng để cho máy chủ biết cách phản hồi yêu cầu GET cho một điểm cuối cụ thể. Sau đó, một hàm callback sẽ được dùng để xác định cách xử lý yêu cầu này. Tuyến đường hoạt động như sau:

  • Việc chỉ định '*.js' làm đối số đầu tiên có nghĩa là điều này sẽ hoạt động cho mọi điểm cuối được kích hoạt để tìm nạp một tệp JS.
  • Trong lệnh gọi lại, .br được đính kèm vào URL của yêu cầu và tiêu đề phản hồi Content-Encoding được đặt thành br.
  • Tiêu đề Content-Type được đặt thành application/javascript; charset=UTF-8 để chỉ định loại MIME.
  • Cuối cùng, next() đảm bảo rằng chuỗi tiếp tục đến mọi lệnh gọi lại có thể xuất hiện tiếp theo.

Vì một số trình duyệt có thể không hỗ trợ tính năng nén brotli, hãy xác nhận rằng brotli được hỗ trợ trước khi trả về tệp được nén bằng brotli bằng cách kiểm tra xem tiêu đề yêu cầu Accept-Encoding có chứa br hay không:

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

Sau khi ứng dụng tải lại, hãy xem lại bảng điều khiển Mạng.

Kích thước gói là 53,1 KB (từ 225 KB)

Thành công! Bạn đã sử dụng phương pháp nén Brotli để nén thêm các tài sản của mình!

Kết luận

Lớp học lập trình này minh hoạ cách brotli có thể giảm thêm kích thước tổng thể của ứng dụng. Khi được hỗ trợ, brotli là một thuật toán nén mạnh mẽ hơn gzip.