Thử tính năng lazyload module của angular2 rc5 với webpack 2
TIL
491
White

Hoàng Duy viết ngày 05/09/2016

05/09/2106 5:21PM
UPDATE: tương thích với angualar 2.0.0-rc.6

Hello bà con, hôm nay team angular2 release phiên bản RC5 có một số thay đổi, trong đó có việc giới thiệu NgModule và khả năng lazy load cho router. Em cũng xem qua vì hứng thú với lazy load.

NgModule thì dễ hiểu rồi, nhất là đối với các bác đã làm angular 1. Đó là một gói các thành phần gồm provider, component, pipe, module con. Khai báo như này:

@NgModule({
  imports: [
    // các module phụ thuộc, route cũng sẽ tính là module, tí nói sau.
  ],
  declarations: [
    // các thứ dùng trong template, tức là component, directive với pipe
  ],
  bootstrap: [
    // cái module chính có cái này để bộ dịch biết load cái component nào là root.
  ],
  providers: [
    // các provider
  ],
})
class AppModule {}

OK. Quay lại routes, chúng ta cần khai báo một route module như vầy

import { Routes, RouterModule } from '@angular/router';
export const AppRoutes: Routes = [
  {
    path: '',
    component: MainWrapper,
    children: [
      {
        path: 'library',
        // component này là lazy, khi nào access route 'library' mới load.
        loadChildren: './library', // (*)
      },
    ],
  }, {
    path: 'login',
    // đây là 1 component bình thường, load cùng app
    component: Login,
  },
];
export const routeModule = RouterModule.forRoot(AppRoutes);

Sau đó khai báo vào NgModule:

@NgModule({
  imports: [
    routeModule
  ],
})
class AppModule {}

Phần ví dụ trên dùng SystemJS, chỗ (*) load rất đơn giản vì systemjs load async tât cả các file rồi. Tuy nhiên mình lại bundle bằng webpack, tất cả gộp làm 1 nên phải sửa đổi 1 tí.

Về webpack thì nó hỗ trợ chia nhỏ bundle thành các chunk, để làm được điều này thay vì import trực tiếp thì các bác dùng require.ensure với webpack 1 và system.import với webpack 2:

// wp1
require.ensure([], (require) => {
   require(path-to-file)
})

// wp2
System.import(path-to-file)

Phần require.ensure mình không chắc chắn lắm, đại khái thế.
Khi build webpack sẽ nhét các file này vào các chunk riêng, lúc nào gọi mới load.

Như thế chúng ta có thể khai báo router như sau:

// chỗ này để ngăn thằng typescript báo lỗi type missmatch
// UPDATE rc-6: phần này không cần nữa vì routes config đã chấp nhận hàm
//- const asyncWrap: Type = (a: Function) => a;


export const AppRoutes: Routes = [
  {
    ...
    children: [
      ...
      {
        path: 'library',
        loadChildren: () => System.import('./library').then(r => r.LibraryModule),
      },
    ],
  },
  ...
];

Dụng ý là đưa cho loadChildren một hàm, và bảo nó khi nào load component thì thực thi hàm này để lấy ra file cần load.

Chúng ta cần sửa đổi NgModuleFactoryLoader, cái này thực hiện việc load module async

import {
  NgModuleFactoryLoader,
  Injectable,
  Compiler,
  NgModuleFactory,
  Type,
} from '@angular/core';

@Injectable()
export class AsyncNgModuleLoader implements NgModuleFactoryLoader {
  constructor(private compiler: Compiler) {}

  load(modulePath: string | Function): Promise<NgModuleFactory<any>> {
    if (typeof modulePath === 'function') {
      return Promise
        .resolve(modulePath())
        .then((type: any) => checkNotEmpty(type, '', ''))
        .then((type: any) => this.compiler.compileModuleAsync(type));
    }

    return Promise.resolve(undefined);
  }
}

function checkNotEmpty(value: any, modulePath: string, exportName: string): any {
  if (!value) {
    throw new Error(`Cannot find '${exportName}' in '${modulePath}'`);
  }
  return value;
}

Sau đó khai báo với App là tao dùng thằng loader mới này thay cho thằng cũ. Dependencies injection muôn năm

@NgModule({
  ....
  providers: [
    { provide: NgModuleFactoryLoader, useClass: AsyncNgModuleLoader },
  ],
})
export class AppModule {}

Chạy ngon. Đã gì đâu.
alt text

Hình trên thể hiện cảnh file 0.bundle.js được load khi click link library.

Viết xong đọc suýt hiểu, thôi thì đây là repo minh họa =)))

Sắp tới em sẽ tổng hợp một series về angular2, tùy độ nhiệt tình của các bác. Không thích thì hoy đi nha.


[*] AsyncLoader được ăn trộm, hoặc lấy cảm hứng từ repo của Brandon Roberts

mahpahh 10-08-2016

Bình luận


White
{{ comment.user.name }}
Bỏ hay Hay
{{comment.like_count}}
Male avatar
{{ comment_error }}
Hủy
   

Hiển thị thử

Chỉnh sửa

White

Hoàng Duy

24 bài viết.
54 người follow
Kipalog
{{userFollowed ? 'Following' : 'Follow'}}
Cùng một tác giả
White
39 8
Xin chào, đây là lần đầu tiên mình post bài ở đây. Nhiều vấn đề mình cũng không rành lắm, có gì sai mọi người góp ý nhé. Xin cảm ơn :D Bài này gi...
Hoàng Duy viết hơn 2 năm trước
39 8
White
30 3
Đây là một trong các concept mới đối tượng mới được đưa vào ECMAScript 6. Việc sử dụng chúng rất dễ nhưng để hiểu được thì (đối với tôi) cũng cần k...
Hoàng Duy viết hơn 2 năm trước
30 3
White
21 8
Lâu không post gì muốn viết một bài dài dài về js cơ mà đau đầu quá viết mãi không xong, thôi post bài ngắn vậy :smiley: Lấy screen size ở đây tôi...
Hoàng Duy viết hơn 2 năm trước
21 8
Bài viết liên quan
White
18 1
Toán tử XOR có tính chất: + A XOR A = 0 + 0 XOR A = A Với tính chất này, có thể cài đặt bài toán sau với độ phức tạp O(N) về runtime, và với O(1)...
kiennt viết hơn 1 năm trước
18 1
White
1 1
Chào mọi người, hôm nay mình viết một bài TIL nhỏ về cách lấy độ phân giải của màn hình hiện tại đang sử dụng. xdpyinfo | grep dimensions Kết quả...
namtx viết 7 tháng trước
1 1
White
8 0
Lấy fake path của file trong html input Ngữ cảnh: em cần làm một cái nút tải ảnh lên có preview. GIải pháp đầu: Dùng (Link) đọc file ảnh thành ba...
Hoàng Duy viết gần 2 năm trước
8 0
{{like_count}}

kipalog

{{ comment_count }}

bình luận

{{liked ? "Đã kipalog" : "Kipalog"}}


White
{{userFollowed ? 'Following' : 'Follow'}}
24 bài viết.
54 người follow

 Đầu mục bài viết

Vẫn còn nữa! x

Kipalog vẫn còn rất nhiều bài viết hay và chủ đề thú vị chờ bạn khám phá!