بارگذاری Routeها به صورت lazy

Routes Lazy Loading

Vue.JS 2: بارگذاری route ها به صورت lazy - قسمت 87

در آخرین قسمت از این فصل باید به سراغ مبحث lazyloading آدرس ها یا همان URL ها برویم. اگر به برنامه خود برویم (در صفحه اصلی) دو لینک Home و User را داریم. لینکِ Home، همان صفحه اصلی است که در آن هستیم (به آدرس http://localhost:8080/) اما اگر روی User کلیک نکنیم آیا به کدهای آن نیاز داریم؟ پاسخ قطعا منفی است. با این حساب آیا واقعا لازم است که تمام کدها را در همان ابتدا بارگذاری کنیم و کاربر همه چیز را یکجا دانلود کند؟ قطعا پاسخ در اینجا هم منفی است. شاید در برنامه ساده ما که فقط چند کامپوننت بسیار کوچک دارد، lazy load کردن کامپوننت ها و مسیر ها تغییری ایجاد نکند اما در برنامه های بزرگ و واقعی که هزاران خط کد دارند، بارگذاری صفحه اول سریع تر از بارگذاری تمام کامپوننت ها به صورت یکجا است.

اگر در طول دوره مثل من جلو آمده و از Vue-cli استفاده کرده باشید، الان محیط توسعه webpack را دارید. همانطور که می دانیم محیط توسعه webpack تمام فایل های ما را درون یک فایل قرار می دهد که برای برنامه های کوچک یا شاید متوسط هیچ مشکلی ندارد اما برای برنامه های بزرگ مشکل زا است. درست است که ادغام تمام فایل ها در یک فایل باعث کاهش تعداد درخواست های HTTP می شود اما اگر کدهایتان بسیار زیاد باشد، حجم bundle نهایی (فایل نهایی که ترکیبی از تمام فایل ها است) بسیار بزرگ می شود و بارگذاری سایت شما را به تاخیر می اندازد. همانطور که می دانید، تحقیقات اکثر متخصصین سئو و گوگل نشان می دهد که تاخیر بیشتر از 2 ثانیه می تواند ضربه مهلکی به سایت شما بزند. در واقع در یکی از این تحقیقات کاربران موبایل فقط 3 ثانیه برای بارگذاری یک سایت صبر کرده بودند و پس از آن پنجره مرورگر را بسته و به سایت دیگری می رفتند. بنابراین باید نقطه تعادلی بین کاهش تعداد درخواست های HTTP و افزایش سایز bundle نهایی پیدا کنید.

lazy loading نوعی بارگذاری صفحات به صورت تاخیری است. به زبان ساده تر فقط عناصری را بارگذاری می کنیم که به آن ها نیاز داشته باشیم. مثلا در برنامه ما زمانی که کاربر برای اولین بار وارد برنامه می شود نیازی به بارگذاری تمام صفحات نیست. چرا؟ به دلیل اینکه کاربر ابتدا صفحه Home را می بیند و شاید اصلا نخواهد به صفحه User برود. بنابراین چرا کاربر را مجبور کنیم که کدهای آن صفحه را نیز دانلود کند؟ روش های پیاده سازی lazy loading بسیار زیاد و متنوع هستند و شما می توانید برای هر محیط توسعه ای که دارید، روش های خاص خودش را پیدا کنید. کافی است نام آن محیط توسعه را به همراه عبارت lazy loading در گوگل جست و جو کنید. ما در این دوره از webpack استفاده می کنیم بنابراین روش پیاده سازی lazy loading روی webpack را توضیح خواهم داد.

<div class="exlink"><a href="https://www.roxo.ir/series/webpack-tutorials/">آموزش کامل webpack</a></div>/

lazy loading با webpack

ابتدا به فایل routes.js بروید. باید بدانید، هر چیزی که در بالای صفحه به صورت import وجود داشته باشد به سرعت و بدون ملاحظات دیگر، بارگذاری خواهد شد. بنابراین دستورات import بالای این صفحه (به جز Home و Header را) حذف می کنیم. توجه داشته باشید که Home و Header جزء صفحه اول هستند بنابراین همیشه باید بارگذاری شوند:

import Home from './components/Home.vue';
import Header from './components/Header.vue';

export const routes = [
    {
        path: '', name: 'Home', components: {
            default: Home,
            'header-top': Header
        }
    },
// بقیه کدها //

در مرحله بعد باید از syntax خاصی استفاده کنیم که webpack آن را شناسایی می کند و به جای ترکیب فایل های آن در bundle اصلی، چندین bundle جداگانه می سازد (در ادامه مشاهده خواهید کرد). حالا فکر کنید که می خواهیم کامپوننت User را به صورت lazy load بارگذاری کنیم. اگر از دستورات با syntax دیگری استفاده کنیم (مثلا syntax زبان Node.js) باز هم مانند import، بارگذاری سریعا اتفاق می افتد:

import Home from './components/Home.vue';
import Header from './components/Header.vue';
require('./components/user/User.vue');

بنابراین نمی توانیم از این کد استفاده کنیم. روش انجام صحیح آن بدین شکل است که یک ثابت تعریف می کنیم که یک تابع باشد:

import Home from './components/Home.vue';
import Header from './components/Header.vue';

const User = resolve => {
    require.ensure(['./components/user/User.vue'], () => {
        resolve(require('./components/user/User.vue'));
    });
}

همانطور که گفتم این نحو (syntax) کمی عجیب است و شما باید آن را حفظ کنید. در واقع کد بالا یک تابع است که require.ensure را صدا می زند. ensure دو آرگومان می گیرد که اولی یک آرایه است و شامل مسیرهایی است که باید بارگذاری شوند و من آدرس User.vue را به آن داده ام. یعنی این آدرس و فایل را زیر نظر بگیر و زمانی که نیاز به بارگذاری آن داریم، آرگومان دوم را اجرا کن که خودش یک تابع است و فایل User.vue را بارگذاری می کند.

حالا همین کار را برای بقیه کامپوننت ها نیز انجام می دهیم:

import Home from './components/Home.vue';
import Header from './components/Header.vue';

const User = resolve => {
    require.ensure(['./components/user/User.vue'], () => {
        resolve(require('./components/user/User.vue'));
    });
};
const UserStart = resolve => {
    require.ensure(['./components/user/UserStart.vue'], () => {
        resolve(require('./components/user/UserStart.vue'));
    });
};
const UserEdit = resolve => {
    require.ensure(['./components/user/UserEdit.vue'], () => {
        resolve(require('./components/user/UserEdit.vue'));
    });
};
const UserDetail = resolve => {
    require.ensure(['./components/user/UserDetail.vue'], () => {
        resolve(require('./components/user/UserDetail.vue'));
    });
};

export const routes = [
    {
        path: '', name: 'Home', components: {
            default: Home,
            'header-top': Header
        }
    },
    {
        path: '/user', components: {
            default: User,
// بقیه کدها //

برای تست کردن این کدها می توانید به dev tools مرورگر رفته (معمولا کلید f12) و سربرگ network را باز کنید. با refresh کردن صفحه اصلی فایل build.js را می بینید که فایل اصلی ما است و همان صفحه اصلی را در بر می گیرد. بقیه فایل های بارگذاری شده مربوط به webpack هستند و با آن ها کاری نداریم. حالا اگر روی User کلیک کنید، دو فایل دیگر (معمولا با نام هایی شبیه به 4.build.js و 5.build.js) بارگذاری می شوند. بنابراین هر قدم که جلوتر می رویم یک فایل جدید بارگذاری می شود.

نکته: اگر بخواهیم به جای جدا کردن هر کامپوننت درون یک bundle (فایل) جداگانه، چندین کامپوننت را درون یک فایل بگذاریم باید آرگومان سومی را به require.ensure پاس بدهیم که نام یک گروه است. در واقع شما یک نام دلخواه را به آن پاس می دهید و کامپوننت هایی که این نام را داشته باشند درون یک bundle قرار خواهند گرفت:

 const User = resolve => {
    require.ensure(['./components/user/User.vue'], () => {
        resolve(require('./components/user/User.vue'));
    }, 'user');
};
const UserStart = resolve => {
    require.ensure(['./components/user/UserStart.vue'], () => {
        resolve(require('./components/user/UserStart.vue'));
    }, 'user');
};
const UserEdit = resolve => {
    require.ensure(['./components/user/UserEdit.vue'], () => {
        resolve(require('./components/user/UserEdit.vue'));
    }, 'user');
};
const UserDetail = resolve => {
    require.ensure(['./components/user/UserDetail.vue'], () => {
        resolve(require('./components/user/UserDetail.vue'));
    }, 'user');
};

من نام user را انتخاب کرده ام بنابراین تمام کامپوننت های بالا درون یک bundle قرار می گیرند که نهایتا می شود دو bundle: یک bundle اصلی برای صفحه Home و یکی دیگر هم bundle دوم ما برای این کامپوننت ها در کد بالا.

تمام فصل‌های سری ترتیبی که روکسو برای مطالعه‌ی دروس سری آموزش رایگان Vue js از صفر تا صد توصیه می‌کند:
نویسنده شوید

دیدگاه‌های شما

در این قسمت، به پرسش‌های تخصصی شما درباره‌ی محتوای مقاله پاسخ داده نمی‌شود. سوالات خود را اینجا بپرسید.