คู่มือที่ครอบคลุมเกี่ยวกับเทคนิคการแบ่งโค้ดส่วนหน้า โดยเน้นที่แนวทางแบบ Route-Based และ Component-Based เพื่อปรับปรุงประสิทธิภาพและประสบการณ์ผู้ใช้
Frontend Code Splitting: Route-Based and Component-Based
ในขอบเขตของการพัฒนาเว็บสมัยใหม่ การมอบประสบการณ์ผู้ใช้ที่รวดเร็วและตอบสนองเป็นสิ่งสำคัญยิ่ง เมื่อแอปพลิเคชันมีความซับซ้อนมากขึ้น ขนาดของ JavaScript bundles สามารถขยายใหญ่ขึ้น ทำให้เวลาในการโหลดเริ่มต้นเพิ่มขึ้นและประสบการณ์ผู้ใช้ช้าลง การแบ่งโค้ดเป็นเทคนิคที่มีประสิทธิภาพในการต่อสู้กับปัญหานี้โดยการแบ่งโค้ดแอปพลิเคชันออกเป็นส่วนย่อยๆ ที่จัดการได้ง่ายกว่า ซึ่งสามารถโหลดได้ตามต้องการ
คู่มือนี้จะสำรวจกลยุทธ์หลักสองประการสำหรับการแบ่งโค้ดส่วนหน้า: แบบ Route-Based และ Component-Based เราจะเจาะลึกหลักการเบื้องหลังแต่ละแนวทาง อภิปรายข้อดีและข้อเสีย และให้ตัวอย่างที่เป็นประโยชน์เพื่อแสดงให้เห็นถึงการนำไปใช้งาน
What is Code Splitting?
Code splitting คือการแบ่งพาร์ติชัน JavaScript bundle แบบ monolithic ออกเป็น bundle หรือ chunk ที่เล็กลง แทนที่จะโหลดโค้ดแอปพลิเคชันทั้งหมดล่วงหน้า จะโหลดเฉพาะโค้ดที่จำเป็นสำหรับมุมมองหรือคอมโพเนนต์ปัจจุบันเท่านั้น ซึ่งจะช่วยลดขนาดการดาวน์โหลดเริ่มต้น ทำให้โหลดหน้าเว็บได้เร็วขึ้นและปรับปรุงประสิทธิภาพที่รับรู้ได้
ประโยชน์หลักของการแบ่งโค้ด ได้แก่:
- Improved initial load time: ขนาด bundle เริ่มต้นที่เล็กลงส่งผลให้โหลดได้เร็วขึ้นและสร้างความประทับใจแรกที่ดีกว่าสำหรับผู้ใช้
- Reduced parsing and compilation time: เบราว์เซอร์ใช้เวลาน้อยลงในการแยกวิเคราะห์และคอมไพล์ bundle ที่เล็กลง ส่งผลให้การแสดงผลเร็วขึ้น
- Enhanced user experience: เวลาในการโหลดที่เร็วขึ้นส่งผลให้ประสบการณ์ผู้ใช้ราบรื่นและตอบสนองได้ดีขึ้น
- Optimized resource utilization: โหลดเฉพาะโค้ดที่จำเป็นเท่านั้น ซึ่งช่วยประหยัดแบนด์วิดท์และทรัพยากรของอุปกรณ์
Route-Based Code Splitting
Route-based code splitting เกี่ยวข้องกับการแบ่งโค้ดแอปพลิเคชันตามเส้นทางหรือหน้าของแอปพลิเคชัน แต่ละเส้นทางสอดคล้องกับ chunk ของโค้ดแยกต่างหากที่โหลดเฉพาะเมื่อผู้ใช้นำทางไปยังเส้นทางนั้น แนวทางนี้มีประสิทธิภาพอย่างยิ่งสำหรับแอปพลิเคชันที่มีส่วนหรือคุณสมบัติที่แตกต่างกันซึ่งไม่ได้เข้าถึงบ่อยนัก
Implementation
JavaScript frameworks ที่ทันสมัย เช่น React, Angular และ Vue ให้การสนับสนุนในตัวสำหรับการแบ่งโค้ดแบบ route-based ซึ่งมักจะใช้ประโยชน์จาก dynamic imports นี่คือวิธีการทำงานตามแนวคิด:
- Define routes: กำหนดเส้นทางของแอปพลิเคชันโดยใช้ routing library เช่น React Router, Angular Router หรือ Vue Router
- Use dynamic imports: แทนที่จะ import components โดยตรง ให้ใช้ dynamic imports (
import()) เพื่อโหลด asynchronously เมื่อเปิดใช้งานเส้นทางที่สอดคล้องกัน - Configure build tool: กำหนดค่า build tool ของคุณ (เช่น webpack, Parcel, Rollup) เพื่อจดจำ dynamic imports และสร้าง chunk แยกต่างหากสำหรับแต่ละเส้นทาง
Example (React with React Router)
พิจารณาแอปพลิเคชัน React อย่างง่ายที่มีสองเส้นทาง: /home และ /about
// App.js
import React, { Suspense, lazy } from 'react';
import { BrowserRouter as Router, Route, Switch } from 'react-router-dom';
const Home = lazy(() => import('./components/Home'));
const About = lazy(() => import('./components/About'));
function App() {
return (
Loading... ในตัวอย่างนี้ คอมโพเนนต์ Home และ About จะถูกโหลดแบบ lazy โดยใช้ React.lazy() และ dynamic imports คอมโพเนนต์ Suspense มี fallback UI ในขณะที่กำลังโหลดคอมโพเนนต์ React Router จัดการการนำทางและทำให้มั่นใจว่าคอมโพเนนต์ที่ถูกต้องจะถูกแสดงผลตามเส้นทางปัจจุบัน
Example (Angular)
ใน Angular การแบ่งโค้ดแบบ route-based ทำได้โดยใช้ lazy-loaded modules
// app-routing.module.ts
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
const routes: Routes = [
{ path: 'home', loadChildren: () => import('./home/home.module').then(m => m.HomeModule) },
{ path: 'about', loadChildren: () => import('./about/about.module').then(m => m.AboutModule) }
];
@NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule]
})
export class AppRoutingModule { }
ที่นี่ คุณสมบัติ loadChildren ในการกำหนดค่าเส้นทางระบุเส้นทางไปยังโมดูลที่ควรโหลดแบบ lazy Angular's router จะโหลดโมดูลและคอมโพเนนต์ที่เกี่ยวข้องโดยอัตโนมัติเมื่อผู้ใช้นำทางไปยังเส้นทางที่สอดคล้องกันเท่านั้น
Example (Vue.js)
Vue.js ยังรองรับการแบ่งโค้ดแบบ route-based โดยใช้ dynamic imports ในการกำหนดค่า router
// router.js
import Vue from 'vue';
import VueRouter from 'vue-router';
Vue.use(VueRouter);
const routes = [
{ path: '/', component: () => import('./components/Home.vue') },
{ path: '/about', component: () => import('./components/About.vue') }
];
const router = new VueRouter({
routes
});
export default router;
ตัวเลือก component ในการกำหนดค่าเส้นทางใช้ dynamic import เพื่อโหลดคอมโพเนนต์ asynchronously Vue Router จะจัดการการโหลดและการแสดงผลของคอมโพเนนต์เมื่อเข้าถึงเส้นทาง
Benefits of Route-Based Code Splitting
- Simple to implement: การแบ่งโค้ดแบบ route-based ค่อนข้างตรงไปตรงมาในการนำไปใช้งาน โดยเฉพาะอย่างยิ่งกับการสนับสนุนที่ได้รับจาก frameworks ที่ทันสมัย
- Clear separation of concerns: แต่ละเส้นทางแสดงถึงส่วนที่แตกต่างกันของแอปพลิเคชัน ทำให้ง่ายต่อการอ้างเหตุผลเกี่ยวกับโค้ดและการพึ่งพา
- Effective for large applications: การแบ่งโค้ดแบบ route-based มีประโยชน์อย่างยิ่งสำหรับแอปพลิเคชันขนาดใหญ่ที่มีเส้นทางและคุณสมบัติมากมาย
Drawbacks of Route-Based Code Splitting
- May not be granular enough: การแบ่งโค้ดแบบ route-based อาจไม่เพียงพอสำหรับแอปพลิเคชันที่มีคอมโพเนนต์ที่ซับซ้อนซึ่งใช้ร่วมกันในหลายเส้นทาง
- Initial load time may still be high: หากเส้นทางมี dependencies จำนวนมาก เวลาในการโหลดเริ่มต้นสำหรับเส้นทางนั้นอาจยังคงมีนัยสำคัญ
Component-Based Code Splitting
Component-based code splitting เป็นการแบ่งโค้ดไปอีกขั้นโดยการแบ่งโค้ดแอปพลิเคชันออกเป็นส่วนย่อยๆ ตาม individual components แนวทางนี้ช่วยให้สามารถควบคุมการโหลดโค้ดได้อย่างละเอียดมากขึ้น และอาจมีประสิทธิภาพอย่างยิ่งสำหรับแอปพลิเคชันที่มี UIs ที่ซับซ้อนและ reusable components
Implementation
Component-based code splitting ยังอาศัย dynamic imports แต่แทนที่จะโหลดทั้งเส้นทาง individual components จะถูกโหลดตามต้องการ สิ่งนี้สามารถทำได้โดยใช้เทคนิคต่างๆ เช่น:
- Lazy loading components: ใช้ dynamic imports เพื่อโหลด components เฉพาะเมื่อจำเป็นเท่านั้น เช่น เมื่อแสดงผลเป็นครั้งแรก หรือเมื่อมีเหตุการณ์เฉพาะเกิดขึ้น
- Conditional rendering: แสดงผล components แบบมีเงื่อนไขตาม user interaction หรือปัจจัยอื่นๆ โดยโหลดโค้ด component เฉพาะเมื่อตรงตามเงื่อนไข
- Intersection Observer API: ใช้ Intersection Observer API เพื่อตรวจจับเมื่อ component มองเห็นได้ใน viewport และโหลดโค้ดตามนั้น สิ่งนี้มีประโยชน์อย่างยิ่งสำหรับการโหลด components ที่เริ่มต้นนอกหน้าจอ
Example (React)
import React, { Suspense, lazy } from 'react';
const MyComponent = lazy(() => import('./MyComponent'));
function App() {
return (
Loading... }>