ابتدا باید در مورد webpack توضیح بدهم: webpack یک module bundler است. توسعه دهندگان جاوا اسکریپت با مشکل بزرگی روبرو هستند و آن هم تعداد بالای فایل های جاوا اسکریپت و به طور کل asset های وب سایت ها است که باعث کندی سرعت بارگذاری سایت می شوند. عملیات باندل کردن (bundling) تمام این فایل ها را با هم ادغام می کند تا برای دریافت آن ها فقط یک درخواست به سمت سرور ارسال شود. کار webpack نیز همین است؛ یعنی فایل ها را باندل کرده و به طور هوشمند و با در نظر گرفتن اولویت ها ارسال می کند.
Tree Shaking (به معنی «درخت تکانی») یک استراتژی است که توسعه دهندگان وب از آن برای کوچک کردن کدهای جاوا اسکریپت و حذف کد های اضافی استفاده می کنند.
در این مقاله ی آموزشی می خواهیم نحوه ی انجام tree shaking در جاوا اسکریپت را با استفاده از webpack توضیح دهیم. در واقع Tree Shaking که به نام live code inclusion هم شناخته می شود روشی برای بهینه سازی کدهای جاوا اسکریپتی است که در قالب ECMAScript نوشته شده باشند.
با گذر زمان برنامه های وب ما دارای dependency (وابستگی به منابع یا کدهای خاص) می شوند اما برخی اوقات و پس از گذشت مدتی این وابستگی ها از بین می روند. نتیجه این می شود که کدهایی داریم که اصلا به آن ها نیازی نداریم! بنابراین هدف ما این است که این کدهای اضافی و به درد نخور را حذف کنیم تا باعث درگیری منابع سیستمی نشوند و سرعت برنامه ی وب ما را بالاتر ببرند. حالا متوجه شدید چرا به این تکنیک «درخت تکانی» می گویند؟ اگر کدهای جاوا اسکریپت خود را به صورت یک درخت تصور کنید، شاخ و برگ های مُرده می شود همان کدهای اضافی شما!
پیدا کردن کدهای مُرده، یعنی کدهایی که استفاده ای در برنامه ندارند، برای زبان های پویا کار دشواری بود اما ماژول های ECMAScript 6 از نوع استاتیک (پایا) هستند. بنابراین کار پیدا کردن این کدهای مرده تنها با import و export کردن انجام می شود. این مفهوم برای اولین بار توسط یک bundler به نام Rollup در سال 2015 معرفی شد اما امروزه اکثر bundler ها مانند webpack از آن پشتیبانی می کنند؛ webpack از نسخه ی 2 از tree shaking و ماژول های ECMAScript 6 پشتیبانی می کرده است اما در نسخه ی چهارم خود ویژگی های جالب و خوبی برای ارتقاء این عملیات اضافه کرده است.
از منظر پردازش و رندر، جاوا اسکریپت از دیگر منابع دنیای وب (مانند تصاویر و HTML و...) سنگین تر و پردازش آن پر هزینه تر است چرا که قبل از اجرا باید parse و سپس کامپایل شود! به همین دلیل پیشنهاد می شود تمام توسعه دهندگان وب قبل از باندل کردن کدهای جاوا اسکریپت خود، آن ها را تا حد ممکن کاهش دهند. بگذارید یک مثال برایتان بزنم؛ تصویر زیر مقایسه ی زمان لازم برای بارگذاری یک فایل جاوا اسکریپت به حجم 170KB و یک فایل تصویری JPEG به حجم 170KB است:
می بینید که جاوا اسکریپت زمان بیشتری نیازد دارد!
Tree Shaking در جاوا اسکریپت از دستورات استاتیک import استفاده می کند تا تنها ماژول هایی که موردنیاز شما است را در باندل قرار بدهد؛ در حالت developer build (هنگام توسعه) تمام موارد یک ماژول import خواهند شد اما در production build (اجرایی شدن وب سایت) می توانیم به webpack بگوییم چه چیزهایی را نیاز داریم. بدین صورت باندل جاوا اسکریپت ما کوچک تر و بهینه تر خواهد بود و طبیعتا سرعت بیشتری نیز خواهد داشت.
در برنامه های جاوا اسکریپتی امروزی وابستگی ها (dependency) از طریق دستورات استاتیک مانند دستور زیر import می شوند:
import arrayMenu from "array-menu";
کد بالا به webpack می گوید هر چه در ماژولی به نام array-menu وجود دارد را import کن اما اگر برنامه ی شما تنها از بخشی از یک پکیج استفاده می کند نیازی به ارسال تمام آن به سمت کاربر نیست. در این صورت می توانیم بگوییم:
import { burger, fries, shake } from "array-menu";
متاسفانه در حال حاضر هیچ فرآیندی برای خودکارسازی tree shaking وجود ندارد. بنابراین باید خودتان در کدها به دنبال فرصت استفاده از آن بوده و سپس به صورت دستی کدهایش را بنویسید؛ به طور مثال در کدهایتان به دنبال دستورات استاتیک import بگردید و سعی کنید توابع و کلاس های اضافی در کدهایتان را حذف کنید. سپس فایل component خود را طوری ویرایش کنید که تنها آنچه را نیاز دارید import کند.
اگر شما از کامپایلرهای جاوا اسکریپت مانند Babel استفاده می کنید، باید قبل از tree shaking چند کار را انجام بدهید؛ برخی از preset ها مانند babel-preset-env به طور خودکار ماژول های ES6 را به ماژول های CommonJS تبدیل می کنند که باعث پیچیدگی tree shaking می شود. راه حل این است که preset خود را طوری تنظیم کنید که ماژول های ES6 را دستکاری نکند. برای انجام این کار کافی است کد زیر را به فایل configuration (پیکربندی) Babel اضافه کنید:
{ "presets": [ ["env", { "modules": false }] ] }
پس از آن bundler شما می تواند وابستگی های کدتان را آنالیز کند و به شما کمک کند که کدهای مُرده را از بین ببرید. همچنین برای بهره وری کامل از Tree shaking بهتر است کدهایتان را minify کنید؛ برای انجام این کار می توانید از پلاگین UglifyJS Plugin استفاده کنید. در چنین حالتی webpack کدهای مُرده را شناسایی و نشانه گذاری کرده و UglifyJS نیز کدها را تمیز کرده و کدهای مُرده را از باندل حذف می کند.
در اینجا یک مثال webpack آورده ایم تا با عملیات Tree Shaking آشنا شوید. فرض کنید که فایل modules.js
را بدین صورت داریم:
export function drive(props) { return props.gas } export function fly(props) { return props.miles }
سپس فایل index.js
را نیز با محتویات زیر داریم:
import { drive } from modules; eventHandler = (event) => { event.preventDefault() drive({ gas: event.target.value }) }
در این مثال ()fly اهمیتی ندارد بنابراین وارد باندل هم نخواهد شد چرا که tree shaking آن را به عنوان کد مرده علامت گذاری کرده و UglifyJS آن را حذف می کند. در واقع webpack کلاس های استفاده شده را با پیام (harmony export (immutable و کلاس های بدون استفاده را با پیام unused harmony export مشخص می کند و برای آنکه UglifyJS متوجه این پیام ها شود باید حتما optimization.usedExports
را روشن کرده باشیم.
با اینکه Tree Shaking تنها چند خط از کد بالا را حذف کرد اما در کل پروژه تاثیر زیادی دارد.
در این قسمت، به پرسشهای تخصصی شما دربارهی محتوای مقاله پاسخ داده نمیشود. سوالات خود را اینجا بپرسید.
در این قسمت، به پرسشهای تخصصی شما دربارهی محتوای مقاله پاسخ داده نمیشود. سوالات خود را اینجا بپرسید.
در این قسمت، به پرسشهای تخصصی شما دربارهی محتوای مقاله پاسخ داده نمیشود. سوالات خود را اینجا بپرسید.