>  기사  >  웹 프론트엔드  >  Webpack은 AngularJS_AngularJS의 지연 로딩을 구현합니다.

Webpack은 AngularJS_AngularJS의 지연 로딩을 구현합니다.

WBOY
WBOY원래의
2016-05-16 15:12:221657검색

단일 페이지 앱이 성장함에 따라 다운로드 시간도 늘어납니다. 이는 사용자 경험에 별로 좋지 않습니다(힌트: 그러나 사용자 경험은 우리가 단일 페이지 앱을 개발하는 이유입니다). 더 많은 코드는 더 큰 파일을 의미하며, 코드 압축이 더 이상 요구 사항을 충족하지 못할 때까지 사용자를 위해 할 수 있는 유일한 일은 전체 애플리케이션을 한 번에 다운로드하도록 요청하는 것을 중단하는 것입니다. 게으른 로딩이 유용한 곳입니다. 모든 파일을 한 번에 다운로드하는 대신 사용자는 지금 필요한 파일만 다운로드할 수 있습니다.

그래요. 애플리케이션을 지연 로딩하는 방법은 무엇입니까? 기본적으로 두 가지로 나누어집니다. 모듈을 작은 덩어리로 나누고 요청 시 이러한 덩어리를 로드할 수 있는 메커니즘을 구현하십시오. 많은 일을 하는 것 같지 않나요? Webpack을 사용하는 경우에는 그렇지 않습니다. 기본적으로 코드 분할 기능을 지원합니다. 이 기사에서는 여러분이 Webpack에 익숙하다고 가정하지만, 그렇지 않은 경우 여기에 소개합니다. 간단히 말해서 AngularUI Router와 ocLazyLoad도 사용하겠습니다.

코드는 GitHub에서 확인할 수 있습니다. 언제든지 포크할 수 있습니다.

웹팩 구성

사실 특별한 건 없습니다. 실제로 문서에서 복사하여 붙여넣기만 하면 됩니다. 유일한 차이점은 코드를 깨끗하게 유지하기 위해 ng-annotate를 사용하고 ECMAScript 2015 마법 중 일부를 사용하기 위해 babel을 사용한다는 것입니다. ES6에 관심이 있다면 이전 게시물을 확인해 보세요. 이러한 것들은 모두 훌륭하지만 지연 로딩을 구현하는 데 필요한 것은 없습니다.

// webpack.config.js
var config = {
entry: {
app: ['./src/core/bootstrap.js'],
},
output: {
path: __dirname + '/build/',
filename: 'bundle.js',
},
resolve: {
root: __dirname + '/src/',
},
module: {
noParse: [],
loaders: [
{ test: /\.js$/, exclude: /node_modules/,
loader: 'ng-annotate!babel' },
{ test: /\.html$/, loader: 'raw' },
]
}
};
module.exports = config;

신청

애플리케이션 모듈은 모든 페이지에서 다운로드해야 하는 Bundle.js에 포함되어야 하는 기본 파일입니다. 보시다시피, 전역 종속성을 제외하고 복잡한 것은 로드하지 않습니다. 컨트롤러를 로드하는 것과 달리 라우팅 구성만 로드합니다.

// app.js
'use strict';
export default require('angular')
.module('lazyApp', [
require('angular-ui-router'),
require('oclazyload'),
require('./pages/home/home.routing').name,
require('./pages/messages/messages.routing').name,
]);

라우팅 구성

모든 지연 로딩은 경로 구성에서 구현됩니다. 앞서 말했듯이 우리는 중첩된 뷰를 구현해야 하기 때문에 AngularUI Router를 사용하고 있습니다. 우리에게는 몇 가지 사용 사례가 있습니다. 전체 모듈(하위 상태 컨트롤러 포함)을 로드하거나 (상위 상태에 대한 종속성과 관계없이) 상태당 하나의 컨트롤러를 로드할 수 있습니다.

전체 모듈 로드

사용자가 /home 경로를 입력하면 브라우저가 홈 모듈을 다운로드합니다. 여기에는 home과 home.about의 두 가지 상태에 대한 두 개의 컨트롤러가 포함되어 있습니다. 상태 구성 객체의 해결 속성을 통해 지연 로딩을 구현할 수 있습니다. Webpack의 require.ensure 메소드 덕분에 홈 모듈을 첫 번째 코드 블록으로 생성할 수 있습니다. 1.bundle.js 라고 합니다. $ocLazyLoad.load가 없으면 Argument 'HomeController' is not a function, got unundefined 오류가 발생하는 것을 발견하게 됩니다. 왜냐하면 Angular의 디자인에서는 애플리케이션을 시작한 후 파일을 로드하는 것이 불가능하기 때문입니다. 그러나 $ocLazyLoad.load를 사용하면 시작 중에 모듈을 등록하고 로드된 후에 사용할 수 있습니다.

// home.routing.js
'use strict';
function homeRouting($urlRouterProvider, $stateProvider) {
$urlRouterProvider.otherwise('/home');
$stateProvider
.state('home', {
url: '/home',
template: require('./views/home.html'),
controller: 'HomeController as vm',
resolve: {
loadHomeController: ($q, $ocLazyLoad) => {
return $q((resolve) => {
require.ensure([], () => {
// load whole module
let module = require('./home');
$ocLazyLoad.load({name: 'home'});
resolve(module.controller);
});
});
}
}
}).state('home.about', {
url: '/about',
template: require('./views/home.about.html'),
controller: 'HomeAboutController as vm',
});
}
export default angular
.module('home.routing', [])
.config(homeRouting);

컨트롤러는 모듈 종속성으로 처리됩니다.

// home.js
'use strict';
export default angular
.module('home', [
require('./controllers/home.controller').name,
require('./controllers/home.about.controller').name
]);

로드 컨트롤러만

우리가 하고 있는 일은 첫 번째 단계이며, 다음 단계로 넘어가겠습니다. 이번에는 큰 모듈은 없고 간소화된 컨트롤러만 있을 것입니다.

// messages.routing.js
'use strict';
function messagesRouting($stateProvider) {
$stateProvider
.state('messages', {
url: '/messages',
template: require('./views/messages.html'),
controller: 'MessagesController as vm',
resolve: {
loadMessagesController: ($q, $ocLazyLoad) => {
return $q((resolve) => {
require.ensure([], () => {
// load only controller module
let module = require('./controllers/messages.controller');
$ocLazyLoad.load({name: module.name});
resolve(module.controller);
})
});
}
}
}).state('messages.all', {
url: '/all',
template: require('./views/messages.all.html'),
controller: 'MessagesAllController as vm',
resolve: {
loadMessagesAllController: ($q, $ocLazyLoad) => {
return $q((resolve) => {
require.ensure([], () => {
// load only controller module
let module = require('./controllers/messages.all.controller');
$ocLazyLoad.load({name: module.name});
resolve(module.controller);
})
});
}
}
})

여기에는 특별한 것이 없으며 규칙은 그대로 유지될 수 있다고 생각합니다.

뷰 로드 중

이제 컨트롤러를 잠시 놓고 뷰에 집중해 보겠습니다. 눈치채셨겠지만 우리는 라우팅 구성에 뷰를 포함시켰습니다. 모든 라우팅 구성을 Bundle.js 내부에 넣지 않았다면 문제가 되지 않았지만 이제는 그렇게 해야 합니다. 이 경우는 지연 로딩 경로 구성이 아니라 뷰에 관한 것이므로 Webpack을 사용하여 구현하면 매우 간단합니다.

// messages.routing.js
...
.state('messages.new', {
url: '/new',
templateProvider: ($q) => {
return $q((resolve) => {
// lazy load the view
require.ensure([], () => resolve(require('./views/messages.new.html')));
});
},
controller: 'MessagesNewController as vm',
resolve: {
loadMessagesNewController: ($q, $ocLazyLoad) => {
return $q((resolve) => {
require.ensure([], () => {
// load only controller module
let module = require('./controllers/messages.new.controller');
$ocLazyLoad.load({name: module.name});
resolve(module.controller);
})
});
}
}
});
}
export default angular
.module('messages.routing', [])
.config(messagesRouting);

중복 종속성 주의

message.all.controller와 message.new.controller의 내용을 살펴보겠습니다.

// messages.all.controller.js
'use strict';
class MessagesAllController {
constructor(msgStore) {
this.msgs = msgStore.all();
}
}
export default angular
.module('messages.all.controller', [
require('commons/msg-store').name,
])
.controller('MessagesAllController', MessagesAllController);
// messages.all.controller.js
'use strict';
class MessagesNewController {
constructor(msgStore) {
this.text = '';
this._msgStore = msgStore;
}
create() {
this._msgStore.add(this.text);
this.text = '';
}
}
export default angular
.module('messages.new.controller', [
require('commons/msg-store').name,
])
.controller('MessagesNewController', MessagesNewController);

문제의 원인은 require('commons/msg-store').name 입니다. 컨트롤러 간 메시지 공유를 실현하려면 msgStore 서비스가 필요합니다. 이 서비스는 두 패키지 모두에 존재합니다. message.all.controller에 하나가 있고 message.new.controller에 또 하나가 있습니다. 이제 최적화할 여지가 없습니다. 어떻게 해결하나요? msgStore를 애플리케이션 모듈의 종속성으로 추가하기만 하면 됩니다. 이것이 완벽하지는 않지만 대부분의 경우 충분합니다.

// app.js
'use strict';
export default require('angular')
.module('lazyApp', [
require('angular-ui-router'),
require('oclazyload'),
// msgStore as global dependency
require('commons/msg-store').name,
require('./pages/home/home.routing').name,
require('./pages/messages/messages.routing').name,
]);

单元测试的技巧

把 msgStore 改成是全局依赖并不意味着你应该从控制器中删除它。如果你这样做了,在你编写测试的时候,如果没有模拟这一个依赖,那么它就无法正常工作了。因为在单元测试中,你只会加载这一个控制器而非整个应用模块。

// messages.all.controller.spec.js
'use strict';
describe('MessagesAllController', () => {
var controller,
msgStoreMock;
beforeEach(angular.mock.module(require('./messages.all.controller').name));
beforeEach(inject(($controller) => {
msgStoreMock = require('commons/msg-store/msg-store.service.mock');
spyOn(msgStoreMock, 'all').and.returnValue(['foo', ]);
controller = $controller('MessagesAllController', { msgStore: msgStoreMock });
}));
it('saves msgStore.all() in msgs', () => {
expect(msgStoreMock.all).toHaveBeenCalled();
expect(controller.msgs).toEqual(['foo', ]);
});
});

以上内容是小编给大家分享的Webpack 实现 AngularJS 的延迟加载,希望对大家有所帮助!

성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.