Бюджэты выконання для JavaScript: аплявенне лімітавання пакетаў у CI
Дазнаецеся, чаму JavaScript коштае значная большая сума, чым трывалась яго загрузка, як задаць рэальны бюджет на прытлумленасць, а таксама як за дапамою webpack заблокаваць стварэнне проекта, які перакроюе гэты бюджет.
Крыніцы: The Cost of JavaScript — Performance budgets and why your bundle size is driving users away
Старонка, яка працуе мгновэнна на ноутбуку разработчыка, можа замарзнуць на калькольніку рэальнага кліента на кантэкстнах секундах. Разлік рэдкасцю стаўыцься толькі з швайнае сеті: ён вытыкаецца з работы CPU, якой патрабуе кожны кілабайт JavaScript, калі ён прабрацуеся да простага прыстрою. У гэтым кярыі пояснюецца, звыклы той расход, як ператворыць яго на частаку бюджэту на працэсаванне, і як заставіць вашу систему практычнага стварэння адхіліць змяны, якія нарушаюць гэты бюджэт, прычым яны нават не дасягнуць продакшэна.
Разлік межы разработчыка і прыстрою корыстніка
Большасць команд, якія працуюць з фронтэндам, ствараюць і тестуюць на апаратным забезпечэнні, якое ўжо не адпраўляе рэальных умов: савременныя ноутбукі, сяродзеўнія або волокнавыя з’ёднання, і сервер разработчыка, які працуе на localhost. За такіх умов практычна будь-які пакет здаецца швайным, таму розмер пакета часта спрыяецца як чымс, што трэба адчыстыць пазней, а не як элемент дизайна.
Рэальны трафік выглядае інакш. Значная частка візітараў прыходзіць на сяродніх тэлефонах з Андроѓдам, з нестабільным 4G чыстацем або через пераполненыя публічныя сеті Wi-Fi. Узгадаймо дашборд, які выкарыстоўвае многа дадзэнаў і негайна адпавядае ў местным браузеры, пры тым як пад час тэставання на старэйшых iPhone-ах інтэрактыўныя элементы керування зачыняюць працаваць прыблізна за тры секунды. У коде няма нічога нештаціонарнага; проста прыстрою трэба набагато больш часу, каб обрабацаваць той самы скрыпт.
Гэты затрываеў мае эканамічныя наследкі. Дадатковы, неоптымізаваны JavaScript постаўна адкладае момент, калі корыстнік можа весті інтэракцыю, і гэты эфект ўсё бол болючы для критычных процэсаў, такіх як аблогаванне чыстаця або дадаванне айтэму у кошык. Калі гэтыя крокі здаюцца повольнымі, людзі ўжо не ведаюць іх атрымляць, таму саме занадта вялікі пакет можа тыхо адвядзець корыстнікаў.
Чаму JavaScript коштае больш, чым час яго завантажэння
Працаваўшы ўсі гады, затрымка сеті была галоўным бутылчынам, і робота над пасібнасцю была спрямованая на зменшэнне вагі зображэнняў і пакращэнне транспортавання дадзеных, напрыклад, за дапамою HTTP/2. Шырокія проблемы застаюцца актуальнымі, але для JavaScript сёння большым вызваннем є тое, што выконваецца пасля прыбыцьі байтов.
Скрыпта не можа быць выкарыстоўваная, калі завершаецца завантажэнне. Браузер павінен яе аналізаваць, компіляваць і выкананы, прычаму большая частка гэтых дзеянняў выканваецца на галоўным потоку — там самым потоку, які адпавядае за обробку натыскаў, кліканняў і атрыбутаў візуальнага матэрыялу. Цэлкам можліва, каб пакет вагой 400 KB быў шырока завантажаны, але стораніца застаўся нерэагуючай, таму што прыстрой занятый обробкай коду замест таго, каб рэагаваць на вхідныя даны.
У тэлефоне с середнім класам гэты цыкл парсавання, кампілявання і выконавання можа значна пагоршыць Interaction to Next Paint (INP) — показнік, який мерыў швальнасць адпаведзення сторанкі на дзеянні корыстувальніка. Гэты показнік безпаслявно вплывае на рэйтынги Core Web Vitals, і низкія значэння вітал-показніка зазвычай супараднуюцца з нижэйшым рэтам залишання корыстувальніка та гorsымі бізнес-рэзультатамі. Таму будь-яе серйознае старанне па падборчыце гэтых показнікаў должна включаць скорачанне колькасці JavaScript-кода, які мобільныя прыстроі павінны парсаваць і выкананы, а не толькі зменшэнне розмеру завантажвання.
Што такое бюджет на працэздатнасць і як яго задаць
Бюджет на працэс выконання JavaScript — это чыстая мерка, яка абмежвае колькісць коду, які можа мястіцца на сторанцы, маршруце або частцы коду. Тэхнічна ён проста цифра, але яго рэальная ценна заключаецца ў організацыйных аспектах: це даговор, які падпісвае весь калектыв. У замест на тое, каб пасля выпуску адкрываць проблэмы з працэсамі выконання і спяшна ўсё практычваць, бюджет выступае як захоўні механізм, який не дазволяе ім ужо з’яўляцца ў фінальны код.
Практычны савет: Бюджет ператварае праблемы працэсу выконання з чагоś, на што трэба реагаваць, у абмежэння, якія трэба врахоўваць пад час проектавання, так сама як і трэбованні да доступнасці чыстаць безпекі.
Пачатак задання заключаецца у выборы конкрэтных, вимерлівых лімітаў. Шырока аднародна мета — падтрымка розмеру JavaScript-кода критычнага шляху на будзь-яй сторанцы на роўні прыблізна 170 KB пасля стыснення; гэта значэнне выбрана так, каб сярэдняе мобільнае прыстрою было можна швядка досягнуць стану інтэрактыўнасці. Яныя такія цифры трэба пераканацца ў ўзмоўленасці з вашай аудыэнцыяй, але прынцып застаецца тым жа: як толькі ліміт установлена, кожная новая залежнасц чы ўможнасць павінныя з самага першага дня абґрунтаваць свой вага.
Калькі лёгкая ў прыменэнні за дапамогою калькі практычных пунктав:
- Бюджет на кожны маршрут чы точку входу, а не толькі на всю аплікацыю, так каб важкая адміністрацыйная частка не паглотала асигнацыі стартовай сторанцы.
- Зважаць павінны адной і той жа спосабам кожны раз (пасля стыснення проты нестысненага розмеру), каб цифры заставаліся порównымыя между разнымі версіямі.
- Пераглядаць ліміт, калі зменяецца склад вашай аудыэнцыі чы прыстроёў, а не таямна падвышаць яго ў кожны раз, калі версія не запускаецца.
Автоматызацыя перакантролі ў CI/CD
Бюджэты, якія залежаць ад таго, чы гэты чалавек памятае пра ўсё перакантроліваць, дыяжу недаўго. Дадзены функцыяны элемент прадаёцца, апрацоўнік сфокусаваны на логіцы, ніхто не адгледзе звярнення пакета, і выйшоў регрэсіяны прыклад. Ядзін спосаб, які дазволяе масштабавацца, — гэта прабязганне перакантролі безпосередна ў пайплайн, так што кожныя змены адразу ж перакантроліваюцца автаматычна.
Прыметка: Калі перакантролі выконваецца ў CI, кожны pull request перакантроліваецца за бюджэтом, і нікому не трэба памятаць пра гэта.
Інструменты для паблікацыі, такія як webpack, можуць зрабіць гэта за вас: налаштавцыях іх можна задаць, каб вельмі большы выходны файл спрацоўваў як парадок паблікацыі, а не як адзвешчэнне. Тады адзвешчэння прыходзіць негайна, прыўязанае да змены, якая яго вызвала. Якщо запрошэнне да злучэння прыносіць бібліятэку, якая выкладае частаку па большай шырокасейці, чым дазволена, процес паблікацыі стае нерабочым, і автару трэба яго выправіць прычаму перш чым злучыць код.
У наведанай выкладцы викорыстоўваецца опцыя performance з бібліятэкі webpack. Установка значэння hints на 'error' ператварае паведамленні пра вялічыну файлаў у праблемы, якія спакошуюць процес складання. Параметр maxAssetSize абмежвае вялічыну кожного окремага выданага файла (тут 250 КіБ), а maxEntrypointSize — сумарную вялічыну всіх актуальных файлаў для адного входнага тыпу (тут 500 КіБ); оба значэння выражаныя ў байтах. Функцыя assetFilter вялічынае, якія файлы ўзагалі будуць перакантролеваны, у гэтым случае ігноруючы карты выхадных кодаў та файлы JSON, юначэй не выклікаць хутароўкі.
module.exports = {
// ... other webpack configuration ...
performance: {
hints: 'error',
// Emit an error whenever a bundle exceeds the size limits
maxAssetSize: 250 * 1024,
// Maximum size in bytes for any generated asset (e.g., 250 KiB)
maxEntrypointSize: 500 * 1024,
// Maximum size in bytes for an entrypoint (e.g., 500 KiB)
assetFilter: function(assetFilename) {
// Optionally exclude certain assets (e.g., source maps) from performance hints
return !/\.(map|json)$/.test(assetFilename);
}
}
};
Пам’ятайце, што webpack парабялівае гэтыя ліміты з розмерамі файлаў, якія выдаюцца, а гэтыя розмеры зазвычай не ўзроўнаваныя з розмерамі пасля стыснення, якія завантажваюць корыстувальнікі. Якщо ваш бюджет заданы ў стысненых кілабайтах, перакладзіце яго ў нерастысненыя розмеры для гэтай перапачаткованняі, або сконкуруйце яго з окольным крокам, які вымерае розмеры пасля стыснення за дапамою gzip або Brotli.
Стратэгіі, якія трываюць бандлы ў межах бюджету
Бюджет і аўтаматызаваная перапачаткованняя паведамляюць вас, калі вы перакроўлі ліміт; ўтрыманне яго пад лімітом трэбуе цярпелівага інжынерскага падходу. Найэфектывейшыя тэхнікі ўжо вядомы, і яны працуюць найкраща ў сукупнасці.
Раздзелены код па маршрутах і функцыях
Разбій коду — это процес перетворэння адного монолітнага пакета на меншыя часткі, які завантажуюцца за патрэбам. Частым прыкладам ёсць важкая панель адміністрацыі ў корпоратыўным прыкладным програме: завяршваючы ёё завантажэнне за дапамогою дынамічных заповедзей import(), код адкалываецца толькі тады, калі адміністратар фактычна перайходзіць на гэтую сторонку. Звычныя корыстувачы ніколі яго не завантажуюць, што можа зменшыць пачатковы размер пакета на сотні кілабайт.
Дазвольце функцыі «tree shaking» адмахнуцца непатрэбным кодам
Функцыя «tree shaking» усувае элементы, якія ніколі не выкарыстоўваюцца, таму непатрэбныя часткі вашых сабеўных модуляў і бібліятэкаў не потрапляюць у выходны код. Яна найэфектывней працюе з синтаксам ES-модуляў і залежнасцямі, якія публікуюцца у формате, які можна адмахнуць, таму варта пераканацца, як створаны пакет, пры тым, калі вы яго викорыстоўваеце.
Адзяйце: выкарыстоўванне велікай бібліятэкі для адной-едзінай дапаможнай функцыі — адна з найпашчэрэйшых прычын занадто вялікага размеру коду. Шукайце легкія альтэрнатыўны варыянт або імпортуйце толькі тую функцыю, якая вам патрэбна.
Адкладзіце тое, чаго не патрэбуе першы экран
Актыўнае заваношчанне компонентаў, якія не ўскладнююць пачатковы адгляд — такіх як дыялогавыя вікна, элементы, якія з’яўляюцца пад контентам, або рэдка выкарыстоўваныя панелі — адкладае ўскладнення з парсаванням і выконанням да моменту, калі яны стануць неабходныя. У поўнай зусіллі разам з роздзеленням коду і аптимізацыяй структуры коду это дапамагае захаваць галоўную вясь для роботы пры першых секундах, калі корыстувальнікі найбольш верагатна будуць взаімадзейваць.
Заключэнне
- Дорогі ў викорыстоўванні аспект JavaScript на мобільных прыстроях — это яго парсаванне, кампіляванне і выконанне на галоўной вясі, што безпасебна вплывае на INP і іншыя показнікі Core Web Vitals.
performance.hints: 'error' у webpack, дазволяе выявіць регрэсіі ў пул-прызначэннях, якія іх вносяць.