国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 編程 > JavaScript > 正文

Webpack 實現(xiàn) AngularJS 的延遲加載

2019-11-20 10:27:26
字體:
供稿:網(wǎng)友

隨著你的單頁應(yīng)用擴大,其下載時間也越來越長。這對提高用戶體驗不會有好處(提示:但用戶體驗正是我們開發(fā)單頁應(yīng)用的原因)。更多的代碼意味著更大的文件,直到代碼壓縮已經(jīng)不能滿足你的需求,你唯一能為你的用戶做的就是不要再讓他一次性下載整個應(yīng)用。這時,延遲加載就派上用場了。不同于一次性下載所有文件,而是讓用戶只下載他現(xiàn)在需要的文件。

所以。如何讓你的應(yīng)用程序?qū)崿F(xiàn)延遲加載?它基本上是分成兩件事情。把你的模塊拆分成小塊,并實施一些機制,允許按需加載這些塊。聽起來似乎有很多工作量,不是嗎?如果你使用 Webpack 的話,就不會這樣。它支持開箱即用的代碼分割特性。在這篇文章中我假定你熟悉 Webpack,但如果你不會的話,這里有一篇介紹 。為了長話短說,我們也將使用 AngularUI Router 和 ocLazyLoad 。

代碼可以在 GitHub 上。你可以隨時 fork 它。

Webpack 的配置

沒什么特別的,真的。實際上從你可以直接從文檔中復(fù)制然后粘貼,唯一的區(qū)別是采用了 ng-annotate ,以讓我們的代碼保持簡潔,以及采用 babel 來使用一些 ECMAScript 2015 的魔法特性。如果你對 ES6 感興趣,可以看看 這篇以前的帖子 。雖然這些東西都是非常棒的,但是它們都不是實現(xiàn)延遲加載所必需的東西。

// webpack.config.jsvar 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;

應(yīng)用

應(yīng)用模塊是主文件,它必須被包括在 bundle.js 內(nèi),這是在每一個頁面上都需要強制下載的。正如你所看到的,我們不會加載任何復(fù)雜的東西,除了全局的依賴。不同于加載控制器,我們只加載路由配置。

// 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,]);

路由配置

所有的延遲加載都在路由配置中實現(xiàn)。正如我所說,我們正在使用 AngularUI Router ,因為我們需要實現(xiàn)嵌套視圖。我們有幾個使用案例。我們可以加載整個模塊(包括子狀態(tài)控制器)或每個 state 加載一個控制器(不去考慮對父級 state 的依賴)。

加載整個模塊

當(dāng)用戶輸入 /home 路徑,瀏覽器就會下載 home 模塊。它包括兩個控制器,針對 home 和 home.about 這兩個state。我們通過 state 的配置對象中的 resolve 屬性就可以實現(xiàn)延遲加載。得益于 Webpack 的 require.ensure 方法,我們可以把 home 模塊創(chuàng)建成第一個代碼塊。它就叫做 1.bundle.js 。如果沒有 $ocLazyLoad.load ,我們會發(fā)現(xiàn)得到一個錯誤 Argument 'HomeController' is not a function, got undefined ,因為在 Angular 的設(shè)計中,啟動應(yīng)用之后再加載文件的方式是不可行的。 但是 $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 modulelet 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);

控制器被當(dāng)作是模塊的依賴。

// 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 modulelet 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 modulelet module = require('./controllers/messages.all.controller');$ocLazyLoad.load({name: module.name});resolve(module.controller);})});}}})

我相信在這里沒有什么特別的,規(guī)則可以保持不變。

加載視圖(Views)

現(xiàn)在,讓我們暫時放開控制器而去關(guān)注一下視圖。正如你可能已經(jīng)注意到的,我們把視圖嵌入到了路由配置里面。如果我們沒有把里面所有的路由配置放進 bundle.js ,這就不會是一個問題,但現(xiàn)在我們需要這么做。這個案例不是要延遲加載路由配置而是視圖,那么當(dāng)我們使用 Webpack 來實現(xiàn)的時候,這會非常簡單。

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

當(dāng)心重復(fù)的依賴

讓我們來看看 messages.all.controller 和 messages.new.controller 的內(nèi)容。

// 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 這一個服務(wù),來實現(xiàn)控制器之間的消息共享。此服務(wù)在兩個包中都存在。在 messages.all.controller 中有一個,在 messages.new.controller 中又有一個。現(xiàn)在,它已經(jīng)沒有任何優(yōu)化的空間。如何解決呢?只需要把 msgStore 添加為應(yīng)用模塊的依賴。雖然這還不夠完美,在大多數(shù)情況下,這已經(jīng)足夠了。

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

單元測試的技巧

把 msgStore 改成是全局依賴并不意味著你應(yīng)該從控制器中刪除它。如果你這樣做了,在你編寫測試的時候,如果沒有模擬這一個依賴,那么它就無法正常工作了。因為在單元測試中,你只會加載這一個控制器而非整個應(yīng)用模塊。

// 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', ]);});});

以上內(nèi)容是小編給大家分享的Webpack 實現(xiàn) AngularJS 的延遲加載,希望對大家有所幫助!

發(fā)表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發(fā)表
主站蜘蛛池模板: 永嘉县| 洛扎县| 肃宁县| 马鞍山市| 兴安县| 阿巴嘎旗| 郓城县| 子长县| 汝城县| 江孜县| 雷山县| 镇沅| 土默特右旗| 南通市| 洪雅县| 乾安县| 玉溪市| 天门市| 渭南市| 石城县| 辽中县| 晴隆县| 栾川县| 囊谦县| 青阳县| 青龙| 辉南县| 龙江县| 府谷县| 沈阳市| 封丘县| 彭阳县| 陆良县| 衡东县| 甘孜县| 平谷区| 南昌县| 隆安县| 墨脱县| 绩溪县| 玉屏|