Π ΡƒΠ±Ρ€ΠΈΠΊΠΈ
Π‘Π΅Π· Ρ€ΡƒΠ±Ρ€ΠΈΠΊΠΈ

Express + Brotli + WebPack πŸš€

Π’Ρ‹Ρ€Π°ΠΆΠ°ΠΉΡ‚Π΅ ❀️ Π² Ρ„ΠΎΡ€ΠΌΠ΅ Π±Ρ€ΠΎΠ»ΡŒΡ‚ΠΈ с ΠΏΠΎΠΌΠΎΡ‰ΡŒΡŽ WebPack, Ρ‡Ρ‚ΠΎΠ±Ρ‹ ΡΠΎΡ…Ρ€Π°Π½ΠΈΡ‚ΡŒ Π½Π΅ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Ρ… ΠΊΠ»ΠΈΠ΅Π½Ρ‚ΠΎΠ² ⏰ ΠΈ πŸ’΅

Автор ΠΎΡ€ΠΈΠ³ΠΈΠ½Π°Π»Π°: Rachit Gulati.

Π”Π°Π²Π°ΠΉΡ‚Π΅ сТимаСм вмСстС ΠΈ ΡƒΠ·Π½Π°Π΅ΠΌ, ΠΊΠ°ΠΊ Brotli ΠΌΠΎΠΆΠ΅Ρ‚ ΠΏΠΎΠΌΠΎΡ‡ΡŒ Π½Π°ΠΌ ΡƒΠ²Π΅Π»ΠΈΡ‡ΠΈΡ‚ΡŒ ΠΏΡ€ΠΎΠΈΠ·Π²ΠΎΠ΄ΠΈΡ‚Π΅Π»ΡŒΠ½ΠΎΡΡ‚ΡŒ Π½Π°ΡˆΠΈΡ… сайтов. Π― Ρ€Π΅Π°Π»ΠΈΠ·ΠΎΠ²Π°Π» Π΅Π³ΠΎ Π² ΠΎΠ΄Π½ΠΎΠΌ ΠΈΠ· ΠΌΠΎΠΈΡ… Ρ€Π°Π±ΠΎΡ‡ΠΈΡ… ΠΏΡ€ΠΎΠ΅ΠΊΡ‚ΠΎΠ². Π˜Ρ‚Π°ΠΊ, я просто ΠΏΠΎΠ΄ΡƒΠΌΠ°Π» ΠΏΠΎΠ΄Π΅Π»ΠΈΡ‚ΡŒΡΡ своим ΠΎΠΏΡ‹Ρ‚ΠΎΠΌ со всСми.

ΠžΡΠ½ΠΎΠ²Π½Ρ‹Π΅ опрСдСлСния πŸ“–.

ЭкспрСсс: Быстрый, Π½Π΅ΠΎΠΏΠΈΠ½Π½ΠΎΠ²Π°Π½Π½Ρ‹ΠΉ, минималистский Π²Π΅Π±-каркас для Node.js. Π‘Ρ€ΠΎΡ‚ΠΈ: Π­Ρ‚ΠΎ Π±ΠΈΠ±Π»ΠΈΠΎΡ‚Π΅ΠΊΠ° сТатия Π΄Π°Π½Π½Ρ‹Ρ… с ΠΎΡ‚ΠΊΡ€Ρ‹Ρ‚Ρ‹ΠΌ исходным ΠΊΠΎΠ΄ΠΎΠΌ, разработанная Jyrki Alakuijala ΠΈ ZoltΓ‘n Szabadka. Он основан Π½Π° соврСмСнном Π²Π°Ρ€ΠΈΠ°Π½Ρ‚Π΅ Π°Π»Π³ΠΎΡ€ΠΈΡ‚ΠΌΠ° LZ77, кодирования Π₯Π°Ρ„Ρ„ΠΌΠ°Π½Π° ΠΈ модСлирования контСкста 2-Π³ΠΎ порядка. WebPack: Π­Ρ‚ΠΎ ΠΌΠΎΠ΄ΡƒΠ»ΡŒ Bundler. Он ΠΏΡ€ΠΈΠ½ΠΈΠΌΠ°Π΅Ρ‚ ΠΌΠΎΠ΄ΡƒΠ»ΠΈ с зависимостями ΠΈ Π³Π΅Π½Π΅Ρ€ΠΈΡ€ΡƒΠ΅Ρ‚ статичСскиС Π°ΠΊΡ‚ΠΈΠ²Ρ‹, ΠΏΡ€Π΅Π΄ΡΡ‚Π°Π²Π»ΡΡŽΡ‰ΠΈΠ΅ эти ΠΌΠΎΠ΄ΡƒΠ»ΠΈ.

Π”Π°Π²Π°ΠΉΡ‚Π΅ Π½Π°Ρ‡Π½Π΅ΠΌ с Ρ€Π΅Π°Π»ΡŒΠ½ΠΎΠ³ΠΎ Π΄Π΅Ρ€ΡŒΠΌΠ° πŸ’© !!!

Π‘Ρ‹Π»ΠΈ Π΄Π²Π° способа Ρ€Π΅Π°Π»ΠΈΠ·Π°Ρ†ΠΈΠΈ сТатия Π² Express Π½Π°ΠΏΡ€ΡΠΌΡƒΡŽ (Π±Π΅Π· ΠΊΠ°ΠΊΠΎΠ³ΠΎ-Π»ΠΈΠ±ΠΎ Π²Π΅Π±-сСрвСра I.E: Nginx ΠΈ Ρ‚. Π”.):

  1. БтатичСскоС Π·Π΄Π°Π½ΠΈΠ΅ сТатых Ρ„Π°ΠΉΠ»ΠΎΠ² с ΠΏΠΎΠΌΠΎΡ‰ΡŒΡŽ WebPack (любая другая Π·Π°Π΄Π°Ρ‡Π° Frontend ΠΈΠ»ΠΈ Builder) ΠΈ обслуТиваСт ΠΈΡ… ΠΏΠΎ Ρ‚Ρ€Π΅Π±ΠΎΠ²Π°Π½ΠΈΡŽ ΠΏΠΎ ΠΌΠ΅Ρ€Π΅ нСобходимости ΠΊΠ»ΠΈΠ΅Π½Ρ‚Π°.
  2. ДинамичСскоС Π·Π΄Π°Π½ΠΈΠ΅ сТатых Ρ„Π°ΠΉΠ»ΠΎΠ² Π² Ρ‚Π΅Ρ‡Π΅Π½ΠΈΠ΅ Π²Ρ€Π΅ΠΌΠ΅Π½ΠΈ выполнСния (Π²Ρ‹ ΠΌΠΎΠΆΠ΅Ρ‚Π΅ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ Ρ‚Ρ€Π΅Π±ΠΎΠ²Π°Ρ‚ΡŒ («сТатиС»)) Π’ Express для динамичСски компрСссионных Ρ„Π°ΠΉΠ»ΠΎΠ² ΠΈ ΠΎΠ±ΡΠ»ΡƒΠΆΠΈΠ²Π°ΠΉΡ‚Π΅ΡΡŒ ΠΊΠ»ΠΈΠ΅Π½Ρ‚Ρƒ Π½Π° Π»Π΅Ρ‚Ρƒ. Π― Ρ‚ΠΎΠ»ΡŒΠΊΠΎ Ρ€Π΅Π°Π»ΠΈΠ·ΠΎΠ²Π°Π» статичСскоС Π·Π΄Π°Π½ΠΈΠ΅ Ρ„Π°ΠΉΠ»ΠΎΠ². Π’Π°ΠΊ Ρ‡Ρ‚ΠΎ Π΄Π°Π²Π°ΠΉΡ‚Π΅ ΠΏΠΎΠ³ΠΎΠ²ΠΎΡ€ΠΈΠΌ ΠΎΠ± этом Π±ΠΎΠ»Π΅Π΅ ΠΏΠΎΠ΄Ρ€ΠΎΠ±Π½ΠΎ.

БтатичСскоС сТатиС с Express На ΠΏΠ΅Ρ€Π²ΠΎΠΌ шагС, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ строит ваши ΠΏΠ°ΠΊΠ΅Ρ‚Ρ‹ , Π²Ρ‹ ΠΌΠΎΠΆΠ΅Ρ‚Π΅ Π²ΠΊΠ»ΡŽΡ‡ΠΈΡ‚ΡŒ эти Π΄Π²Π° ΠΏΠ»Π°Π³ΠΈΠ½Π° Π‘ΠΆΠ°Ρ‚ΠΈΠ΅ - WebPack-Plugin ΠΈ brotli-webpack-plugin ΠžΡ‚ΠΊΠ°Π·

const CompressionPlugin = require('compression-webpack-plugin');
const BrotliPlugin = require('brotli-webpack-plugin');
module.exports = {
plugins: [
 new CompressionPlugin({
 asset: '[path].gz[query]',
 algorithm: 'gzip',
 test: /\.js$|\.css$|\.html$/,
 threshold: 10240,
 minRatio: 0.8
 }),
 new BrotliPlugin({
 asset: '[path].br[query]',
 test: /\.js$|\.css$|\.html$/,
 threshold: 10240,
 minRatio: 0.8
 })
]
}

Π­Ρ‚ΠΈ ΠΏΠ»Π°Π³ΠΈΠ½Ρ‹ Π±ΡƒΠ΄ΡƒΡ‚ Π³Π΅Π½Π΅Ρ€ΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ ΠΊΠ°ΠΊ gzip, Ρ‚Π°ΠΊ ΠΈ brotli file для всСх Π²Π°ΡˆΠΈΡ… связков, Ρ‚.Π΅. Ссли имя ΠΏΡƒΡ‡ΠΊΠ° ‘vendor_d0cfe49e718C136CFE49E718C136C61.js, Π²Ρ‹ ΠΏΠΎΠ»ΡƒΡ‡ΠΈΡ‚Π΅ Vendor_D0CFE49E718C136C661.js.gzip ΠΈ vendor_d0c661.js.br Π² Ρ‚ΠΎΠΌ ΠΆΠ΅ ΠΊΠ°Ρ‚Π°Π»ΠΎΠ³Π΅ (Π΄Π°Π²Π°ΠΉΡ‚Π΅ ΠΏΡ€Π΅Π΄ΠΏΠΎΠ»ΠΎΠΆΠΈΠΌ, Ρ‡Ρ‚ΠΎ это /dist/Static/ vendor_d0cfe49e718c1366c661.js. * На Π΄Π°Π½Π½Ρ‹ΠΉ ΠΌΠΎΠΌΠ΅Π½Ρ‚).

PS: ΠŸΡ€ΠΈΠ²Π΅Π΄Π΅Π½Π½Ρ‹ΠΉ Π²Ρ‹ΡˆΠ΅ ΠΊΠΎΠ΄ Π±ΡƒΠ΄Π΅Ρ‚ Π³Π΅Π½Π΅Ρ€ΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ Ρ‚ΠΎΠ»ΡŒΠΊΠΎ .gzip ΠΈ .br, Ссли minratio 0,8 достигаСтся Π²ΠΎ врСмя сТатия Ρ„Π°ΠΉΠ»ΠΎΠ². Π’Π°ΠΊΠΈΠΌ ΠΎΠ±Ρ€Π°Π·ΠΎΠΌ, Π² случаС ΠΎΡ‡Π΅Π½ΡŒ ΠΌΠ°Π»Π΅Π½ΡŒΠΊΠΈΡ… Ρ„Π°ΠΉΠ»ΠΎΠ² GZIP ΠΈ BR Ρ„Π°ΠΉΠ»Ρ‹ Π½Π΅ Π±ΡƒΠ΄ΡƒΡ‚ сгСнСрированы. ΠŸΡ€ΠΈΡ‡ΠΈΠ½Π° Π² Ρ‚ΠΎΠΌ, Ρ‡Ρ‚ΠΎ врСмя Π² сТимании ΠΈ распарковании костлССС, Ρ‡Π΅ΠΌ фактичСский Ρ„Π°ΠΉΠ», обслуТиваСмый Π±Π΅Π· сТатия.

Π’Π°ΠΌ Ρ‚Π°ΠΊΠΆΠ΅ ΠΌΠΎΠΆΠ΅Ρ‚ ΠΏΠΎΡ‚Ρ€Π΅Π±ΠΎΠ²Π°Ρ‚ΡŒΡΡ ΡƒΡΡ‚Π°Π½ΠΎΠ²ΠΈΡ‚ΡŒ ΠΏΡƒΠ±Π»ΠΈΡ‡Π½Ρ‹ΠΉ ΠΏΡƒΡ‚ΡŒ Π² ΠΊΠΎΠ½Ρ„ΠΈΠ³ΡƒΡ€Π°Ρ†ΠΈΠΈ Π²Ρ‹Ρ…ΠΎΠ΄Π° WebPack Π² Β«/StaticΒ». Он Π±ΡƒΠ΄Π΅Ρ‚ ΡƒΠΊΠ°Π·Ρ‹Π²Π°Π΅Ρ‚ ΠΏΡƒΠ±Π»ΠΈΡ‡Π½Ρ‹ΠΉ адрСс URL-адрСса Π²Ρ‹Ρ…ΠΎΠ΄Π½Ρ‹Ρ… Ρ„Π°ΠΉΠ»ΠΎΠ² ΠΏΡ€ΠΈ ΡƒΠΏΠΎΠΌΠΈΠ½Π°Π½ΠΈΠΈ Π² Π±Ρ€Π°ΡƒΠ·Π΅Ρ€Π΅. Π§Ρ‚ΠΎ ΠΏΠΎΠΌΠΎΠΆΠ΅Ρ‚ Π½Π°ΠΌ Ρ„ΠΈΠ»ΡŒΡ‚Ρ€ΠΎΠ²Π°Ρ‚ΡŒ URL-адрСс запроса ΠΈ ΠΏΠΎΠ΄Π°Π²Π°Ρ‚ΡŒ Ρ„Π°ΠΉΠ»Ρ‹ с ΠΏΠΎΠΌΠΎΡ‰ΡŒΡŽ Express-Static-Gzip Fonly Static, Ссли URL состоит ΠΈΠ· Β«/StaticΒ».

output: {
path: '/dist/static',
filename: '[name]_[chunkhash].js',
chunkFilename: '[id].[chunkhash].js',
publicPath: '/static/',
},

На Π²Ρ‚ΠΎΡ€ΠΎΠΌ этапС, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ Π΄ΠΎΠ»ΠΆΠ΅Π½ ΡΠ»ΡƒΠΆΠΈΡ‚ΡŒ ΠΏΡ€Π°Π²ΠΈΠ»ΡŒΠ½ΠΎΠΌΡƒ Ρ„Π°ΠΉΠ»Ρƒ Π½Π° основС Π²Ρ…ΠΎΠ΄Π½Ρ‹Ρ… Π·Π°Π³ΠΎΠ»ΠΎΠ²ΠΊΠΎΠ² ΠΈΠ· клиСнтского Π±Ρ€Π°ΡƒΠ·Π΅Ρ€Π° ΠžΡ‚ΠΊΠ°Π· ΠœΡ‹ Π±ΡƒΠ΄Π΅ΠΌ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ Express-Static-Gzip

aaa.png.png.
var express = require("express");
var expressStaticGzip = require("express-static-gzip");
var app = express();
// app.use(express.static(path.join(__dirname))); This was used previously with express.
app.use("/", expressStaticGzip(path.join(__dirname), {
 enableBrotli: true
}));

ΠŸΡ€ΠΈΠ²Π΅Π΄Π΅Π½Π½Ρ‹ΠΉ Π²Ρ‹ΡˆΠ΅ ΠΊΠΎΠ΄ являСтся настройкой ΠΊΠΎΠ΄Π° ΠΏΠΎ ΡƒΠΌΠΎΠ»Ρ‡Π°Π½ΠΈΡŽ ΠΈΠ· Β«Express-Static-GzipΒ», Π½ΠΎ я Ρ…ΠΎΡ‚Π΅Π» ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ Ρ‚ΠΎΠ»ΡŒΠΊΠΎ статичСскиС Ρ„Π°ΠΉΠ»Ρ‹ ΠΈΠ· этой Π±ΠΈΠ±Π»ΠΈΠΎΡ‚Π΅ΠΊΠΈ. Если Ρ„Π°ΠΉΠ» Π½Π΅ сущСствуСт, я Ρ…ΠΎΡ‚Π΅Π» Π±Ρ€ΠΎΡΠΈΡ‚ΡŒ ΠΎΡˆΠΈΠ±ΠΊΡƒ, ΠΈ ΠΌΠΎΠΉ ΠΊΠΎΠ΄ Π½Π΅ Π΄ΠΎΠ»ΠΆΠ΅Π½ ΠΈΠ΄Ρ‚ΠΈ дальшС Π½Π° Π΄Ρ€ΡƒΠ³ΠΈΠ΅ ΠΌΠ°Ρ€ΡˆΡ€ΡƒΡ‚Ρ‹. Π˜Ρ‚Π°ΠΊ, я Ρ‚ΠΎΠ»ΡŒΠΊΠΎ Π½Π΅ΠΌΠ½ΠΎΠ³ΠΎ Π²Π·Π»ΠΎΠΌΠ°Π» Π² исходном ΠΊΠΎΠ΄Π΅ ΠΈ создал Π½ΠΎΠ²Ρ‹ΠΉ ΠΏΡ€ΠΎΠΌΠ΅ΠΆΡƒΡ‚ΠΎΡ‡Π½Ρ‹ΠΉ Ρ„Π°ΠΉΠ» Compression.js.

НиТС ΠΏΡ€ΠΈΠ²Π΅Π΄Π΅Π½ Π²Π·Π»ΠΎΠΌΠ°Π½Π½Ρ‹ΠΉ ΠΊΠΎΠ΄:

var express = require("express");
const expressStaticGzip = require('compression'); // compression.js gist is available on the github.
var app = express();
 
app.get('*', expressStaticGzip(path.join(__dirname), {
 urlContains: 'static/',
 fallthrough: false,
 enableBrotli: true,
}));

Π•ΡΡ‚ΡŒ Ρ‚Ρ€ΠΈ ΠΏΠ°Ρ€Π°ΠΌΠ΅Ρ‚Ρ€Π°, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Π΅ я использовал здСсь

1 ** URLContains: ** Π­Ρ‚ΠΎ ΠΏΡ€ΠΎΠ²Π΅Ρ€ΠΈΡ‚, Π±ΡƒΠ΄Π΅Ρ‚ Π»ΠΈ ΠΎΡ€ΠΈΠ³ΠΈΠ½Π°Π»ΡŒΠ½Ρ‹ΠΉ URL запроса «статичСский/Β» Π² Π½Π΅ΠΌ. Π’ΠΎΠ³Π΄Π° Ρ‚ΠΎΠ»ΡŒΠΊΠΎ ΠΏΠΎΠ΄Π°Π²Π°Ρ‚ΡŒ Ρ„Π°ΠΉΠ»Ρ‹ Ρ‡Π΅Ρ€Π΅Π· этот ΠΏΠ»Π°Π³ΠΈΠ½, Π΅Ρ‰Π΅ ΠΈΠ³Π½ΠΎΡ€ΠΈΡ€ΡƒΠΉΡ‚Π΅ URL. 2. Блэст: Π­Ρ‚ΠΎ Π΄ΠΎΠ»ΠΆΠ½ΠΎ Π±Ρ‹Ρ‚ΡŒ Π»ΠΎΠΆΠ½ΠΎ, Ρ‡Ρ‚ΠΎΠ±Ρ‹ Π±Ρ€ΠΎΡΠΈΡ‚ΡŒ ΠΎΡˆΠΈΠ±ΠΊΡƒ, Ссли Ρ„Π°ΠΉΠ», ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ Π²Ρ‹ ΠΈΡ‰Π΅Ρ‚Π΅, Π½Π΅ сущСствуСт Π² ΠΊΠ°Ρ‚Π°Π»ΠΎΠ³Π΅ Path.join (__ dirname), ΠΈ URL-адрСс Β«URLContainsΒ». 3. Enablebrotli: Он ΠΏΡ€ΠΎΠ²Π΅Ρ€ΠΈΡ‚, доступСн Π»ΠΈ Ρ„Π°ΠΉΠ» Brotli Π½Π° Path.join (__ dirname), ΠΈ ΡΠΎΠΎΡ‚Π²Π΅Ρ‚ΡΡ‚Π²ΡƒΡŽΡ‰ΠΈΠ΅ Π·Π°Π³ΠΎΠ»ΠΎΠ²ΠΊΠΈ Π·Π°ΠΏΡ€Π°ΡˆΠΈΠ²Π°ΡŽΡ‚ΡΡ ΠΊΠ»ΠΈΠ΅Π½Ρ‚ΠΎΠΌ, Π·Π°Ρ‚Π΅ΠΌ ΠΎΠ±ΡΠ»ΡƒΠΆΠΈΠ²Π°ΡŽΡ‚ Ρ„Π°ΠΉΠ» .br. НиТС ΠΏΡ€ΠΈΠ²Π΅Π΄Π΅Π½ Π³ΠΈΠ΄ с компрСссиСй .js. Π― Π²Π·Π»ΠΎΠΌΠ°Π» с Π»ΠΈΠ½ΠΈΠΈ 59-65.

const mime = require('mime');
const serveStatic = require('serve-static');
const fileSystem = require('fs');

module.exports = expressStaticGzip;

/**
 * Generates a middleware function to serve static files.
 * It is build on top of the express.static middleware.
 * It extends the express.static middleware with
 * the capability to serve (previously) gziped files. For this
 * it asumes, the gziped files are next to the original files.
 * @param {string} rootFolder: folder to staticly serve files from
 * @param {{enableBrotli:boolean,
 * customCompressions:[{encodingName:string,fileExtension:string}],
 * indexFromEmptyFile:boolean}} options: options to change module behaviour
 * @returns express middleware function
 */
function expressStaticGzip(rootFolder, options) {
  options = options || {};
  if (typeof (options.indexFromEmptyFile) === 'undefined') options.indexFromEmptyFile = true;

    // create a express.static middleware to handle serving files
  const defaultStatic = serveStatic(rootFolder, options);
  const compressions = [];
  const files = {};

    // read compressions from options
  setupCompressions();

    // if at least one compression has been added, lookup files
  if (compressions.length > 0) {
    findAllCompressionFiles(fileSystem, rootFolder);
  }

  return function middleware(req, res, next) {
    changeUrlFromEmptyToIndexHtml(req);

        // get browser's' supported encodings
    const acceptEncoding = req.header('accept-encoding');

        // test if any compression is available
    const matchedFile = files[req.path];
    console.log(req.originalUrl, matchedFile);
    if (matchedFile) {
        // as long as there is any compression available for this
        // file, add the Vary Header (used for caching proxies)
      res.setHeader('Vary', 'Accept-Encoding');

                // use the first matching compression to serve a compresed file
      const compression =
            findAvailableCompressionForFile(matchedFile.compressions, acceptEncoding);
      if (compression) {
        convertToCompressedRequest(req, res, compression);
      }
    }

      // allways call the default static file provider
    defaultStatic(req, res, (err) => {
      if (err && (req.originalUrl.indexOf(options.urlContains) > -1)) {
        console.log('Hola', req.originalUrl, err);
        return res.status(404).json({ error: `No file found with ${req.originalUrl}` });
      }
      return next();
    });
  };

    /**
     * Reads the options into a list of available compressions.
     */
  function setupCompressions() {
        // register all provided compressions
    if (options.customCompressions && options.customCompressions.length > 0) {
      for (let i = 0; i < options.customCompressions.length; i += 1) {
        const customCompression = options.customCompressions[i];
        registerCompression(customCompression.encodingName, customCompression.fileExtension);
      }
    }

        // enable brotli compression
    if (options.enableBrotli) {
      registerCompression('br', 'br');
    }

        // gzip compression is enabled by default
    registerCompression('gzip', 'gz');
  }

    /**
     * Changes the url and adds required headers to serve a compressed file.
     * @param {Object} req
     * @param {Object} res
     */
  function convertToCompressedRequest(req, res, compression) {
    const type = mime.lookup(req.path);
    const charset = mime.charsets.lookup(type);
    let search = req.url.split('?').splice(1).join('?');

    if (search !== '') {
      search = `?${search}`;
    }

    req.url = req.path + compression.fileExtension + search;
    res.setHeader('Content-Encoding', compression.encodingName);
    res.setHeader('Content-Type', type + (charset ? `; charset=${charset}` : ''));
  }

    /**
     * In case it's enabled in the options and the
     * requested url does not request a specific file, "index.html" will be appended.
     * @param {Object} req
     */
  function changeUrlFromEmptyToIndexHtml(req) {
    if (options.indexFromEmptyFile && req.url.endsWith('/')) {
      req.url += 'index.html';
    }
  }

    /**
     * Searches for the first matching compression available from the given compressions.
     * @param {[Compression]} compressionList
     * @param {string} acceptedEncoding
     * @returns
     */
  function findAvailableCompressionForFile(compressionList, acceptedEncoding) {
    if (acceptedEncoding) {
      for (let i = 0; i < compressionList.length; i += 1) {
        if (acceptedEncoding.indexOf(compressionList[i].encodingName) >= 0) {
          return compressionList[i];
        }
      }
    }
    return null;
  }

    /**
     * Picks all files into the matching compression's file list. Search is done recursively!
     * @param {Object} fs: node.fs
     * @param {string} folderPath
     */
  function findAllCompressionFiles(fs, folderPath) {
    const filesMain = fs.readdirSync(folderPath);
        // iterate all files in the current folder
    for (let i = 0; i < filesMain.length; i += 1) {
      const filePath = `${folderPath}/${filesMain[i]}`;
      const stats = fs.statSync(filePath);
      if (stats.isDirectory()) {
                // recursively search folders and append the matching files
        findAllCompressionFiles(fs, filePath);
      } else {
        addAllMatchingCompressionsToFile(filesMain[i], filePath);
      }
    }
  }

    /**
     * Takes a filename and checks if there is any compression type matching the file extension.
     * Adds all matching compressions to the file.
     * @param {string} fileName
     * @param {string} fillFilePath
     */
  function addAllMatchingCompressionsToFile(fileName, fullFilePath) {
    for (let i = 0; i < compressions.length; i += 1) {
      if (fileName.endsWith(compressions[i].fileExtension)) {
        addCompressionToFile(fullFilePath, compressions[i]);
        return;
      }
    }
  }

    /**
     * Adds the compression to the file's list of available compressions
     * @param {string} filePath
     * @param {Compression} compression
     */
  function addCompressionToFile(filePath, compression) {
    const srcFilePath = filePath.replace(compression.fileExtension, '').replace(rootFolder, '');
    const existingFile = files[srcFilePath];
    if (!existingFile) {
      files[srcFilePath] = { compressions: [compression] };
    } else {
      existingFile.compressions.push(compression);
    }
  }

    /**
     * Registers a new compression to the module.
     * @param {string} encodingName
     * @param {string} fileExtension
     */
  function registerCompression(encodingName, fileExtension) {
    if (!findCompressionByName(encodingName)) {
      compressions.push(new Compression(encodingName, fileExtension));
    }
  }

    /**
     * Constructor
     * @param {string} encodingName
     * @param {string} fileExtension
     * @returns {encodingName:string, fileExtension:string,files:[Object]}
     */
  function Compression(encodingName, fileExtension) {
    this.encodingName = encodingName;
    this.fileExtension = `.${fileExtension}`;
  }

    /**
     * Compression lookup by name.
     * @param {string} encodingName
     * @returns {Compression}
     */
  function findCompressionByName(encodingName) {
    for (let i = 0; i < compressions.length; i += 1) {
      if (compressions[i].encodingName === encodingName) { return compressions[i]; }
    }
    return null;
  }
}

Анализ Ρ€Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚ΠΎΠ²:

Π”Π°Π²Π°ΠΉΡ‚Π΅ сравним ΠΏΡ€ΠΎΠΈΠ·Π²ΠΎΠ΄ΠΈΡ‚Π΅Π»ΡŒΠ½ΠΎΡΡ‚ΡŒ сайта с Brotli ΠΈΠ»ΠΈ GZIP ΠΈΠ»ΠΈ просто нСсТатым Π·Π°ΠΌΠΈΠ½ΠΈΡ€ΠΎΠ²Π°Π½Π½Ρ‹ΠΌ Ρ„Π°ΠΉΠ»Π°ΠΌΠΈ.

Π’ Π‘ΠΎΠ³Π΅ ΠΌΡ‹ довСряСм, всС ΠΎΡΡ‚Π°Π»ΡŒΠ½Ρ‹Π΅ приносят Π΄Π°Π½Π½Ρ‹Π΅. -W. Эдвардс Π”Π΅ΠΌΠΈΠ½Π³

Π”Π°Π²Π°ΠΉΡ‚Π΅ ΠΊΠΎΠΏΠ°Ρ‚ΡŒ ⛏ Π² Π°Π½Π°Π»ΠΈΠ· ΠΈ Π½Π°ΠΉΠ΄ΠΈΡ‚Π΅ Ρ€Π΅Π°Π»ΡŒΠ½Ρ‹Π΅ числа. ΠŸΠΎΡΠΊΠΎΠ»ΡŒΠΊΡƒ это ΠΌΠΎΠ΅ Ρ€Π°Π±ΠΎΡ‡Π΅Π΅ мСсто Π²Π΅Π±-сайта, ΠΊΠΎΡ‚ΠΎΡ€ΠΎΠ΅ ΠΌΡ‹ использовали для Π²Π½ΡƒΡ‚Ρ€Π΅Π½Π½Π΅ΠΉ Ρ†Π΅Π»ΠΈ. Π― Π½Π΅ ΠΌΠΎΠ³Ρƒ ΠΏΠΎΠ΄Π΅Π»ΠΈΡ‚ΡŒΡΡ настоящим ΡΠΊΡ€ΠΈΠ½ΡˆΠΎΡ‚ΠΎΠΌ здСсь, Π½ΠΎ Π½ΠΈΠΆΠ΅ Ρ€Π΅Π°Π»ΡŒΠ½Ρ‹Π΅ числа, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Π΅ я собирал ΠΏΡ€ΠΈ тСстировании сайта Π½Π° Ρ€Π°Π·Π½Ρ‹Ρ… Ρ‚ΠΈΠΏΠ°Ρ… компрСссиях.

aaaa.png.
  1. Brotli составляСт ~ 8% ((7.24-6,67)/7.24), эффСктивно, Ρ‡Π΅ΠΌ GZIP ΠΈ 65,7% (19,48-6,67)/19,48), эффСктивно, Ρ‡Π΅ΠΌ нСсТатый Ρ„Π°ΠΉΠ». Если Π±Ρ€Π°ΡƒΠ·Π΅Ρ€ Π½Π΅ смоТСт ΡΠ»ΡƒΠΆΠΈΡ‚ΡŒ Brotli, Ρƒ нас Π΅ΡΡ‚ΡŒ Π·Π°Π³Ρ€ΡΠ·Π½ΠΈΡ‚Π΅Π»ΡŒΠ½Ρ‹ΠΉ Π² GZIP, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ составляСт 62% (19,48-7.24)/19,48), эффСктивнСС нСсТатого Ρ„Π°ΠΉΠ»Π°. Π’Π°ΠΊ Ρ‡Ρ‚ΠΎ здСсь Ρƒ нас Π²Ρ‹ΠΈΠ³Ρ€Π°ΡŽΡ‚ ΡΠΈΡ‚ΡƒΠ°Ρ†ΠΈΡŽ.
  2. Π’Π΅ΠΏΠ΅Ρ€ΡŒ Π΄Π°Π²Π°ΠΉΡ‚Π΅ ΠΏΡ€ΠΎΠ°Π½Π°Π»ΠΈΠ·ΠΈΡ€ΡƒΠ΅ΠΌ Ρ€Π°Π·ΠΌΠ΅Ρ€. Π‘Ρ€ΠΎΡ‚ΠΈ – это ((586-458)/586) ~ 21,85% эффСктивно, Ρ‡Π΅ΠΌ gzip, ΠΈ ΠΎΠ½ΠΎ Π΅ΡΡ‚ΡŒ ((2.5 1024-458)/2.5 1024) ~ 82,1% эффСктивно, Ρ‡Π΅ΠΌ нСсТатыС Ρ„Π°ΠΉΠ»Ρ‹. Π’Π°ΠΊΠΈΠΌ ΠΎΠ±Ρ€Π°Π·ΠΎΠΌ, ΠΌΠ½ΠΎΠ³ΠΎ пропускной способности ΠΌΠΎΠΆΠ½ΠΎ ΡΠΎΡ…Ρ€Π°Π½ΠΈΡ‚ΡŒ с ΠΏΠΎΠΌΠΎΡ‰ΡŒΡŽ сТатия Π±Ρ€ΠΎΡ‚Π»Π΅ΠΉ. НСкоторыС Π΄Π°Π½Π½Ρ‹Π΅ для ΠΌΠ΅Π΄Π»Π΅Π½Π½ΠΎΠΉ сСти 3G:
Aaaaa.png.

Бпасибо всСм Π·Π° Ρ‡Ρ‚Π΅Π½ΠΈΠ΅ Π΄ΠΎ сих ΠΏΠΎΡ€. Если Π²Π°ΠΌ это нравится ΠΈ Ρ…ΠΎΡ‡Ρƒ, Ρ‡Ρ‚ΠΎΠ±Ρ‹ я написал большС. ΠŸΠΎΠΆΠ°Π»ΡƒΠΉΡΡ‚Π°, Π΄Π°ΠΉΡ‚Π΅ ΠΌΠ½Π΅ Π·Π½Π°Ρ‚ΡŒ.