Что такое 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, ознакомьтесь с их  документация.

Оригинал


Spread the love

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *