ホームページ  >  記事  >  ウェブフロントエンド  >  Webpack は AngularJS_AngularJS の遅延読み込みを実装します

Webpack は AngularJS_AngularJS の遅延読み込みを実装します

WBOY
WBOYオリジナル
2016-05-16 15:12:221660ブラウズ

シングルページ アプリが大きくなるにつれて、ダウンロード時間も長くなります。これはユーザー エクスペリエンスにとってあまり良いことではありません (ヒント: しかし、シングル ページ アプリを開発するのはユーザー エクスペリエンスのためです)。コードが増えるとファイルが大きくなります。コード圧縮がニーズを満たさなくなるまで、ユーザーにできる唯一のことは、アプリケーション全体を一度にダウンロードするように要求するのをやめる事です。ここで遅延読み込みが役に立ちます。すべてのファイルを一度にダウンロードするのではなく、ユーザーは現在必要なファイルのみをダウンロードできます。

それで。アプリケーションを遅延読み込みするにはどうすればよいですか?それは基本的に2つのことに分かれます。モジュールを小さなチャンクに分割し、これらのチャンクをオンデマンドでロードできるようにするメカニズムを実装します。とても大変な仕事だと思いませんか? Webpack を使用している場合はそうではありません。すぐに使えるコード分割機能をサポートします。この記事では、読者が Webpack に精通していることを前提としていますが、そうでない場合は、ここで概要を説明します。簡単に説明すると、AngularUI Router と ocLazyLoad も使用します。

コードは GitHub で入手できます。いつでもフォークできます。

Webpack 構成

特に何もありません。実際には、ドキュメントからコピーして貼り付けるだけで済みます。唯一の違いは、コードをクリーンに保つために 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 を使用しています。いくつかの使用例があります。モジュール全体 (子ステート コントローラーを含む) をロードすることも、ステートごとに 1 つのコントローラー (親ステートへの依存関係に関係なく) をロードすることもできます。

モジュール全体をロードします

ユーザーが /home パスを入力すると、ブラウザはホーム モジュールをダウンロードします。これには、home と home.about の 2 つの状態に対応する 2 つのコントローラーが含まれています。状態設定オブジェクトのsolve属性を通じて遅延読み込みを実装できます。 Webpack の require.ensure メソッドのおかげで、最初のコード ブロックとしてホーム モジュールを作成できます。これは 1.bundle.js と呼ばれます。 $ocLazyLoad.load がないと、Angular の設計ではアプリケーションの起動後にファイルをロードすることが不可能なため、 Argument 'HomeController' is not a function, got unfineed というエラーが発生することがわかります。 ただし、$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);

依存関係の重複に注意してください

messages.all.controller とmessages.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 サービスが必要です。このサービスは両方のパッケージに存在します。 1 つはmessages.all.controller に、もう 1 つはmessages.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 までご連絡ください。