ããã³ããšã³ãã®ã³ãŒãåå²ã«é¢ããå æ¬çãªã¬ã€ãã§ããŠã§ãã¢ããªã±ãŒã·ã§ã³ã®ããã©ãŒãã³ã¹ãåäžãããŸããããReactãVueãAngularã®å®çšçãªäŸãéããŠãã«ãŒãããŒã¹ãšã³ã³ããŒãã³ãããŒã¹ã®æŠç¥ãåŠã³ãŸãã
ããã³ããšã³ãã®ã³ãŒãåå²ïŒã«ãŒãããŒã¹ããã³ã³ã³ããŒãã³ãããŒã¹æŠç¥ã®åŸ¹åºè§£èª¬
çŸä»£ã®ããžã¿ã«ç€ŸäŒã«ãããŠããŠãŒã¶ãŒããŠã§ããµã€ãã«æ±ã第äžå°è±¡ã¯ãå€ãã®å Žåãé床ãšããåäžã®ææšã«ãã£ãŠæ±ºãŸããŸããèªã¿èŸŒã¿ã®é ãã¢ããªã±ãŒã·ã§ã³ã¯ãé«ãçŽåž°çããŠãŒã¶ãŒã®äžæºããããŠåçã®æå€±ã«ã€ãªããå¯èœæ§ããããŸããããã³ããšã³ãã¢ããªã±ãŒã·ã§ã³ãè€éåããã«ã€ããŠããã®ãµã€ãºã®ç®¡çã¯éèŠãªèª²é¡ãšãªããŸããã»ãšãã©ã®ãã³ãã©ãŒã®ããã©ã«ãã®åäœã¯ãã¢ããªã±ãŒã·ã§ã³ã®ãã¹ãŠã®ã³ãŒããå«ãåäžã®ã¢ããªã·ãã¯ãªJavaScriptãã¡ã€ã«ãäœæããããšã§ããããã¯ãã©ã³ãã£ã³ã°ããŒãžã蚪ãããŠãŒã¶ãŒãã管çè ããã·ã¥ããŒãããŠãŒã¶ãŒãããã¡ã€ã«èšå®ããããŠåœŒããæ±ºããŠäœ¿çšããªããããããªããã§ãã¯ã¢ãŠããããŒã®ã³ãŒããŸã§ããŠã³ããŒãããŠããå¯èœæ§ãããããšãæå³ããŸãã
ããã§ç»å Žããã®ãã³ãŒãåå²ã§ããããã¯ã巚倧ãªJavaScriptãã³ãã«ãããªã³ããã³ãã§èªã¿èŸŒã¿å¯èœãªãããå°ãã管çãããããã£ã³ã¯ã«åå²ããããšãå¯èœã«ãã匷åãªãã¯ããã¯ã§ããæåã®ãã¥ãŒã§ãŠãŒã¶ãŒãå¿ èŠãšããã³ãŒãã®ã¿ãéä¿¡ããããšã§ãèªã¿èŸŒã¿æéãåçã«æ¹åãããŠãŒã¶ãŒãšã¯ã¹ããªãšã³ã¹ãåäžãããGoogleã®Core Web Vitalsã®ãããªéèŠãªããã©ãŒãã³ã¹ææšã«è¯ã圱é¿ãäžããããšãã§ããŸãã
ãã®å æ¬çãªã¬ã€ãã§ã¯ãããã³ããšã³ãã®ã³ãŒãåå²ã«ããã2ã€ã®äž»èŠãªæŠç¥ãã«ãŒãããŒã¹ãšã³ã³ããŒãã³ãããŒã¹ã«ã€ããŠæ¢æ±ããŸããReactãVueãAngularãšãã£ã人æ°ã®ãããã¬ãŒã ã¯ãŒã¯ã䜿çšããå®è·µçã§çŸå®çãªäŸã亀ããªãããããããã® ã¢ãããŒãã®çç±ãæ¹æ³ããããŠã¿ã€ãã³ã°ã«ã€ããŠæ·±ãæãäžããŠãããŸãã
åé¡ç¹ïŒã¢ããªã·ãã¯ãªJavaScriptãã³ãã«
ããŒãã§ã®äŒæãå±±ã§ã®ãã¬ããã³ã°ããããŠãã©ãŒãã«ãªããžãã¹äŒè°ãå«ããè€æ°ã®ç®çå°ãžã®æ è¡ã®è·é ããããŠãããšæ³åããŠã¿ãŠãã ãããã¢ããªã·ãã¯ãªã¢ãããŒãã¯ãæ°Žçããã€ãã³ã°ããŒããããžãã¹ã¹ãŒããäžã€ã®å·šå€§ãªã¹ãŒãã±ãŒã¹ã«è©°ã蟌ãããšãããããªãã®ã§ããããŒãã«å°çãããšããå¿ èŠãªã®ã¯æ°Žçã ããªã®ã«ããã®å·šå€§ãªã±ãŒã¹ãéã³åããªããã°ãªããŸãããããã¯éããéå¹ççã§ãåä»ã§ãã
ã¢ããªã·ãã¯ãªJavaScriptãã³ãã«ã¯ããŠã§ãã¢ããªã±ãŒã·ã§ã³ã«åæ§ã®åé¡ããããããŸãïŒ
- éå°ãªåæèªã¿èŸŒã¿æéïŒ ãŠãŒã¶ãŒãäœããèŠããæäœãããããåã«ããã©ãŠã¶ã¯ã¢ããªã±ãŒã·ã§ã³å šäœã®ã³ãŒããããŠã³ããŒãããè§£æããå®è¡ããªããã°ãªããŸãããããã¯ãäœéãªãããã¯ãŒã¯ãæ§èœã®äœãããã€ã¹ã§ã¯æ°ç§ãããããšããããŸãã
- ç¡é§ãªåž¯åå¹ ïŒ ãŠãŒã¶ãŒã¯æ±ºããŠã¢ã¯ã»ã¹ããªããããããªãæ©èœã®ã³ãŒããããŠã³ããŒãããäžå¿ èŠã«ããŒã¿ãã©ã³ãæ¶è²»ããŸããããã¯ç¹ã«ãã€ã³ã¿ãŒãããã¢ã¯ã»ã¹ãé«äŸ¡ãŸãã¯å¶éãããŠããå°åã®ã¢ãã€ã«ãŠãŒã¶ãŒã«ãšã£ãŠåé¡ãšãªããŸãã
- äœããã£ãã·ã¥å¹çïŒ ããæ©èœã®äžè¡ã®ã³ãŒããå°ã倿Žããã ãã§ããã³ãã«å šäœã®ãã£ãã·ã¥ãç¡å¹ã«ãªããŸãããã®çµæã99%ãå€ãã£ãŠããªããŠãããŠãŒã¶ãŒã¯ã¢ããªã±ãŒã·ã§ã³å šäœãåããŠã³ããŒããããããŸãã
- Core Web Vitalsãžã®æªåœ±é¿ïŒ 倧ããªãã³ãã«ã¯ãLargest Contentful Paint (LCP)ãTime to Interactive (TTI)ãšãã£ãææšã«çŽæ¥çãªå®³ãåãŒãããµã€ãã®SEOã©ã³ãã³ã°ããŠãŒã¶ãŒæºè¶³åºŠã«åœ±é¿ãäžããå¯èœæ§ããããŸãã
ã³ãŒãåå²ã¯ãã®åé¡ã®è§£æ±ºçã§ããããã¯ãããŒãçšãå±±çšãäŒè°çšã®3ã€ã®å¥ã ã®å°ããªããã°ã«è·ç©ãè©°ãããããªãã®ã§ããå¿ èŠãªãã®ããå¿ èŠãªãšãã«ã ãæã¡éã¶ã®ã§ãã
解決çïŒã³ãŒãåå²ãšã¯ïŒ
ã³ãŒãåå²ãšã¯ãã¢ããªã±ãŒã·ã§ã³ã®ã³ãŒããããªã³ããã³ããŸãã¯äžŠè¡ããŠèªã¿èŸŒãããšãã§ããæ§ã ãªãã³ãã«ãããã£ã³ã¯ãã«åå²ããããã»ã¹ã§ããäžã€ã®å€§ã㪠`app.js` ã®ä»£ããã«ã`main.js`ã`dashboard.chunk.js`ã`profile.chunk.js` ãªã©ãæã«å ¥ããããšãã§ããŸãã
WebpackãViteãRollupã®ãããªçŸä»£ã®ãã«ãããŒã«ã¯ããã®ããã»ã¹ãä¿¡ããããªãã»ã©ã¢ã¯ã»ã¹ããããããŸããããããã¯ãã¢ãžã¥ãŒã«ãéåæã«ã€ã³ããŒãã§ããçŸä»£ã®JavaScript (ECMAScript) ã®æ©èœã§ããåç㪠`import()` æ§æãæŽ»çšããŠããŸãããã³ãã©ãŒã `import()` ãèŠã€ãããšããã®ã¢ãžã¥ãŒã«ãšãã®äŸåé¢ä¿ã®ããã«èªåçã«å¥ã®ãã£ã³ã¯ãäœæããŸãã
ã³ãŒãåå²ãå®è£ ããããã®æãäžè¬çã§å¹æçãª2ã€ã®æŠç¥ãæ¢ã£ãŠã¿ãŸãããã
æŠç¥1ïŒã«ãŒãããŒã¹ã®ã³ãŒãåå²
ã«ãŒãããŒã¹ã®åå²ã¯ãæãçŽæçã§åºãæ¡çšãããŠããã³ãŒãå岿Šç¥ã§ããããžãã¯ã¯åçŽã§ãïŒãŠãŒã¶ãŒã `/home` ããŒãžã«ããå Žåã`/dashboard` ã `/settings` ããŒãžã®ã³ãŒãã¯å¿ èŠãããŸãããã¢ããªã±ãŒã·ã§ã³ã®ã«ãŒãã«æ²¿ã£ãŠã³ãŒããåå²ããããšã§ããŠãŒã¶ãŒãçŸåšè¡šç€ºããŠããããŒãžã®ã³ãŒãã®ã¿ãããŠã³ããŒãããããã«ã§ããŸãã
ä»çµã¿
ã¢ããªã±ãŒã·ã§ã³ã®ã«ãŒã¿ãŒããç¹å®ã®ã«ãŒãã«é¢é£ä»ããããã³ã³ããŒãã³ããåçã«èªã¿èŸŒãããã«èšå®ããŸãããŠãŒã¶ãŒãåããŠãã®ã«ãŒãã«ç§»åãããšãã«ãŒã¿ãŒã¯å¯Ÿå¿ããJavaScriptãã£ã³ã¯ãååŸããããã®ãããã¯ãŒã¯ãªã¯ãšã¹ããããªã¬ãŒããŸããèªã¿èŸŒãŸãããšãã³ã³ããŒãã³ããã¬ã³ããªã³ã°ããããã®ãã£ã³ã¯ã¯åŸç¶ã®èšªåã®ããã«ãã©ãŠã¶ã«ãã£ãŠãã£ãã·ã¥ãããŸãã
ã«ãŒãããŒã¹åå²ã®å©ç¹
- åæèªã¿èŸŒã¿ã®å€§å¹ ãªåæžïŒ åæãã³ãã«ã«ã¯ãã³ã¢ã¢ããªã±ãŒã·ã§ã³ããžãã¯ãšããã©ã«ãã«ãŒãïŒäŸïŒã©ã³ãã£ã³ã°ããŒãžïŒã®ã³ãŒãã®ã¿ãå«ãŸãããããã¯ããã«å°ãããé«éã«èªã¿èŸŒããŸãã
- å®è£ ã容æïŒ ã»ãšãã©ã®çŸä»£çãªã«ãŒãã£ã³ã°ã©ã€ãã©ãªã¯é å»¶èªã¿èŸŒã¿ãçµã¿èŸŒã¿ã§ãµããŒãããŠãããããå®è£ ã¯ç°¡åã§ãã
- æç¢ºãªè«ççå¢çïŒ ã«ãŒãã¯ã³ãŒãã®èªç¶ã§æç¢ºãªåé¢ç¹ãæäŸããã¢ããªã±ãŒã·ã§ã³ã®ã©ã®éšåãåå²ãããŠããããçè§£ããããããŸãã
å®è£ äŸ
ReactãšReact Router
Reactã¯ãã®ããã«2ã€ã®ã³ã¢ãŠãŒãã£ãªãã£ã`React.lazy()` ãš `
React Routerã䜿çšãã `App.js` ã®äŸïŒ
import React, { Suspense, lazy } from 'react';
import { BrowserRouter as Router, Routes, Route } from 'react-router-dom';
// Statically import components that are always needed
import Navbar from './components/Navbar';
import LoadingSpinner from './components/LoadingSpinner';
// Lazily import route components
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;
ãã®äŸã§ã¯ã`DashboardPage` ãš `SettingsPage` ã®ã³ãŒãã¯åæãã³ãã«ã«å«ãŸããŸãããããã¯ããŠãŒã¶ãŒããããã `/dashboard` ãŸã㯠`/settings` ã«ç§»åãããšãã«ã®ã¿ãµãŒããŒããååŸãããŸãã`Suspense` ã³ã³ããŒãã³ãã¯ããã®ååŸäžã« `LoadingSpinner` ã衚瀺ããããšã§ãã¹ã ãŒãºãªãŠãŒã¶ãŒãšã¯ã¹ããªãšã³ã¹ãä¿èšŒããŸãã
VueãšVue Router
Vue Routerã¯ãã«ãŒãèšå®ã§çŽæ¥åç㪠`import()` æ§æã䜿çšããããšã§ãã«ãŒãã®é å»¶èªã¿èŸŒã¿ãæšæºã§ãµããŒãããŠããŸãã
Vue Routerã䜿çšãã `router/index.js` ã®äŸïŒ
import { createRouter, createWebHistory } from 'vue-router';
import HomeView from '../views/HomeView.vue'; // Statically imported for initial load
const routes = [
{
path: '/',
name: 'home',
component: HomeView
},
{
path: '/about',
name: 'about',
// Route level code-splitting
// This generates a separate chunk (about.[hash].js) for this route
// which is lazy-loaded when the route is visited.
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;
ããã§ã¯ã`/about` ãš `/dashboard` ã«ãŒãã®ã³ã³ããŒãã³ãã¯ãåçãªã€ã³ããŒããè¿ã颿°ãšããŠå®çŸ©ãããŠããŸãããã³ãã©ãŒã¯ãããçè§£ããå¥ã ã®ãã£ã³ã¯ãäœæããŸãã`/* webpackChunkName: "about" */` ã¯ãWebpackã«çµæã®ãã£ã³ã¯ãæ±çšIDã§ã¯ãªã `about.js` ãšããååã«ããããã«æç€ºãããããžãã¯ã³ã¡ã³ããã§ããããã°ã«åœ¹ç«ã¡ãŸãã
AngularãšAngular Router
Angularã®ã«ãŒã¿ãŒã¯ãã«ãŒãèšå®ã® `loadChildren` ããããã£ã䜿çšããŠãã¢ãžã¥ãŒã«å šäœã®é å»¶èªã¿èŸŒã¿ãå¯èœã«ããŸãã
`app-routing.module.ts` ã®äŸïŒ
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { HomeComponent } from './home/home.component'; // Part of the main bundle
const routes: Routes = [
{
path: '',
component: HomeComponent
},
{
path: 'products',
// Lazy load the ProductsModule
loadChildren: () => import('./products/products.module').then(m => m.ProductsModule)
},
{
path: 'admin',
// Lazy load the AdminModule
loadChildren: () => import('./admin/admin.module').then(m => m.AdminModule)
}
];
@NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule]
})
export class AppRoutingModule { }
ãã®Angularã®äŸã§ã¯ã`products` ãš `admin` æ©èœã«é¢é£ããã³ãŒãã¯ãããããç¬èªã®ã¢ãžã¥ãŒã«ïŒ`ProductsModule` ãš `AdminModule`ïŒå ã«ã«ãã»ã«åãããŠããŸãã`loadChildren` æ§æã¯ããŠãŒã¶ãŒã `/products` ãŸã㯠`/admin` ã§å§ãŸãURLã«ç§»åãããšãã«ã®ã¿ããããã®ã¢ãžã¥ãŒã«ãååŸããŠèªã¿èŸŒãããã«Angularã«ãŒã¿ãŒã«æç€ºããŸãã
æŠç¥2ïŒã³ã³ããŒãã³ãããŒã¹ã®ã³ãŒãåå²
ã«ãŒãããŒã¹ã®åå²ã¯çŽ æŽãããåºçºç¹ã§ãããã³ã³ããŒãã³ãããŒã¹ã®åå²ã§ããã©ãŒãã³ã¹æé©åãããã«äžæ©é²ããããšãã§ããŸãããã®æŠç¥ã¯ãå€ãã®å ŽåããŠãŒã¶ãŒã®æäœã«å¿ããŠãç¹å®ã®ãã¥ãŒå ã§å®éã«å¿ èŠã«ãªã£ããšãã«ã®ã¿ã³ã³ããŒãã³ããèªã¿èŸŒãããšãå«ã¿ãŸãã
ããã«ã¯è¡šç€ºãããªãããŸãã¯ãã£ãã«äœ¿çšãããªãã³ã³ããŒãã³ããèããŠã¿ãŠãã ããããªããããã®ã³ãŒããæåã®ããŒãžèªã¿èŸŒã¿ã®äžéšã§ããå¿ èŠãããã®ã§ããããïŒ
ã³ã³ããŒãã³ãããŒã¹åå²ã®äžè¬çãªãŠãŒã¹ã±ãŒã¹
- ã¢ãŒãã«ãšãã€ã¢ãã°ïŒ è€éãªã¢ãŒãã«ïŒäŸïŒãŠãŒã¶ãŒãããã¡ã€ã«ãšãã£ã¿ïŒã®ã³ãŒãã¯ããŠãŒã¶ãŒããããéãããã®ãã¿ã³ãã¯ãªãã¯ãããšãã«ã®ã¿èªã¿èŸŒãå¿ èŠããããŸãã
- ãã¡ãŒã¹ããã¥ãŒä»¥äžã®ã³ã³ãã³ãïŒ é·ãã©ã³ãã£ã³ã°ããŒãžã§ã¯ãããŒãžã®ã¯ããäžã«ããè€éãªã³ã³ããŒãã³ãã¯ããŠãŒã¶ãŒããã®è¿ããŸã§ã¹ã¯ããŒã«ãããšãã«ã®ã¿èªã¿èŸŒãããšãã§ããŸãã
- è€éãªUIèŠçŽ ïŒ ã€ã³ã¿ã©ã¯ãã£ããªãã£ãŒããæ¥ä»ããã«ãŒããªããããã¹ããšãã£ã¿ã®ãããªéãã³ã³ããŒãã³ãã¯ãããããé 眮ãããŠããããŒãžã®åæã¬ã³ããªã³ã°ãé«éåããããã«é å»¶èªã¿èŸŒã¿ã§ããŸãã
- æ©èœãã©ã°ãŸãã¯A/Bãã¹ãïŒ ç¹å®ã®æ©èœãã©ã°ããŠãŒã¶ãŒã«å¯ŸããŠæå¹ã«ãªã£ãŠããå Žåã«ã®ã¿ãã³ã³ããŒãã³ããèªã¿èŸŒã¿ãŸãã
- ããŒã«ããŒã¹ã®UIïŒ ããã·ã¥ããŒãäžã®ç®¡çè å°çšã³ã³ããŒãã³ãã¯ããadminãããŒã«ãæã€ãŠãŒã¶ãŒã«å¯ŸããŠã®ã¿èªã¿èŸŒãŸããã¹ãã§ãã
å®è£ äŸ
React
åã `React.lazy` ãš `Suspense` ã®ãã¿ãŒã³ã䜿çšã§ããŸãããã¢ããªã±ãŒã·ã§ã³ã®ç¶æ ã«åºã¥ããŠæ¡ä»¶ä»ãã§ã¬ã³ããªã³ã°ãããªã¬ãŒããŸãã
é å»¶èªã¿èŸŒã¿ãããã¢ãŒãã«ã®äŸïŒ
import React, { useState, Suspense, lazy } from 'react';
import LoadingSpinner from './components/LoadingSpinner';
// Lazily import the modal component
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>
{/* The modal component and its code will only be loaded when isModalOpen is true */}
{isModalOpen && (
<Suspense fallback={<LoadingSpinner />}>
<EditProfileModal onClose={closeModal} />
</Suspense>
)}
</div>
);
}
export default UserProfilePage;
ãã®ã·ããªãªã§ã¯ã`EditProfileModal.js` ã®JavaScriptãã£ã³ã¯ã¯ããŠãŒã¶ãŒãåããŠãEdit Profileããã¿ã³ãã¯ãªãã¯ããåŸã«ã®ã¿ãµãŒããŒã«ãªã¯ãšã¹ããããŸãã
Vue
Vueã® `defineAsyncComponent` 颿°ã¯ããã«æé©ã§ããå®éã«ã¬ã³ããªã³ã°ããããšãã«ã®ã¿èªã¿èŸŒãŸããã³ã³ããŒãã³ãã®ã©ãããŒãäœæã§ããŸãã
é å»¶èªã¿èŸŒã¿ããããã£ãŒãã³ã³ããŒãã³ãã®äŸïŒ
<template>
<div>
<h1>Sales Dashboard</h1>
<button @click="showChart = true" v-if="!showChart">Show Sales Chart</button>
<!-- The SalesChart component will be loaded and rendered only when showChart is true -->
<SalesChart v-if="showChart" />
</div>
</template>
<script setup>
import { ref, defineAsyncComponent } from 'vue';
const showChart = ref(false);
// Define an async component. The heavy charting library will be in its own chunk.
const SalesChart = defineAsyncComponent(() =>
import('../components/SalesChart.vue')
);
</script>
ããã§ã¯ãæœåšçã«éã `SalesChart` ã³ã³ããŒãã³ãïŒããã³ãã£ãŒãã©ã€ãã©ãªãªã©ã®äŸåé¢ä¿ïŒã®ã³ãŒããåé¢ãããŠããŸããããã¯ããŠãŒã¶ãŒããã¿ã³ãã¯ãªãã¯ããŠæç€ºçã«ãªã¯ãšã¹ããããšãã«ã®ã¿ããŠã³ããŒããããããŠã³ããããŸãã
é«åºŠãªãã¯ããã¯ãšãã¿ãŒã³
ã«ãŒãããŒã¹ãšã³ã³ããŒãã³ãããŒã¹ã®åå²ã®åºæ¬ããã¹ã¿ãŒãããããŠãŒã¶ãŒãšã¯ã¹ããªãšã³ã¹ãããã«æŽç·Žãããããã«ãããé«åºŠãªãã¯ããã¯ãæ¡çšã§ããŸãã
ãã£ã³ã¯ã®ããªããŒããšããªãã§ãã
ãŠãŒã¶ãŒããªã³ã¯ãã¯ãªãã¯ããã®ãåŸ ã£ãŠããæ¬¡ã®ã«ãŒãã®ã³ãŒããååŸãããšãããããªé å»¶ãçããå¯èœæ§ããããŸããäºåã«ã³ãŒããèªã¿èŸŒãããšã§ããããããè³¢ã察åŠã§ããŸãã
- ããªãã§ããïŒPrefetchingïŒïŒ ããã¯ããã©ãŠã¶ã«ã¢ã€ãã«æéäžã«ãªãœãŒã¹ãååŸããããã«æç€ºããŸãããªããªãããŠãŒã¶ãŒãå°æ¥ã®ããã²ãŒã·ã§ã³ã§ãããå¿ èŠãšããå¯èœæ§ãããããã§ããããã¯åªå 床ã®äœããã³ãã§ããäŸãã°ããŠãŒã¶ãŒããã°ã€ã³ããããããã·ã¥ããŒãã®ã³ãŒããããªãã§ããã§ããŸãããªããªãã圌ããæ¬¡ã«ããã«è¡ãå¯èœæ§ãéåžžã«é«ãããã§ãã
- ããªããŒãïŒPreloadingïŒïŒ ããã¯ããã©ãŠã¶ã«ãªãœãŒã¹ãé«ãåªå 床ã§ååŸããããã«æç€ºããŸãããªããªããããã¯çŸåšã®ããŒãžã§å¿ èŠã§ããããã®çºèŠãé ããããã§ãïŒäŸïŒCSSãã¡ã€ã«ã®å¥¥æ·±ãã§å®çŸ©ããããã©ã³ãïŒãã³ãŒãåå²ã®æèã§ã¯ããŠãŒã¶ãŒããªã³ã¯ã«ãããŒãããšãã«ãã£ã³ã¯ãããªããŒãããããšã§ãã¯ãªãã¯ãããšãã«ããã²ãŒã·ã§ã³ãç¬æã«æããããããã«ã§ããŸãã
WebpackãViteã®ãããªãã³ãã©ãŒã¯ããããžãã¯ã³ã¡ã³ããã䜿çšããŠãããå®è£ ã§ããŸãïŒ
// Prefetch: good for likely next pages
import(/* webpackPrefetch: true, webpackChunkName: "dashboard" */ './pages/DashboardPage');
// Preload: good for high-confidence next interactions on the current page
const openModal = () => {
import(/* webpackPreload: true, webpackChunkName: "profile-modal" */ './components/ProfileModal');
// ... then open the modal
}
èªã¿èŸŒã¿ç¶æ ãšãšã©ãŒç¶æ ã®åŠç
ãããã¯ãŒã¯çµç±ã§ã³ãŒããèªã¿èŸŒãããšã¯ã倱æããå¯èœæ§ã®ããéåææäœã§ããå ç¢ãªå®è£ ã¯ããããèæ ®ã«å ¥ããªããã°ãªããŸããã
- èªã¿èŸŒã¿ç¶æ
ïŒ ãã£ã³ã¯ãååŸãããŠããéã¯ãåžžã«ãŠãŒã¶ãŒã«ãã£ãŒãããã¯ãæäŸããŠãã ãããããã«ãããUIãç¡åå¿ã«æããã®ãé²ããŸããã¹ã±ã«ãã³ïŒæçµçãªã¬ã€ã¢ãŠããæš¡å£ãããã¬ãŒã¹ãã«ããŒUIïŒã¯ãäžè¬çãªã¹ãããŒãããåªãããŠãŒã¶ãŒãšã¯ã¹ããªãšã³ã¹ãæäŸããããšãå€ãã§ããReactã® `
` ã¯ããã容æã«ããŸããVueãAngularã§ã¯ãããŒãã£ã³ã°ãã©ã°ãšå ±ã« `v-if`/`ngIf` ã䜿çšã§ããŸãã - ãšã©ãŒç¶æ ïŒ ãŠãŒã¶ãŒãäžå®å®ãªãããã¯ãŒã¯äžã«ããŠãJavaScriptãã£ã³ã¯ã®èªã¿èŸŒã¿ã«å€±æããå Žåã¯ã©ãããŸããïŒ ã¢ããªã±ãŒã·ã§ã³ã¯ã¯ã©ãã·ã¥ãã¹ãã§ã¯ãããŸãããé å»¶èªã¿èŸŒã¿ãããã³ã³ããŒãã³ãããšã©ãŒããŠã³ããªïŒReactã®å ŽåïŒã§ã©ããããããåçã€ã³ããŒãã®ãããã¹ã§ `.catch()` ã䜿çšããŠã倱æãé©åã«åŠçããŸãããšã©ãŒã¡ãã»ãŒãžãšãå詊è¡ããã¿ã³ã衚瀺ããããšãã§ããŸãã
Reactã®ãšã©ãŒããŠã³ããªã®äŸïŒ
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>
);
}
ããŒã«ãšåæ
枬å®ã§ããªããã®ã¯æé©åã§ããŸãããçŸä»£ã®ããã³ããšã³ãããŒã«ã¯ãã¢ããªã±ãŒã·ã§ã³ã®ãã³ãã«ãèŠèŠåãåæããããã®åªãããŠãŒãã£ãªãã£ãæäŸããŸãã
- Webpack Bundle AnalyzerïŒ ãã®ããŒã«ã¯ãåºåãã³ãã«ã®ããªãŒãããèŠèŠåãäœæããŸããåãã£ã³ã¯å ã«äœãå«ãŸããŠãããã倧ããªãŸãã¯éè€ããäŸåé¢ä¿ãç¹å®ããã³ãŒãå岿Šç¥ãæåŸ ã©ããã«æ©èœããŠãããã確èªããã®ã«éåžžã«äŸ¡å€ããããŸãã
- Vite (Rollup Plugin Visualizer)ïŒ ViteãŠãŒã¶ãŒã¯ `rollup-plugin-visualizer` ã䜿çšããŠããã³ãã«æ§æã®åæ§ã®ã€ã³ã¿ã©ã¯ãã£ããªãã£ãŒããåŸãããšãã§ããŸãã
ãã³ãã«ã宿çã«åæããããšã§ããããªãæé©åã®æ©äŒãç¹å®ã§ããŸããäŸãã°ã`moment.js` ã `lodash` ã®ãããªå€§ããªã©ã€ãã©ãªãè€æ°ã®ãã£ã³ã¯ã«å«ãŸããŠããããšãçºèŠãããããããŸãããããã¯ããããå ±æã® `vendors` ãã£ã³ã¯ã«ç§»åãããããã軜éãªä»£æ¿ææ®µãèŠã€ããæ©äŒã«ãªãå¯èœæ§ããããŸãã
ãã¹ããã©ã¯ãã£ã¹ãšããããèœãšã穎
ã³ãŒãåå²ã¯åŒ·åã§ãããäžèœè¬ã§ã¯ãããŸããã誀ã£ãŠé©çšãããšãããã©ãŒãã³ã¹ãæãªãããšããããŸãã
- åå²ããããªãïŒ ããŸãã«ãå€ãã®å°ããªãã£ã³ã¯ãäœæããããšã¯é广ã«ãªãå¯èœæ§ããããŸããåãã£ã³ã¯ã¯å¥ã ã®HTTPãªã¯ãšã¹ããå¿ èŠãšãããããã®ãªã¯ãšã¹ãã®ãªãŒããŒãããã¯ãç¹ã«é«é å»¶ã®ã¢ãã€ã«ãããã¯ãŒã¯ã§ã¯ããã¡ã€ã«ãµã€ãºãå°ãããšããå©ç¹ãäžåãããšããããŸãããã©ã³ã¹ãèŠã€ããŠãã ããããŸãã«ãŒãããå§ããæ¬¡ã«æã倧ããããæã䜿çšãããªãã³ã³ããŒãã³ãã ããæŠç¥çã«åå²ããŸãã
- ãŠãŒã¶ãŒãžã£ãŒããŒãåæããïŒ ãŠãŒã¶ãŒãå®éã«ã¢ããªã±ãŒã·ã§ã³ãã©ã®ããã«ããã²ãŒããããã«åºã¥ããŠã³ãŒããåå²ããŸãã95%ã®ãŠãŒã¶ãŒããã°ã€ã³ããŒãžããçŽæ¥ããã·ã¥ããŒãã«ç§»åããå Žåããã°ã€ã³ããŒãžã§ããã·ã¥ããŒãã®ã³ãŒããããªãã§ããããããšãæ€èšããŠãã ããã
- å ±éã®äŸåé¢ä¿ãã°ã«ãŒãåããïŒ ã»ãšãã©ã®ãã³ãã©ãŒã¯ãè€æ°ã®ã«ãŒãã§äœ¿çšãããã©ã€ãã©ãªã®ããã«å ±æã® `vendors` ãã£ã³ã¯ãèªåçã«äœæããæŠç¥ïŒWebpackã® `SplitChunksPlugin` ãªã©ïŒãæã£ãŠããŸããããã«ãããéè€ãé²ãããã£ãã·ã¥ãæ¹åããŸãã
- Cumulative Layout Shift (CLS)ã«æ³šæããïŒ ã³ã³ããŒãã³ããèªã¿èŸŒãéãããŒãã£ã³ã°ç¶æ ïŒã¹ã±ã«ãã³ãªã©ïŒãæçµçãªã³ã³ããŒãã³ããšåãã¹ããŒã¹ãå ããããã«ããŠãã ãããããããªããšãã³ã³ããŒãã³ããèªã¿èŸŒãŸãããšãã«ããŒãžã³ã³ãã³ããé£ã³è·³ããCLSã¹ã³ã¢ãæªåããŸãã
çµè«ïŒãã¹ãŠã®äººã®ããã®ããéããŠã§ã
ã³ãŒãåå²ã¯ãã¯ãé«åºŠã§ããããªãã¯ããã¯ã§ã¯ãããŸãããããã¯ãçŸä»£çã§é«æ§èœãªãŠã§ãã¢ããªã±ãŒã·ã§ã³ãæ§ç¯ããããã®åºæ¬çãªèŠä»¶ã§ããåäžã®ã¢ããªã·ãã¯ãªãã³ãã«ããé¢ãããªã³ããã³ãã®èªã¿èŸŒã¿ãæ¡çšããããšã§ããŠãŒã¶ãŒã®ããã€ã¹ããããã¯ãŒã¯ç¶æ³ã«é¢ä¿ãªããå€§å¹ ã«é«éã§å¿çæ§ã®é«ããšã¯ã¹ããªãšã³ã¹ãæäŸã§ããŸãã
ãŸãã¯ã«ãŒãããŒã¹ã®ã³ãŒãåå²ããå§ããŠãã ãããããã¯ãæåã«æå€§ã®ããã©ãŒãã³ã¹åäžããããããæã£åãæ©ãææã§ãããããå°å ¥ããããããã³ãã«ã¢ãã©ã€ã¶ãŒã§ã¢ããªã±ãŒã·ã§ã³ãåæããã³ã³ããŒãã³ãããŒã¹ã®åå²ã®åè£ãç¹å®ããŸããã¢ããªã±ãŒã·ã§ã³ã®èªã¿èŸŒã¿ããã©ãŒãã³ã¹ãããã«æŽç·Žãããããã«ã倧ãããã€ã³ã¿ã©ã¯ãã£ãããŸãã¯ãã£ãã«äœ¿çšãããªãã³ã³ããŒãã³ãã«çŠç¹ãåœãŠãŠãã ããã
ãããã®æŠç¥ãææ ®æ·±ãé©çšããããšã§ããŠã§ããµã€ããéãããã ãã§ãªããã°ããŒãã«ãªãªãŒãã£ãšã³ã¹ã«ãšã£ãŠãŠã§ããããã¢ã¯ã»ã¹ãããããæ¥œãããã®ã«ããŠããã®ã§ããäžåºŠã«äžã€ã®ãã£ã³ã¯ãã€ã