Parandage oma veebirakenduse jõudlust selle põhjaliku esikoodi tükeldamise juhendiga. Õppige marsruudi- ja komponendipõhiseid strateegiaid koos praktiliste näidetega Reacti, Vue ja Angulari jaoks.
Frontend koodi tükeldamine: põhjalik ülevaade marsruudi- ja komponendipõhistest strateegiatest
Tänapäevasel digimaastikul määrab kasutaja esmamulje teie veebisaidist sageli üksainus mõõdik: kiirus. Aeglaselt laadiv rakendus võib kaasa tuua kõrge põrkemäära, pettunud kasutajad ja saamata jäänud tulu. Kuna esirakendused muutuvad üha keerukamaks, on nende suuruse haldamine kriitilise tähtsusega. Enamiku komplekteerijate (bundler) vaikekäitumine on luua üks monoliitne JavaScripti fail, mis sisaldab kogu teie rakenduse koodi. See tähendab, et kasutaja, kes külastab teie avalehte, võib alla laadida ka koodi administraatori töölaua, kasutajaprofiili seadete ja ostukorvi voo jaoks, mida ta kunagi ei pruugi kasutada.
Siin tulebki mängu koodi tükeldamine. See on võimas tehnika, mis võimaldab teil oma suure JavaScripti kogumi jaotada väiksemateks, hallatavateks tükkideks, mida saab laadida vastavalt vajadusele. Saates ainult selle koodi, mida kasutaja esialgse vaate jaoks vajab, saate dramaatiliselt parandada laadimisaegu, täiustada kasutajakogemust ja mõjutada positiivselt olulisi jõudlusnäitajaid, nagu Google'i Core Web Vitals.
See põhjalik juhend uurib kahte peamist esikoodi tükeldamise strateegiat: marsruudipõhist ja komponendipõhist. Süveneme iga lähenemisviisi "miks", "kuidas" ja "millal" küsimustesse, koos praktiliste ja reaalsete näidetega, kasutades populaarseid raamistikke nagu React, Vue ja Angular.
Probleem: monoliitne JavaScripti kogum
Kujutage ette, et pakite mitme sihtkohaga reisiks, mis hõlmab rannapuhkust, mägimatka ja ametlikku ärikonverentsi. Monoliitne lähenemine on nagu üritaksite oma ujumisriideid, matkasaapaid ja äriülikonda toppida ühte, tohutu suurde kohvrisse. Randa jõudes peate seda hiiglaslikku kohvrit kaasas tassima, kuigi vajate ainult ujumisriideid. See on raske, ebaefektiivne ja kohmakas.
Monoliitne JavaScripti kogum tekitab veebirakenduse jaoks sarnaseid probleeme:
- Liiga pikk esialgne laadimisaeg: Veebilehitseja peab alla laadima, sõeluma ja käivitama kogu rakenduse koodi, enne kui kasutaja saab midagi näha või sellega suhelda. See võib aeglasemates võrkudes või vähem võimsates seadmetes võtta mitu sekundit.
- Raisatud andmemaht: Kasutajad laadivad alla koodi funktsioonide jaoks, mida nad kunagi ei pruugi kasutada, tarbides asjatult oma andmesidepakette. See on eriti problemaatiline mobiilikasutajatele piirkondades, kus internetiühendus on kallis või piiratud.
- Kehv vahemälu efektiivsus: Väike muudatus ühes koodireas ühes funktsioonis muudab kehtetuks kogu kogumi vahemälu. Seejärel on kasutaja sunnitud kogu rakenduse uuesti alla laadima, isegi kui 99% sellest on muutumatu.
- Negatiivne mõju Core Web Vitalsile: Suured kogumid kahjustavad otseselt selliseid mõõdikuid nagu Largest Contentful Paint (LCP) ja Time to Interactive (TTI), mis võivad mõjutada teie saidi SEO-reitingut ja kasutajate rahulolu.
Koodi tükeldamine on selle probleemi lahendus. See on nagu pakkida kolm eraldi, väiksemat kotti: üks ranna, teine mägede ja kolmas konverentsi jaoks. Te kannate kaasas ainult seda, mida vajate, siis kui seda vajate.
Lahendus: mis on koodi tükeldamine?
Koodi tükeldamine on protsess, mille käigus jagatakse teie rakenduse kood erinevateks kogumiteks ehk "tükkideks" (chunks), mida saab seejärel laadida vastavalt vajadusele või paralleelselt. Ühe suure `app.js` asemel võib teil olla `main.js`, `dashboard.chunk.js`, `profile.chunk.js` ja nii edasi.
Kaasaegsed ehitustööriistad nagu Webpack, Vite ja Rollup on selle protsessi teinud uskumatult kättesaadavaks. Nad kasutavad dünaamilist `import()` süntaksit, mis on kaasaegse JavaScripti (ECMAScript) funktsioon ja võimaldab mooduleid asünkroonselt importida. Kui komplekteerija näeb `import()` käsku, loob see automaatselt selle mooduli ja selle sõltuvuste jaoks eraldi tüki.
Uurime kahte kõige levinumat ja tõhusamat strateegiat koodi tükeldamise rakendamiseks.
Strateegia 1: marsruudipõhine koodi tükeldamine
Marsruudipõhine tükeldamine on kõige intuitiivsem ja laialdasemalt kasutatav koodi tükeldamise strateegia. Loogika on lihtne: kui kasutaja on `/home` lehel, ei vaja ta koodi `/dashboard` või `/settings` lehtede jaoks. Jagades oma koodi mööda rakenduse marsruute, tagate, et kasutajad laadivad alla ainult selle lehe koodi, mida nad hetkel vaatavad.
Kuidas see töötab
Te konfigureerite oma rakenduse ruuteri nii, et see laadiks dünaamiliselt konkreetse marsruudiga seotud komponendi. Kui kasutaja navigeerib sellele marsruudile esimest korda, käivitab ruuter võrgupäringu vastava JavaScripti tüki toomiseks. Pärast laadimist renderdatakse komponent ja veebilehitseja salvestab tüki vahemällu järgnevate külastuste jaoks.
Marsruudipõhise tükeldamise eelised
- Märkimisväärne esialgse laadimise vähendamine: Esialgne kogum sisaldab ainult rakenduse tuumikloogikat ja vaikimisi marsruudi (nt avalehe) koodi, muutes selle palju väiksemaks ja kiiremaks laadida.
- Lihtne rakendada: Enamikul kaasaegsetel marsruutimisteekidel on sisseehitatud tugi laisklaadimisele, mis muudab rakendamise lihtsaks.
- Selged loogilised piirid: Marsruudid pakuvad loomulikke ja selgeid eralduspunkte teie koodile, mis teeb arusaamise, milliseid rakenduse osi tükeldatakse, lihtsaks.
Rakendusnäited
React koos React Routeriga
React pakub selleks kahte peamist utiliiti: `React.lazy()` ja `
Näide `App.js` failist, kasutades React Routerit:
import React, { Suspense, lazy } from 'react';
import { BrowserRouter as Router, Routes, Route } from 'react-router-dom';
// Staatiliselt imporditud komponendid, mida on alati vaja
import Navbar from './components/Navbar';
import LoadingSpinner from './components/LoadingSpinner';
// Laisalt imporditud marsruudi komponendid
const HomePage = lazy(() => import('./pages/HomePage'));
const DashboardPage = lazy(() => import('./pages/DashboardPage'));
const SettingsPage = lazy(() => import('./pages/SettingsPage'));
const NotFoundPage = lazy(() => import('./pages/NotFoundPage'));
function App() {
return (
<Router>
<Navbar />
<Suspense fallback={<LoadingSpinner />}>
<Routes>
<Route path="/" element={<HomePage />} />
<Route path="/dashboard" element={<DashboardPage />} />
<Route path="/settings" element={<SettingsPage />} />
<Route path="*" element={<NotFoundPage />} />
</Routes>
</Suspense>
</Router>
);
}
export default App;
Selles näites ei lisata `DashboardPage` ja `SettingsPage` koodi esialgsesse kogumisse. See laaditakse serverist alles siis, kui kasutaja navigeerib vastavalt marsruutidele `/dashboard` või `/settings`. `Suspense` komponent tagab sujuva kasutajakogemuse, näidates selle laadimise ajal `LoadingSpinner`'it.
Vue koos Vue Routeriga
Vue Router toetab marsruutide laisklaadimist otse karbist, kasutades dünaamilist `import()` süntaksit otse teie marsruudi konfiguratsioonis.
Näide `router/index.js` failist, kasutades Vue Routerit:
import { createRouter, createWebHistory } from 'vue-router';
import HomeView from '../views/HomeView.vue'; // Staatiliselt imporditud esmaseks laadimiseks
const routes = [
{
path: '/',
name: 'home',
component: HomeView
},
{
path: '/about',
name: 'about',
// Marsruudi tasemel koodi tükeldamine
// See genereerib selle marsruudi jaoks eraldi tüki (about.[hash].js)
// mis laaditakse laisalt, kui marsruuti külastatakse.
component: () => import(/* webpackChunkName: "about" */ '../views/AboutView.vue')
},
{
path: '/dashboard',
name: 'dashboard',
component: () => import(/* webpackChunkName: "dashboard" */ '../views/DashboardView.vue')
}
];
const router = createRouter({
history: createWebHistory(process.env.BASE_URL),
routes
});
export default router;
Siin on `/about` ja `/dashboard` marsruutide komponent defineeritud funktsioonina, mis tagastab dünaamilise impordi. Komplekteerija mõistab seda ja loob eraldi tükid. `/* webpackChunkName: "about" */` on "maagiline kommentaar", mis ütleb Webpackile, et nimetada tulemuseks olev tükk `about.js` geneerilise ID asemel, mis võib olla silumisel kasulik.
Angular koos Angular Routeriga
Angulari ruuter kasutab marsruudi konfiguratsioonis atribuuti `loadChildren`, et võimaldada tervete moodulite laisklaadimist.
Näide `app-routing.module.ts` failist:
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { HomeComponent } from './home/home.component'; // Peamise kogumi osa
const routes: Routes = [
{
path: '',
component: HomeComponent
},
{
path: 'products',
// Laadige laisalt ProductsModule
loadChildren: () => import('./products/products.module').then(m => m.ProductsModule)
},
{
path: 'admin',
// Laadige laisalt AdminModule
loadChildren: () => import('./admin/admin.module').then(m => m.AdminModule)
}
];
@NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule]
})
export class AppRoutingModule { }
Selles Angulari näites on `products` ja `admin` funktsioonidega seotud kood kapseldatud nende endi moodulitesse (`ProductsModule` ja `AdminModule`). `loadChildren` süntaks annab Angular Routerile käsu need moodulid alla laadida ja käivitada alles siis, kui kasutaja navigeerib URL-ile, mis algab `/products` või `/admin`.
Strateegia 2: komponendipõhine koodi tükeldamine
Kuigi marsruudipõhine tükeldamine on suurepärane alguspunkt, saate jõudluse optimeerimist komponendipõhise tükeldamisega veelgi edasi viia. See strateegia hõlmab komponentide laadimist ainult siis, kui neid antud vaates tegelikult vaja on, sageli vastusena kasutaja interaktsioonile.
Mõelge komponentidele, mis ei ole kohe nähtavad või mida kasutatakse harva. Miks peaks nende kood olema osa lehe esialgsest laadimisest?
Komponendipõhise tükeldamise levinud kasutusjuhud
- Modaalaknad ja dialoogid: Keeruka modaalakna (nt kasutajaprofiili redaktori) kood tuleb laadida ainult siis, kui kasutaja klõpsab selle avamiseks nuppu.
- Lehe alumise osa sisu (Below-the-Fold): Pika avalehe puhul saab keerukaid komponente, mis asuvad lehe allosas, laadida alles siis, kui kasutaja nende lähedale kerib.
- Keerukad kasutajaliidese elemendid: Raskeid komponente, nagu interaktiivsed graafikud, kuupäevavalijad või rikasteksti redaktorid, saab laisalt laadida, et kiirendada selle lehe esialgset renderdamist, kus nad asuvad.
- Funktsioonilipud või A/B testid: Laadige komponent ainult siis, kui kasutaja jaoks on konkreetne funktsioonilipp lubatud.
- Rollipõhine kasutajaliides: Administraatorispetsiifiline komponent töölaual tuleks laadida ainult 'admin' rolliga kasutajatele.
Rakendusnäited
React
Saate kasutada sama `React.lazy` ja `Suspense` mustrit, kuid käivitada renderdamise tingimuslikult, tuginedes rakenduse olekule.
Näide laisalt laetavast modaalaknast:
import React, { useState, Suspense, lazy } from 'react';
import LoadingSpinner from './components/LoadingSpinner';
// Importige modaalakna komponent laisalt
const EditProfileModal = lazy(() => import('./components/EditProfileModal'));
function UserProfilePage() {
const [isModalOpen, setIsModalOpen] = useState(false);
const openModal = () => {
setIsModalOpen(true);
};
const closeModal = () => {
setIsModalOpen(false);
};
return (
<div>
<h1>User Profile</h1>
<p>Some user information here...</p>
<button onClick={openModal}>Edit Profile</button>
{/* Modaalakna komponent ja selle kood laaditakse alles siis, kui isModalOpen on tõene */}
{isModalOpen && (
<Suspense fallback={<LoadingSpinner />}>
<EditProfileModal onClose={closeModal} />
</Suspense>
)}
</div>
);
}
export default UserProfilePage;
Selle stsenaariumi korral küsitakse `EditProfileModal.js` JavaScripti tükki serverist alles pärast seda, kui kasutaja on esimest korda klõpsanud nupul "Muuda profiili".
Vue
Vue `defineAsyncComponent` funktsioon on selleks ideaalne. See võimaldab teil luua komponendi ümber mähise, mis laaditakse alles siis, kui see tegelikult renderdatakse.
Näide laisalt laetavast graafiku komponendist:
<template>
<div>
<h1>Sales Dashboard</h1>
<button @click="showChart = true" v-if="!showChart">Show Sales Chart</button>
<!-- SalesChart komponent laaditakse ja renderdatakse alles siis, kui showChart on tõene -->
<SalesChart v-if="showChart" />
</div>
</template>
<script setup>
import { ref, defineAsyncComponent } from 'vue';
const showChart = ref(false);
// Defineerige asünkroonne komponent. Raske graafikuteek on omaette tükis.
const SalesChart = defineAsyncComponent(() =>
import('../components/SalesChart.vue')
);
</script>
Siin on potentsiaalselt raske `SalesChart` komponendi (ja selle sõltuvuste, nagu graafikuteek) kood eraldatud. See laaditakse alla ja paigaldatakse alles siis, kui kasutaja seda selgesõnaliselt nupule klõpsates nõuab.
Täpsemad tehnikad ja mustrid
Kui olete marsruudi- ja komponendipõhise tükeldamise põhitõed omandanud, saate kasutajakogemuse edasiseks täiustamiseks kasutada täpsemaid tehnikaid.
Tükkide eellaadimine (Preloading) ja eeltõmbamine (Prefetching)
Enne järgmise marsruudi koodi toomist kasutaja lingile klõpsamise ootamine võib tekitada väikese viivituse. Saame seda targemini teha, laadides koodi ette.
- Eeltõmbamine (Prefetching): See annab brauserile teada, et see peaks ressursi alla laadima oma ooteajal, kuna kasutaja võib seda vajada tulevikus navigeerimiseks. See on madala prioriteediga vihje. Näiteks, kui kasutaja on sisse loginud, saate eeltõmmata töölaua koodi, kuna on väga tõenäoline, et ta sinna järgmisena läheb.
- Eellaadimine (Preloading): See annab brauserile teada, et see peaks ressursi kõrge prioriteediga alla laadima, kuna seda on vaja praegusel lehel, kuid selle avastamine viibis (nt sügaval CSS-failis defineeritud font). Koodi tükeldamise kontekstis võiksite tüki eellaadida, kui kasutaja hõljutab kursorit lingi kohal, muutes navigeerimise klõpsamisel hetkeliseks.
Komplekteerijad nagu Webpack ja Vite võimaldavad teil seda rakendada "maagiliste kommentaaride" abil:
// Prefetch: hea tõenäoliste järgmiste lehtede jaoks
import(/* webpackPrefetch: true, webpackChunkName: "dashboard" */ './pages/DashboardPage');
// Preload: hea suure kindlusega järgmiste interaktsioonide jaoks praegusel lehel
const openModal = () => {
import(/* webpackPreload: true, webpackChunkName: "profile-modal" */ './components/ProfileModal');
// ... then open the modal
}
Laadimis- ja veaolukordade käsitlemine
Koodi laadimine võrgu kaudu on asünkroonne toiming, mis võib ebaõnnestuda. Tugev rakendus peab sellega arvestama.
- Laadimisolekud: Andke kasutajale alati tagasisidet, kui tükki laaditakse. See hoiab ära kasutajaliidese tunde, et see ei reageeri. Skeletid (placeholder UI-d, mis jäljendavad lõplikku paigutust) on sageli parem kasutajakogemus kui üldised spinnerid. Reacti `
` muudab selle lihtsaks. Vue's ja Angularis saate kasutada `v-if`/`ngIf` koos laadimislippudega. - Veaolukorrad: Mis siis, kui kasutaja on ebastabiilsel võrgus ja JavaScripti tüki laadimine ebaõnnestub? Teie rakendus ei tohiks kokku joosta. Mähkige oma laisalt laetud komponendid veapiirde (Error Boundary) sisse (Reactis) või kasutage dünaamilise impordi lubadusel `.catch()`, et ebaõnnestumist graatsiliselt käsitleda. Võiksite näidata veateadet ja "Proovi uuesti" nuppu.
Reacti veapiirde (Error Boundary) näide:
import { ErrorBoundary } from 'react-error-boundary';
function MyComponent() {
return (
<ErrorBoundary
FallbackComponent={({ error, resetErrorBoundary }) => (
<div>
<p>Oops! Failed to load component.</p>
<button onClick={resetErrorBoundary}>Try again</button>
</div>
)}
>
<Suspense fallback={<Spinner />}>
<MyLazyLoadedComponent />
</Suspense>
</ErrorBoundary>
);
}
Tööriistad ja analüüs
Te ei saa optimeerida seda, mida te ei saa mõõta. Kaasaegsed esiosa tööriistad pakuvad suurepäraseid utiliite teie rakenduse kogumite visualiseerimiseks ja analüüsimiseks.
- Webpack Bundle Analyzer: See tööriist loob teie väljundkogumitest puukaardi visualiseeringu. See on hindamatu väärtusega, et tuvastada, mis on iga tüki sees, märgata suuri või dubleeritud sõltuvusi ja kontrollida, kas teie koodi tükeldamise strateegia töötab ootuspäraselt.
- Vite (Rollup Plugin Visualizer): Vite'i kasutajad saavad kasutada `rollup-plugin-visualizer`'it, et saada sarnane interaktiivne graafik oma kogumi koostisest.
Oma kogumeid regulaarselt analüüsides saate tuvastada edasise optimeerimise võimalusi. Näiteks võite avastada, et suur teek nagu `moment.js` või `lodash` on lisatud mitmesse tükki. See võib olla võimalus teisaldada see jagatud `vendors` tükki või leida kergem alternatiiv.
Parimad praktikad ja levinud lõksud
Kuigi koodi tükeldamine on võimas, ei ole see imerohi. Selle vale rakendamine võib mõnikord jõudlust kahjustada.
- Ärge tükeldage liiga palju: Liiga paljude pisikeste tükkide loomine võib olla kahjulik. Iga tükk nõuab eraldi HTTP-päringut ja nende päringute üldkulu võib ületada väiksemate failisuuruste eelised, eriti suure latentsusega mobiilivõrkudes. Leidke tasakaal. Alustage marsruutidest ja seejärel tükeldage strateegiliselt välja ainult suurimad või kõige vähem kasutatud komponendid.
- Analüüsige kasutajate teekondi: Tükeldage oma kood selle põhjal, kuidas kasutajad tegelikult teie rakenduses navigeerivad. Kui 95% kasutajatest läheb sisselogimislehelt otse töölauale, kaaluge töölaua koodi eeltõmbamist sisselogimislehel.
- Grupeerige ühised sõltuvused: Enamikul komplekteerijatel on strateegiad (nagu Webpacki `SplitChunksPlugin`), et automaatselt luua jagatud `vendors` tükk teekidele, mida kasutatakse mitmes marsruudis. See hoiab ära dubleerimise ja parandab vahemälu kasutamist.
- Jälgige kumulatiivset paigutuse nihet (CLS): Komponentide laadimisel veenduge, et teie laadimisolek (nagu skelett) võtaks sama palju ruumi kui lõplik komponent. Vastasel juhul hüppab lehe sisu ringi, kui komponent laaditakse, mis toob kaasa halva CLS-skoori.
Kokkuvõte: kiirem veeb kõigile
Koodi tükeldamine ei ole enam arenenud nišitehnika; see on tänapäevaste, suure jõudlusega veebirakenduste ehitamise põhiline nõue. Liikudes eemale ühest monoliitsest kogumist ja võttes omaks vajaduspõhise laadimise, saate pakkuda oma kasutajatele oluliselt kiiremat ja reageerivamat kogemust, olenemata nende seadmest või võrgutingimustest.
Alustage marsruudipõhise koodi tükeldamisega – see on madalal rippuv vili, mis annab suurima esialgse jõudlusvõidu. Kui see on paigas, analüüsige oma rakendust kogumi analüsaatoriga ja tuvastage kandidaadid komponendipõhiseks tükeldamiseks. Keskenduge suurtele, interaktiivsetele või harva kasutatavatele komponentidele, et oma rakenduse laadimisjõudlust veelgi täiustada.
Neid strateegiaid läbimõeldult rakendades ei muuda te oma veebisaiti lihtsalt kiiremaks; teete veebi kättesaadavamaks ja nauditavamaks ülemaailmsele publikule, üks tükk korraga.