Tree Shaking: ano ito, mekanismo ng pagtanggal ng patay na code at mga kasangkapan

May-akda: IT Sectr Nai-publish: 2026-05-18 Oras ng pagbabasa: 8 min

Tree Shaking — mekanismo ng pagtanggal ng hindi ginagamit na code (dead code elimination) sa yugto ng pagbuo ng aplikasyon. Sinusuri ng Tree Shaking ang static na istruktura ng mga ES-module at isinasama ang mga na-export na function, klase at variable na hindi ini-import kahit saan. Ayon sa Webpack Documentation, ang tamang configuration ng Tree Shaking ay maaaring magbawas ng laki ng bundle ng 30–60% nang hindi binabago ang functionality ng aplikasyon.

Mga Pangunahing Punto

  • Tree Shaking — pagtanggal ng hindi ginagamit na mga export mula sa ES-module batay sa static na pagsusuri ng import/export
  • ES-module (import/export) — ang tanging format na sumusuporta sa Tree Shaking; hindi suportado ang CommonJS
  • Webpack at Rollup — mga pangunahing tagabuo na may suporta sa Tree Shaking sa pamamagitan ng mga plugin
  • Side effects — mga side effect sa module ay humaharang sa Tree Shaking; nilulutas ng flag na sideEffects: false sa package.json ang problema
  • Used exports — pagsusuri ng paggamit ng mga export sa production mode ng Webpack para sa tumpak na pagtanggal ng patay na code

Ano ang Tree Shaking?

Tree Shaking (pag-alog ng puno) — technique ng pag-optimize ng code kung saan ang mga module at function na hindi ginagamit sa aplikasyon ay isinasama mula sa huling bundle. Ang termino ay ipinakilala ng Rollup team noong 2015 at metaporikal na naglalarawan ng proseso: ang puno ng dependencies ay inalog, at ang mga hindi ginagamit na sanga ay nalalagas. Hindi tulad ng manual optimization, ang Tree Shaking ay awtomatikong ginagawa sa yugto ng pagbuo.

Ang Tree Shaking ay gumagana lamang sa ES-module (ECMAScript Modules), kung saan ang mga dependency ay statikong tinutukoy sa pamamagitan ng import at export. Ang CommonJS (require/module.exports) ay hindi sumusuporta sa Tree Shaking dahil ang require ay dynamic na isinasagawa — hindi matukoy ng tagabuo nang maaga kung aling mga function ang talagang ginagamit. Ang mga modernong library (Lodash, Moment.js, RxJS) ay naglalabas ng ES na bersyon para sa suporta ng Tree Shaking.

Rollup: pioneer ng Tree Shaking

Rollup — unang tagabuo na nagpatupad ng Tree Shaking noong 2015. Hindi tulad ng Webpack, ang Rollup ay idinisenyo mula sa simula para sa ES-module at nagsasagawa ng mas agresibong pagtanggal ng patay na code. Sinusuri ng Rollup hindi lamang ang mga indibidwal na export, kundi pati na rin ang buong module: kung ang isang module ay walang side effects at walang export na ginagamit, isinasama ng Rollup ang buong module mula sa bundle.

Ang Rollup ay lalong epektibo para sa mga library at SDK, kung saan mahalaga ang bawat kilobyte. Ang framework na Vue.js ay gumagamit ng Rollup para sa pagbuo ng production na bersyon. Lumipat ang React sa Rollup noong 2020. Para sa mga aplikasyon, mas madalas ginagamit ang Webpack dahil sa mas mayamang ecosystem ng plugin (Hot Module Replacement, code splitting, CSS modules), ngunit para sa maximum na Tree Shaking sa pagbuo ng mga library, ang Rollup ay nananatiling pamantayan ng industriya.

Ang matitipid mula sa Tree Shaking ay lubos na nakadepende sa arkitektura ng proyekto. Sa isang React na aplikasyon na may Ant Design library, maaaring alisin ng Tree Shaking ang hanggang 70% ng code ng UI component. Sa isang proyekto kung saan ang lahat ng import ay tiyak at tumpak, ang matitipid ay magiging 5–15%. Ang average na matitipid ayon sa pananaliksik ng Webpack ay 30–40% ng laki ng bundle.

Ano ang patay na code

Uri ng patay na codeHalimbawaPagtuklas ng Tree Shaking
Hindi ginagamit na exportexport function unusedHelper()Oo
Hindi ginagamit na importimport { unused } from "lib"Oo
Patay na sangay ng kondisyonif (false) { ... }Hindi (tinatanggal ng minifier)
Hindi tinawag na function pagkatapos ng DCEfunction a(){} a() kung saan a ay hindi tinawagBahagya

Paano gumagana ang Tree Shaking: static na pagsusuri ng mga module

Mekanismo ng Tree Shaking ay batay sa dependency graph na itinayo ng tagabuo mula sa lahat ng import/export sa proyekto. Sa unang yugto, binabagtas ng tagabuo ang lahat ng file mula sa entry point at kinokolekta ang puno ng mga module. Sa ikalawang yugto, sinusuri kung aling mga export mula sa bawat module ang talagang ini-import sa ibang mga module.

Para sa bawat module, Webpack o Rollup ay minamarkahan ang mga export bilang ginagamit o hindi ginagamit. Ang hindi ginagamit na mga export ay isinasama mula sa bundle. Gayunpaman, ang module mismo ay nananatili sa bundle kung kahit isang export nito ay ginagamit. Ang ganap na pagbubukod ng module ay posible lamang sa pamamagitan ng sideEffects flag o kung ang module ay walang anumang side effects.

Halimbawa: bago at pagkatapos ng Tree Shaking

js
// utils.js — module na may mga function
export function formatDate(date) {
  return date.toISOString().slice(0, 10);
}

export function formatCurrency(amount) {
  return "$" + amount.toFixed(2);
}

export function slugify(text) {
  return text.toLowerCase().replace(/\s+/g, "-");
}
js
// app.js — entry point
import { formatDate } from "./utils";

const today = formatDate(new Date());
console.log(today);
js
// Pagkatapos ng Tree Shaking — sa bundle ay formatDate lamang
function formatDate(date) {
  return date.toISOString().slice(0, 10);
}
const today = formatDate(new Date());
console.log(today);

Tree Shaking ay isinama ang formatCurrency at slugify mula sa huling bundle dahil hindi sila ini-import sa app.js. Ang laki ng module na utils.js ay nabawasan mula 3 function tungo sa 1. Kung ang utils.js ay naglalaman ng side effects (halimbawa, global na initialization), hindi maaalis ng Tree Shaking kahit ang hindi ginagamit na mga export.

Tree Shaking sa Webpack: configuration at optimization

Webpack ay may kasamang built-in na suporta para sa Tree Shaking sa pamamagitan ng TerserPlugin sa production mode. Para paganahin ang Tree Shaking, sapat na ang dalawang kondisyon: mode na nakatakda sa production (mode: "production") at mga module na gumagamit ng ES syntax (import/export). Awtomatikong minamarkahan ng Webpack ang hindi ginagamit na mga export at ipinapadala ang mga ito sa Terser para tanggalin.

Ang karagdagang configuration na usedExports: true sa optimization.webpack.config.js ay nagpapagana ng detalyadong pagsusuri ng paggamit ng mga export sa loob ng module. Tinutukoy ng opsyong ito kung aling mga export ang talagang ginagamit (used) at alin ang na-export lamang (provided). Ang kombinasyon ng usedExports at Terser ay nagbibigay ng maximum na kahusayan sa pagtanggal ng patay na code.

Configuration ng Webpack para sa Tree Shaking

js
// webpack.config.js — configuration ng Tree Shaking
module.exports = {
  mode: "production",
  entry: "./src/app.js",
  output: {
    filename: "bundle.js",
  },
  optimization: {
    usedExports: true,
    minimize: true,
    concatenateModules: true,
  },
  module: {
    rules: [
      {
        test: /\.js$/,
        exclude: /node_modules\/(?!(my-lib)\/).*/,
        use: {
          loader: "babel-loader",
          options: {
            presets: [
              ["@babel/preset-env", { modules: false }],
            ],
          },
        },
      },
    ],
  },
};

Ang pangunahing parameter — modules: false sa @babel/preset-env. Ang Babel ay default na nagko-convert ng ES-module sa CommonJS, na pumapatay sa Tree Shaking. Ang modules: false ay nagbabawal sa Babel na i-convert ang import/export, pinapanatili ang ES syntax para sa Webpack. Ang concatenateModules ay karagdagang pinagsasama ang mga module sa isang karaniwang saklaw, binabawasan ang bilang ng IIFE at laki ng bundle.

Problema ng side effects at ang sideEffects flag

Side effects (mga side effect) — mga aksyon ng module kapag ini-import na hindi nauugnay sa mga na-export na halaga: global na estilo (import "./styles.css"), polyfill (import "core-js/stable"), initialization ng global na variable o pagrerehistro ng Service Worker. Kung ang module ay naglalaman ng side effects, hindi ito ligtas na maaalis ng tagabuo mula sa bundle, kahit na walang export na ginagamit.

Ang sideEffects flag sa package.json ay nagpapaalam sa tagabuo kung aling mga module sa package ang walang side effects. Para sa isang package kung saan lahat ng module ay dalisay (export lamang ng function), dapat itakda ang "sideEffects": false. Para sa mga package na may CSS o polyfill — isang array ng mga path sa mga file na may side effects: "sideEffects": ["*.css"]. Kung wala ang flag na ito, hindi aalisin ng Tree Shaking kahit ang hindi ginagamit na mga function.

Paano matukoy ang side effects sa iyong code

Upang suriin kung ang isang module ay may side effects, itanong ang tanong: ang import ba na ito ay magsasagawa ng anumang aksyon na hindi nauugnay sa pag-export ng mga halaga? import "./styles.css" ay nagdaragdag ng CSS sa DOM — ito ay side effect. import { throttle } from "lodash-es" ay walang side effects — ginagawa lamang nitong available ang throttle function. Ang polyfill (import "core-js/stable") ay may side effects — binabago nila ang global na prototype.

Para sa iyong sariling mga module, inirerekomenda: ilipat ang mga estilo at polyfill sa mga hiwalay na entry point, paghiwalayin ang mga dalisay na utility (function na walang side effects) mula sa mga module na may side effects (initialization, logging, pagrerehistro ng Service Worker). Sa package.json ng proyekto, itakda ang "sideEffects": false lamang kung lahat ng module ay dalisay. Kung may mga estilo — itakda ang "sideEffects": ["*.css"] nang tumpak.

Halimbawa ng sideEffects configuration

json
{
  "name": "my-ui-lib",
  "version": "2.1.0",
  "sideEffects": [
    "*.css",
    "polyfills.js"
  ],
  "module": "dist/index.esm.js",
  "main": "dist/index.cjs.js"
}

"sideEffects": ["*.css", "polyfills.js"] ay nangangahulugan: lahat ng CSS file ay may side effects (hindi maaaring tanggalin) at polyfills.js din. Lahat ng iba pang JS file sa package ay dalisay — maaari silang ligtas na i-shake. Ang field na module ay nagpapahiwatig ng path sa ES na bersyon ng package na dapat gamitin ng tagabuo sa halip na bersyon ng CommonJS (main) para sa Tree Shaking.

Tree Shaking sa React Native at Metro

React Native na may Metro Bundler ay sumusuporta sa limitadong bersyon ng Tree Shaking. Ang Metro ay hindi nagsasagawa ng kumpletong static na pagsusuri ng ginagamit na mga export (usedExports) tulad ng Webpack. Sa halip, umaasa ang Metro sa Terser para sa pagtanggal ng hindi ginagamit na bahagi ng mga module sa yugto ng minification. Ang kahusayan ng pamamaraang ito ay mas mababa kaysa sa buong Tree Shaking sa Webpack.

Para sa maximum na optimization ng mga proyektong React Native inirerekomenda: gumamit ng mga library na may ES-module (field na module sa package.json), ikonekta ang mga plugin na babel-plugin-transform-remove-console para sa pagtanggal ng debug code, at i-configure ang Metro transformer.minifierConfig para sa Terser. Karagdagan, ang Ram Bundle (paghahati ng bundle sa mga module) ay nagbabawas ng pag-load ng hindi ginagamit na mga screen.

Mga Madalas Itanong

Bakit hindi gumagana ang Tree Shaking sa CommonJS?

CommonJS (require/module.exports) ay hindi sumusuporta sa static na pagsusuri — ang require ay maaaring tawagin nang dynamic sa loob ng mga kondisyon at function. Hindi matukoy ng tagabuo kung aling mga bahagi ng module ang talagang ginagamit. Tanging ang ES-module na may static na import/export ang nagpapahintulot sa Tree Shaking.

Maaari bang gamitin ang Tree Shaking sa TypeScript?

TypeScript ay ganap na compatible sa Tree Shaking sa kondisyon na ang tsconfig.json ay naka-configure para sa ES-module: "module": "esnext". Ang TypeScript compiler ay dapat panatilihin ang import/export nang walang conversion sa CommonJS. Ang Babel na may @babel/preset-typescript at modules: false ay wasto ring nagpapasa ng ES-module sa Webpack.

Paano suriin kung gumana ang Tree Shaking?

Webpack Bundle Analyzer — plugin na nagbibigay-diin sa komposisyon ng bundle sa anyo ng interactive na diagram. Kung ang isang library ay naroroon sa bundle ngunit ang mga function nito ay hindi ginagamit, hindi gumana ang Tree Shaking. Maaari ring suriin ang output file: hanapin ang hindi ginagamit na export sa text ng bundle sa pamamagitan ng grep.

Bakit hindi naka-tree-shake ang Lodash bilang default?

Lodash v4 ay ipinamamahagi bilang CommonJS package. Para sa Tree Shaking, gamitin ang lodash-es — ang ES na bersyon ng library. Palitan ang import throttle from "lodash/throttle" ng import { throttle } from "lodash-es" at i-configure ang resolve.alias sa Webpack para palitan ang lodash ng lodash-es.

Nakakaapekto ba ang Tree Shaking sa oras ng pagbuo?

Tree Shaking ay bahagyang nagpapataas ng oras ng pagbuo (ng 5–15%), dahil nagdaragdag ito ng yugto ng pagsusuri ng dependency graph at pagmamarka ng ginagamit na mga export. Sa development mode, ang Tree Shaking ay karaniwang naka-off para sa bilis. Sa produksyon, ang karagdagang oras ay nabibigyang-katwiran ng makabuluhang pagbawas ng laki ng bundle.

Buod

  • Tree Shaking — awtomatikong pagtanggal ng hindi ginagamit na ES export sa yugto ng pagbuo, pagbawas ng laki ng bundle ng 30–60%
  • ES-module — ang tanging format na sumusuporta sa static na pagsusuri; ang CommonJS ay hindi angkop para sa Tree Shaking
  • Webpack at Rollup ay nagbibigay ng Tree Shaking sa pamamagitan ng usedExports at Terser sa production mode
  • Side effects ay humaharang sa pagtanggal ng module; ang sideEffects: false flag sa package.json ay nilulutas ang problema para sa mga dalisay na library
  • Babel ay dapat i-configure sa modules: false upang hindi i-convert ang ES-module sa CommonJS
  • React Native Metro ay may limitadong Tree Shaking, umaasa sa Terser sa yugto ng minification

Gagawa kami ng mobile application na turnkey

Gumagawa ang IT Sectr ng mga iOS at Android application para sa mga startup at negosyo mula noong 2017. Magpapayo kami sa iyo at magmumungkahi ng pinakamahusay na solusyon.

Pag-usapan ang proyekto

Basahin din