JavaScript

Что такое Tree shaking?

Spread the love

Когда приложение на Javascript достигает определенного размера, его обычно разделяют на модули. Однако, через какое то время, становиться сложно отслеживать все что импортируется и как это используется. В итоге при сборке пакетов, мы можем получить большое количество импортированный кода, который фактически не используется.

Tree shaking (Встряхивание дерева) — это метод оптимизации библиотек путем удаления любого кода из окончательного файла, который фактически не используется.

Допустим, у нас есть файл утилит с некоторыми математическими операциями, которые мы можем использовать в нашем основном скрипте.

mathUtils.js

export function add(a, b) {
    console.log("add");
    return a + b;
}

export function minus(a, b) {
    console.log("minus");
    return a - b;
}

export function multiply(a, b) {
    console.log("multiply");
    return a * b;
}

export function divide(a, b) {
    console.log("divide");
    return a / b;
}

В нашем основном скрипте импортируем и используем только функцию  add().

index.js

import { add } from "./mathUtils";

add(1, 2);

Воспользуемся для сборки webpack. После сборки мы увидим, что все функции из файла  mathUtils.js  включены в финальный пакет, хотя мы только импортировали и использовали функцию  add().

bundle.js

/***/ "./src/mathUtils.js":
/*!**************************!*\
  !*** ./src/mathUtils.js ***!
  \**************************//*! exports provided: add, minus, multiply, divide *//***/ (function(module, __webpack_exports__, __webpack_require__) {

"use strict";
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"add\", function() { return add; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"minus\", function() { return minus; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"multiply\", function() { return multiply; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"divide\", function() { return divide; });\nfunction add(a, b) {\n    console.log(\"add\");\n    return a + b;\n}\n\nfunction minus(a, b) {\n    console.log(\"minus\");\n    return a - b;\n}\n\nfunction multiply(a, b) {\n    console.log(\"multiply\");\n    return a * b;\n}\n\nfunction divide(a, b) {\n    console.log(\"divide\");\n    return a / b;\n}\n\n\n//# sourceURL=webpack:///./src/mathUtils.js?");

/***/ })

Если воспользуемся tree shaking, тогда только то, что мы импортировали и фактически использовали попадет в окончательную сборку.

Как работает tree shaking?

Хотя концепция tree shaking существует примерно с 1990-х годов, она стала доступно в Javascript только с момента появления модулей в стиле ES6. Это потому, что tree shaking может работать только в том случае, если модули являются статическими («static»).

До модулей ES6 у нас были модули CommonJS, которые использовали синтаксис  require(). Такие модули являются динамическими («dynamic»), что означает, что они могут быть импортированы на основе условий.

var myDynamicModule;

if (condition) {
    myDynamicModule = require("foo");
} else {
    myDynamicModule = require("bar");
}

Динамическая природа модулей CommonJS означает, невозможность применение tree shaking, потому что не получится определить, какие модули будут необходимы, до того как код фактически будет запущен.

В ES6 был представлен новый синтаксис для модулей, который полностью статичный. Используя синтаксис  import , мы больше не можем динамически импортировать модуль.

Это не будет работать

if (condition) {
    import foo from "foo";
} else {
    import bar from "bar";
}

Вместо этого мы должны определить весь импорт в глобальной области вне каких-либо условий.

import foo from "foo";
import bar from "bar";

if (condition) {
    // do stuff with foo
} else {
    // do stuff with bar
}

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

От чего избавляет tree shaking?

Tree shaking, по крайней мере, реализация webpack, довольно хорошо удаляет большую часть неиспользуемого кода. Например, импорт, который импортируется, но не используется, впоследствии полностью исключается.

import { add, multiply } from "./mathUtils";

add(1, 2);

В приведенном выше примере функция  multiply() никогда не используется и будет удалена из окончательного пакета.

Так же удаляются свойства импортированных объектов, к которым никогда не осуществляется доступ.

myInfo.js

export const myInfo = {
    name: "Ire Aderinokun",
    birthday: "2 March"
}

index.js

import { myInfo } from "./myInfo.js";

console.log(myInfo.name);

В приведенном выше примере, свойство birthday  никогда не попадает в окончательную сборку, потому что оно фактически нигде не используется.

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

Как насчет «побочных эффектов»?

Побочным эффектом использование tree shaking является необходимость учитывать использование кода, который выполняет какое-то действие при импорте, и не содержат функции экспорта. Хорошим примером этого является использование полифиллов. Полифиллы, как правило, не имеют функции экспорта для использования в основном скрипте, а просто переопределяют некоторые функции.

Tree shaking не может автоматически определить, подобные сценарии, поэтому важно указать их вручную, как мы увидим ниже.

Как использовать tree shake

Tree shaking, как правило, является функции сборщиков пакетов. Например, если вы используете webpack, вы можете просто установить  mode в  production в своем файле конфигурации  webpack.config.js. Это, помимо других опций, так же запускает tree shaking.

module.exports = {
    ...,
    mode: "production",
    ...,
};

Чтобы пометить определенные файлы как исключения для tree shaking, используйте следующий синтаксис в  package.json.

{
    ...,
    "sideEffects": [
        "./src/polyfill.js"
    ],
    ...,
}

Для получения дополнительной информации о том, как использовать tree shaking в webpack, ознакомьтесь с их  документация.

Оригинал

Была ли вам полезна эта статья?
[25 / 4.5]

Spread the love
Editorial Team

View Comments

  • Было бы неплохо упомянуть динамические ES6 модули и как три шейкинг ведет себя с ними

  • По смыслу все ок, но хорошо бы поправить грамматические ляпы в статье(суффиксы, окончания, склонения/спряжения слов), а то мешает восприятию текста

  • В целом нормально но про писи не хватает инофрмации

Recent Posts

Vue 3.4 Новая механика v-model компонента

Краткий перевод: https://vuejs.org/guide/components/v-model.html Основное использование​ v-model используется для реализации двусторонней привязки в компоненте. Начиная с Vue…

12 месяцев ago

Анонс Vue 3.4

Сегодня мы рады объявить о выпуске Vue 3.4 «🏀 Slam Dunk»! Этот выпуск включает в…

12 месяцев ago

Как принудительно пере-отобразить (re-render) компонент Vue

Vue.js — это универсальный и адаптируемый фреймворк. Благодаря своей отличительной архитектуре и системе реактивности Vue…

2 года ago

Проблемы с установкой сертификата на nginix

Недавно, у меня истек сертификат и пришлось заказывать новый и затем устанавливать на хостинг с…

2 года ago

Введение в JavaScript Temporal API

Каким бы ни было ваше мнение о JavaScript, но всем известно, что работа с датами…

2 года ago

Когда и как выбирать между медиа запросами и контейнерными запросами

Все, кто следит за последними событиями в мире адаптивного дизайна, согласятся, что введение контейнерных запросов…

2 года ago