Webpack - AngularJS 로드 지연

9129 단어
당신의 단일 앱이 확대됨에 따라 다운로드 시간도 갈수록 길어진다.이것은 사용자 체험을 향상시키는 데 이롭지 않을 것이다(힌트: 그러나 사용자 체험이 바로 우리가 단일 페이지 응용을 개발한 이유이다).더 많은 코드는 더 큰 파일을 의미한다. 코드가 압축될 때까지 당신의 요구를 충족시키지 못할 때까지, 사용자를 위해 할 수 있는 유일한 일은 더 이상 그로 하여금 전체 응용 프로그램을 한꺼번에 다운로드하지 못하게 하는 것이다.이때 적재 지연이 도움이 된다.모든 파일을 한꺼번에 다운로드하는 것과는 달리 현재 필요한 파일만 다운로드하게 한다.
그래서어떻게 당신의 응용 프로그램이 불러오는 지연을 실현합니까?그것은 기본적으로 두 가지 일로 나뉜다.너의 모듈을 작은 블록으로 나누고, 필요에 따라 이 블록을 불러올 수 있는 메커니즘을 실시해라.듣자니 작업량이 많은 것 같지 않습니까?만약 네가 Webpack을 사용한다면 이렇게 되지 않을 것이다.그것은 상자를 열기 위한 코드 분할 기능을 지원한다.이 문장에서 나는 네가 Webpack에 익숙하다고 가정하지만, 만약 네가 할 수 없다면, 여기에 소개가 한 편 있다.긴 이야기를 위해 AngularUI Router 및 ocLazy Load도 사용할 예정입니다.
코드는 GitHub에서 사용할 수 있습니다.너는 언제든지 그것을 포크할 수 있다.
Webpack 구성
별거 아니야, 정말.실제로 문서에서 직접 복사해서 붙일 수 있다. 유일한 차이점은 ng-annotate를 사용해서 우리의 코드를 간결하게 유지하고 Babel을 사용해서 ECMAScript 2015의 마법적 특성을 사용하는 것이다.만약 당신이 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;

응용 프로그램
응용 모듈은 주 파일입니다. 버블에 포함되어야 합니다.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를 사용하고 있습니다. 왜냐하면 우리는 끼워 넣는 보기를 실현해야 하기 때문입니다.우리는 몇 가지 사용 사례가 있다.모든 모듈 (하위 상태 컨트롤러 포함) 을 불러오거나, 모든state에 컨트롤러를 불러올 수 있습니다. (부모state에 대한 의존을 고려하지 않습니다.)
전체 모듈 로드
사용자가/home 경로를 입력하면 브라우저에서 홈 모듈을 다운로드합니다.그것은 홈과 홈을 겨냥한 두 개의 컨트롤러를 포함한다.about, 이 두 state.state의 설정 대상 중의resolve 속성을 통해 로드 지연을 실현할 수 있습니다.Webpack의 Require 덕분이에요.ensure 방법, 우리는 홈 모듈을 첫 번째 코드 블록으로 만들 수 있습니다.얘는 1이라고 해요.bundle.js .$ocLazyLoad가 없으면Argument'Home Controller'is not a function,got undefined 오류를 발견할 수 있습니다. 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);
})
});
}
}
})

나는 이곳에서 특별한 것이 없다고 믿는다. 규칙은 변하지 않을 수 있다.
뷰 로드(Views)
이제 잠시 컨트롤러를 놓고 보기를 살펴보자.보시다시피, 우리는 보기를 루트 설정에 끼워 넣었습니다.만약 우리가 안에 있는 모든 루트 설정을 버블에 넣지 않았다면.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);

중복된 의존에 주의하다
메시지 좀 봅시다.all.controller와 메시지.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);

우리의 문제의 근원은 리퀴어('commons/msg-store')다.name .그것은 컨트롤러 간의 메시지 공유를 실현하기 위해 msgStore라는 서비스가 필요하다.이 서비스는 두 가방에 모두 존재합니다.메시지all.controller 중 하나가 메시지에 있습니다.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', ]);
});
});

위와 같은 내용은 편집자가 공유한 웹팩으로 AngularJS의 딜레이 로드를 실현하였습니다. 여러분께 도움이 되었으면 좋겠습니다!

좋은 웹페이지 즐겨찾기