- PVSM.RU - https://www.pvsm.ru -

Почему не работает Tree Shaking и как с этим жить

Почему не работает Tree Shaking и как с этим жить - 1

В нашей предыдущей статье [1] про голосовых ботов для Рокетбанка читатели возмутились, что в 2017 году примеры JavaScript для облака Voximplant написаны на ES5. У нас в облаке сильно модифицированный SpiderMonkey, специально обученный не течь и не падать. Тысячи одновременных звонков с параллельно выполняемым JavaScript как бы намекают, что нода – для нас не вариант. Тем не менее, никто не мешает использовать транспайлеры, компилировать ES2017/TypeScript/Elm/Whatever в старый добрый JavaScript и загружать результаты компиляции с помощью Continuous Integration [2]. При таком раскладе возникает соблазн использовать все последние достижения из npmjs, собирая весь код в один ES5 бандл. И вот тут нас ждет засада: даже один метод из lodash дает на выходе бандл размером в полмегабайта. И не похоже, чтобы рекламируемый последние пару лет tree shaking работал.

Кто трясет деревья?

Огромные JavaScript бандлы — это не очень хорошо. В мире браузеров они увеличивают время загрузки страницы: сначала такой бандл надо скачать, потом распарсить, потом выполнить. В мире backend и скриптов-в-облаке тоже свои нюансы. Чтобы выполнять тысячи звонков в секунду, контролируемых через JavaScript, наш SpiderMonkey ограничивает память JavaScript сессии 16-ю мегабайтами. Это на все: исходный код, ast, структуры данных. Архитектура нашей платформы подразумевает, что в облаке выполняется код, который должен работать в реальном времени. А все «тяжелые» вещи можно перенести на свой backend и делать к нему HTTP запросы прямо во время звонка. Беда в том, что пара методов из lodash выглядят как замечательная идея для легковесного кода в облаке. Хоп — и плюс полмегабайта к результирующему JavaScript.

Сообщество JavaScript разработчиков знает об этой проблеме давно, и кроме «давайте выкинем все пробелы и переименуем что не страшно в однобуквенные варианты» (uglify до dead code elimination) активно разрабатывает «Tree Shaking». В идеале, «Tree Shaking» должно убирать весь неиспользуемый код: импорты, вызовы методов, глобальные переменные. И для нашего кода мы должны получить несколько функций lodash, наш код – и всё. А вместо этого получаем lodash целиком. WTF?

Webpack, Rollup и Uglify

Поддержка tree shaking считается сильной стороной rollup, заявлена в последних версиях webpack и уже давно присутствует в UglifyJS в виде «dead code elimination». О разнице между «dead code elimination» два года назад очень хорошо написал [3] автор Rollup: если dead code elimination получает на вход скомпилированный бандл и пытается выкинуть из него неиспользуемый код, то tree shaking работает с AST кода во время компиляции и пытается включить только тот код, который используется. Кстати, Webpack рассчитан на комбинированный подход: вначале tree shaking во время сборки бандла, а затем dead code elimination с помощью UglifyJS плагина.

Только в реальном мире Tree Shaking не работает.

По словам самих авторов, определить используемый код в слабо типизированным языке – задача нетривиальная. И, чтобы ничего не сломать, в непонятных ситуациях код всегда включается. К несчастью, примерами таких «непонятных» ситуаций являются самые популярные библиотеки общего назначения: lodash, underscore, – все вот эти ребята.

Что делать?

Можно, конечно, подождать еще пару лет. Вывод типов становится лучше, ведутся работы [4] над поддержкой tree shaking для типизированных диалектов вроде TypeScript. Но писать ES2017 код с библиотеками хочется сейчас. Без многомегабайтных бандлов.

Сообщество и об этой проблеме знает, поэтому сейчас активно используется временное решение: большие монстры вроде lodash разбиваются на огромную кучу мелких модулей, который можно импортить по отдельности. И тут уже tree shaking сбоев не дает:

Конечно, это демонстрация «в лоб» с пустыми конфигами webpack/rollup. Можно докрутить и до более впечатляющих цифр, но основная идея в том, что не стоит огорчаться тысячам зависимостей, которые ставит yarn. Минимально допиленный напильником стек позволяет выкинуть большую часть неиспользуемого кода и получить вполне читаемый бандл для загрузки в Voximplant или любую другую платформу, которые программируется на JavaScript.

Картинка до ката из статьи про tree shaking в webpack 2 [5]

Автор: eyeofhell

Источник [6]


Сайт-источник PVSM.RU: https://www.pvsm.ru

Путь до страницы источника: https://www.pvsm.ru/javascript/257151

Ссылки в тексте:

[1] предыдущей статье: https://habrahabr.ru/company/Voximplant/blog/329444/

[2] Continuous Integration: https://habrahabr.ru/company/Voximplant/blog/269473/

[3] написал: https://medium.com/@Rich_Harris/tree-shaking-versus-dead-code-elimination-d3765df85c80

[4] работы: https://alexjoverm.github.io/2017/03/06/Tree-shaking-with-Webpack-2-TypeScript-and-Babel/

[5] статьи про tree shaking в webpack 2: https://www.linkedin.com/pulse/tree-shaking-webpack-2-sonia-ramnani

[6] Источник: https://habrahabr.ru/post/330148/