همه چیز در مورد کار با Webpack 4 برای مدیریت Module bundling - قسمت 3 - آموزش Code-splitting در Webpack

دسته بندی: آموزش
زمان مطالعه: ۷ دقیقه
۱۷ دی ۱۳۹۷

در این قسمت میخوام مطلب همه چیز در مورد کار با Webpack 4 رو ادامه بدم و اطلاعات بیشتری رو در مورد Module bundling در اختیارتون قرار بدم.

در قسمت قبل Code splitting رو بصورت مقدماتی تعریف کردم و بهتون توضیح دادم که بعد از مدتی که اپلیکیشن شما بزرگ و بزرگتر میشه، حجم bundle خروجی خیلی زیاد میشه و مدت زمان زیادی طول میکشه تا مرورگر bundle رو دانلود کرده و اون رو اجرا کنه. خب مثل همیشه میخوام این مفهوم کاربردی و مفید رو با استفاده از یک مثال کاربردی بهتون آموزش بدم.

فرض کنید که میخوایم یک ماژول بنام chat رو اضافه کنیم و فقط میخوام زمانی این ماژول لود بشه و از اون استفاده بشه که کاربر بر روی دکمه مورد نظر کلیک کنه. در اولین قدم باید تغییراتی در فایل webpack.config.js به وجود بیاریم. تغییرات بصورت زیر هستند:

  const path = require('path')

  module.exports = {
-   entry: './src/index.js',
+   entry: {
+     app: './src/app.js'
+   },
    output: {
-     filename: 'bundle.js',
+     filename: '[name].bundle.js',
      path: path.resolve(__dirname, 'dist')
    },
    ...
  }

همونطور که در جلسات قبل هم گفته شد، در کنار اون خطوطی که - دارند به معنای اینه که اون خط حذف میشه و خطهایی که + دارند اضافه میشن. همونطور که میبینید entry رو بصورت یک object در آوردم که بشه در اون چند ورودی رو تعریف کرد. در output هم یک [name] قرار دادم. با اینکار به webpack میگیم که برای هر فایل خروجی نام داینامیک قرار بده و webpack هم برای هر فایل خروجی نام مورد نظر رو قرار میده.

یک فایل بنام chat.js در دایرکتوری src به وجود میارم و کدهای زیر رو در اون قرار میدم:

import people from "./people";

export function init() {
  const root = document.createElement("div");
  root.innerHTML = `<p>There are ${people.length} people in the room.</p>`;
  document.body.appendChild(root);
}

همونطور که میبینید بصورت ساده فایل peaple.js که شامل آرایه‌ای از افراد هست رو لود کرده و یک div ساختیم و درون اون اطلاعاتی در مورد تعداد افراد در peaple.js قرار دادیم. خب حالا کدهای زیر رو در index.js قرار میدیم:

import './app.scss';

const button = document.createElement("button");
button.textContent = 'Open chat';
document.body.appendChild(button);

button.onclick = () => {
  import(/* webpackChunkName: "chat" */ "./chat").then(chat => {
    chat.init();
  });
};

میبینید که یک دکمه ساختیم و متن Open chat رو در اون قرار دادیم. در انتها زمانی که بر روی دکمه کلیک میشه، از یک دستور import خاص برای لود کردن ماژول chat استفاده کردیم که در ادامه بیشتر در مورد اون توضیح داده میشه.

استایل زیر رو در فایل app.scss قرار میدم:

button {
  padding: 10px;
  background: #24b47e;
  border: 1px solid rgba(#000, .1);
  border-width: 1px 1px 3px;
  border-radius: 3px;
  font: inherit;
  color: #fff;
  cursor: pointer;
  text-shadow: 0 1px 0 rgba(#000, .3), 0 1px 1px rgba(#000, .2);
}

با استفاده از webpackChunkName که در comment قرار داده شده، نام bundle خروجی رو مشخص کرده و به webpack میگیم که این فایل رو با نام chat خروجی بگیر. Webpack زمانی که به این کد میرسه، به خوبی منظور ما رو میفهمه و همه کدهای مربوط به chat.js رو در خروجی chat.bundle.js قرار میده.

این syntax و نحوه تعریف کردن import مختص webpack نیست و یک ایده با نام Dynamic import هست که به احتمال زیاد در آینده نزدیک بصورت استاندارد در میاد و بخشی از Ecmascript میشه و هدف اصلی اون اینه که ماژولها رو بصورت مستقیم در مرورگر نیز لود کنه.

میبینید که این نحوه تعریف کردن import بصورت Promise هست و در متد then اون به ماژول لود شده دسترسی داریم و میتونیم کارهای مورد نظرمون رو انجام بدیم. حالا اگر دستور npm run build رو در command line اجرا کنید، خروجی بصورت زیر خواهد بود:

همونطور که میبینید دو فایل خروجی توسط webpack ساخته میشه. حالا که نام bundle.js به app.bundle.js تبدیل شده، باید در فایل index.html هم نام اون رو عوض کنیم. بصورت زیر:

  <!doctype html>
  <html>
    <head>
      <title>Hello Webpack</title>
    </head>
    <body>
-     <script src="bundle.js"></script>
+     <script src="app.bundle.js"></script>
    </body>
  </html>

حالا فایل index.html رو در مرورگر Chrome باز کنید. اگر Chrome devtools رو باز کرده و تب Network رو ببینید و صفحه رو مجددا رفرش کنید، جزئیات زیر رو خواهید دید:

میبینید که در ابتدا فقط فایل app.bundle.js لود شده و هیچ خبری از chat.bundle.js نیست. این رفتار به خاطر اینه که ما این فایل رو زمانی که بر روی دکمه مورد نظر کلیک میشه، لود میکنیم. حالا اگر بر روی دکمه Open chat کلیک کنیم، خواهیم دید که فایل chat.bundle.js نیز بصورت اتوماتیک لود میشه و خروجی مورد نظر در مرورگر نمایش داده میشه:

همونطور که دیدید به راحتی و با تغییرات کمی تونستیم Code splitting و lazy loading رو به برنامه خودمون اضافه کنیم. این میتونه یک شروع بسیار خوب برای شما باشه که بتونین برنامه‌های سنگین خودتون رو با استفاده از این تکنیک جداسازی کرده و Performance و سرعت لود سایتتون رو افزایش بدین.

کار با Plugin ها در Webpack

همونطور که دیدیم loader ها روی فایلها بصورت تکی اجرا میشن و کارهای مورد نظر رو انجام میدن ولی شما با استفاده از Plugin ها میتونین بر روی بخش بزرگتری از کدهاتون یا به اصطلاح chunk ها تمرکز کنید.

حالا که کدهامون رو بصورت bundle در آوردیم، به زودی با اضافه کردن ابزارهای external و assest ها، سایز bundle زیاد و زیادتر میشه. اینجا هست که Plugin ها به کمک ما میان و میتونیم با استفاده از اونا کدهامون رو تکه تکه یا Split کنیم و محیط رو برای Production به خوبی آماده کنیم.

همین الان با استفاده از ویژگی mode، ما داریم در پشت صحنه از تعدادی از پلاگینهای پیش‌فرض React استفاده میکنیم. Plugin هایی که در حالت Development از اونا استفاده میشه بصورت زیر هستند:

  • NamedModulesPlugins
  • در این حالت مقدار process.env.NODE_ENV هم رشته development قرار داده میشه.

Plugin هایی که در حالت Production از اونا استفاده میشه بصورت زیر هستند:

  • UglifyJsPlugin
  • ModuleConcatenationPlugin
  • NoEmitOnErrorsPlugin
  • در این حالت مقدار process.env.NODE_ENV هم رشته production قرار داده میشه.

جدا کردن تنظیمات Production و Development

قبل از اینکه Plugin های دیگه‌ای رو اضافه کنیم، ما تنظیمات مربوط به webpack رو جدا میکنیم تا بتونیم از پلاگینهای مختلفی برای حالت Development و Production استفاده کنیم.

برای اینکار فایل webpack.config.js رو به webpack.common.js تغییر نام میدم و فایلهای webpack.prod.js و webpack.dev.js رو اضافه میکنم. پس با اینکار ساختار بصورت زیر میشه:

ما برای ترکیب کردن فایلهای تنظیماتی بالا از ابزار webpack-merge استفاده میکنیم. برای نصب این ابزار بصورت زیر عمل میکنیم:

npm install --save-dev webpack-merge

حالا کدهای زیر رو در فایل webpack.dev.js قرار میدم:

const merge = require('webpack-merge');
const common = require('./webpack.common.js');

module.exports = merge(common, {
  mode: 'development',
});

کدهای زیر رو در هم در فایل webpack.prod.js قرار میدم:

const merge = require('webpack-merge');
const common = require('./webpack.common.js');

module.exports = merge(common, {
  mode: 'production',
});

فایل package.json رو نیز بصورت زیر تغییر میدم:

  "scripts": {
-    "develop": "webpack --watch --mode development",
-    "build": "webpack --mode production"
+    "develop": "webpack --watch --config webpack.dev.js",
+    "build": "webpack --config webpack.prod.js"
   },

همونطور که میبینید در scripts بجای استفاده از mode از config استفاده کردیم و مشخص کردیم که در هر حالت چه تنظیماتی مورد استفاده قرار بگیره. با این کارها حالا میتونیم از پلاگینهای متفاوتی برای Production و Development استفاده کنیم.

در قسمت بعد بیشتر در مورد Plugin ها توضیح میدم و اطلاعات بیشتری رو در مورد Webpack در اختیارتون قرار میدم.

نویسنده
بسیار به طراحی وب علاقمندم و به سرعت در حال یادگیری تمام مباحث پیشرفته هستم و دوست دارم که به دیگران هم یاد بدهم.

نظرات کاربران

اولین دیدگاه این پست رو تو بنویس !

ارسال دیدگاه
خوشحال میشیم دیدگاه و یا تجربیات خودتون رو با ما در میون بذارید :

 
گزارش مشکل