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 về việc rút gọn và nén tải trọng mạng, đồng thời giả định rằng bạn đã nắm được các khái niệm cơ bản về việc 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 tìm hiểu cách nén Brotli có thể giảm hơn nữa 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

Trước khi đi sâu vào việc thêm tính nă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 Remix để chỉnh sửa (Remix) để chỉnh sửa dự án.
  2. Để xem trước trang web, hãy nhấn vào View App (Xem ứng dụng), sau đó nhấn vào Fullscreen toàn màn hình (Toàn màn hình).

Trong Lớp học lập trình về việc rút gọn và nén các phần tải trọng mạng trước đây, chúng tôi đã giảm kích thước của main.js từ 225 KB xuống còn 61,6 KB. Trong lớp học lập trình này, bạn sẽ tìm hiểu cách 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ể cung cấp kết quả nén văn bản tốt hơn nữa so với 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 21% so với gzip đố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 các phiên bản mới nhất của hầu hết các trình duyệt. Các trình duyệt hỗ trợ Brotli sẽ bao gồm br trong 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 thông qua 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

Bật Brotli

Nén động

Tính năng nén động bao gồm việc nén các thành phần một cách nhanh chóng theo yêu cầu của trình duyệt.

Ưu điểm

  • Bạn không cần thực hiện việc tạo và cập nhật các phiên bản nén đã lưu của thành phần.
  • Tính năng nén nhanh hoạt động đặc biệt hiệu quả cho các trang web được tạo động.

Nhược điểm

  • Việc nén các 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ể dẫn đến kết quả về hiệu suất khi người dùng chờ các thành phần nén trước khi được máy chủ gửi đi.

Nén động bằng Node/Express

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

var express = require('express');

var app = express();

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

var listener = app.listen(process.env.PORT, function() {
  console.log('Your app is listening on port ' + listener.address().port);
});

Hiện tại, bạn chỉ cần nhập express và sử dụng phần mềm trung gian express.static để tải tất cả các tệp HTML, JS và CSS tĩnh trong public/directory (và những tệp đó sẽ được tạo bằng gói web với mọi bản dựng).

Để đảm bảo tất cả thành phần đượ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 dưới dạng devDependency trong package.json:

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

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

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

Sau đó, hãy thêm thư viện này làm phần mềm trung gian trước khi liên kết express.static:

//...
var 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 bằng tính năng nén Brotli động

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! Nhỏ hơn khoảng 14% so với gzip (61,6 KB).

Nén tĩnh

Ý tưởng của phương pháp nén tĩnh là nén và lưu trước các tài sản.

Ưu điểm

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

Nhược điểm

  • Thành phần cần được nén với mọi bản dựng. Thời gian xây dựng có thể tăng đáng kể nếu sử dụng các mức nén cao.

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

Vì phương pháp nén tĩnh bao gồm việc nén tệp trước, nên bạn có thể sửa đổi chế độ cài đặt gói web để nén các thành phần trong bước tạo bản dựng. Bạn có thể sử dụng brotli-webpack-plugin để thực hiện việc này.

Bắt đầu bằng cách thêm 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à đưa 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 tài sản ban đầu.
  • test: Hệ thống sẽ xử lý tất cả thành phần khớp với RegExp này (tức là thành phần JavaScript kết thúc bằng .js).

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

Khi ứng dụng tải lại và tạo lại, 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ủ Nút phân phát.

  1. Nhấp vào nút Công cụ.
  2. Hãy 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 để thay đổi thành thư mục public và xem tất cả các tệp trong thư mục đó:
cd public
ls -lh
Kích thước gói khi nén tĩnh Brotli

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 các tệp được nén bằng phương thức Brotli này bất cứ khi nào phiên bản JS ban đầu đượ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 mới trong server.js trước khi các tệp được phân phát bằng express.static.

var express = require('express');

var 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 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 đó, hàm callback đượ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 số này sẽ phù hợp với mọi điểm cuối được kích hoạt để tìm nạp 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 trình tự này sẽ tiếp tục với mọi lệnh gọi lại có thể xảy ra tiếp theo.

Vì một số trình duyệt có thể không hỗ trợ tính năng nén brotli, nên hãy chắc chắ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 tiêu đề yêu cầu Accept-Encoding bao gồm br:

var express = require('express');

var 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 nhìn lại bảng điều khiển Mạng một lần nữa.

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

Thành công! Bạn đã sử dụng tính năng nén Brotli để nén thêm tài sản!

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. Trong trường hợp được hỗ trợ, brotli là thuật toán nén mạnh hơn gzip.