成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

[譯] 通過 Webpack 實(shí)現(xiàn) AngularJS 的延遲加載

Zhuxy / 1545人閱讀

摘要:雖然這些東西都是非常棒的,但是它們都不是實(shí)現(xiàn)延遲加載所必需的東西。我們通過的配置對(duì)象中的屬性就可以實(shí)現(xiàn)延遲加載。單元測(cè)試的技巧把改成是全局依賴并不意味著你應(yīng)該從控制器中刪除它。因?yàn)樵趩卧獪y(cè)試中,你只會(huì)加載這一個(gè)控制器而非整個(gè)應(yīng)用模塊。

原文鏈接:http://michalzalecki.com/lazy-load-angularjs-with-webpack/

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

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

代碼可以在 GitHub 上。你可以隨時(shí) fork 它。

Webpack 的配置

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

// 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;
應(yīng)用

應(yīng)用模塊是主文件,它必須被包括在 bundle.js 內(nèi),這是在每一個(gè)頁面上都需要強(qiáng)制下載的。正如你所看到的,我們不會(huì)加載任何復(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,
  ]);
路由配置

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

加載整個(gè)模塊

當(dāng)用戶輸入 /home 路徑,瀏覽器就會(huì)下載 home 模塊。它包括兩個(gè)控制器,針對(duì) homehome.about 這兩個(gè)state。我們通過 state 的配置對(duì)象中的 resolve 屬性就可以實(shí)現(xiàn)延遲加載。得益于 Webpack 的 require.ensure 方法,我們可以把 home 模塊創(chuàng)建成第一個(gè)代碼塊。它就叫做 1.bundle.js 。如果沒有 $ocLazyLoad.load,我們會(huì)發(fā)現(xiàn)得到一個(gè)錯(cuò)誤 Argument "HomeController" is not a function, got undefined,因?yàn)樵?Angular 的設(shè)計(jì)中,啟動(dòng)應(yīng)用之后再加載文件的方式是不可行的。 但是 $ocLazyLoad.load 使得我們可以在啟動(dòng)階段注冊(cè)一個(gè)模塊,然后在它加載完之后再去使用它。

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

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

// home.js
"use strict";

export default angular
  .module("home", [
    require("./controllers/home.controller").name,
    require("./controllers/home.about.controller").name
  ]);
僅加載控制器

我們所做的是向前邁出的第一步,那么我們接著進(jìn)行下一步。這一次,將沒有大的模塊,只有精簡(jiǎn)的控制器。

// 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);
            })
          });
        }
      }
    })
    ...

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

加載視圖(Views)

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

// 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);
當(dāng)心重復(fù)的依賴

讓我們來看看 messages.all.controllermessages.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 這一個(gè)服務(wù),來實(shí)現(xiàn)控制器之間的消息共享。此服務(wù)在兩個(gè)包中都存在。在 messages.all.controller 中有一個(gè),在 messages.new.controller 中又有一個(gè)。現(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 dependency
    require("commons/msg-store").name,
    require("./pages/home/home.routing").name,
    require("./pages/messages/messages.routing").name,
  ]);
單元測(cè)試的技巧

msgStore 改成是全局依賴并不意味著你應(yīng)該從控制器中刪除它。如果你這樣做了,在你編寫測(cè)試的時(shí)候,如果沒有模擬這一個(gè)依賴,那么它就無法正常工作了。因?yàn)樵趩卧獪y(cè)試中,你只會(huì)加載這一個(gè)控制器而非整個(gè)應(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", 8]);
    controller = $controller("MessagesAllController", { msgStore: msgStoreMock });
  }));

  it("saves msgStore.all() in msgs", () => {
    expect(msgStoreMock.all).toHaveBeenCalled();
    expect(controller.msgs).toEqual(["foo", 8]);
  });

});

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/78768.html

相關(guān)文章

  • webpack 教程資源收集

    學(xué)習(xí)的過程中收藏了這些優(yōu)秀教程和的項(xiàng)目,希望對(duì)你有幫助。 github地址, 有不錯(cuò)的就更新 官方文檔 中文指南 初級(jí)教程 webpack-howto 作者:Pete Hunt Webpack 入門指迷 作者:題葉   webpack-demos 作者:ruanyf 一小時(shí)包教會(huì) —— webpack 入門指南 作者:VaJoy Larn   webpack 入門及實(shí)踐 作者:...

    Backache 評(píng)論0 收藏0
  • [] 關(guān)于 Angular 動(dòng)態(tài)組件你需要知道

    摘要:第一種方式是使用模塊加載器,如果你使用加載器的話,路由在加載子路由模塊時(shí)也是用的作為模塊加載器。還需注意的是,想要使用還需像這樣去注冊(cè)它你當(dāng)然可以在里使用任何標(biāo)識(shí),不過路由模塊使用標(biāo)識(shí),所以最好也使用相同。 原文鏈接:Here is what you need to know about dynamic components in?Angular showImg(https://se...

    lcodecorex 評(píng)論0 收藏0
  • 前端面試題(3)現(xiàn)代技術(shù)

    摘要:什么是單頁面應(yīng)用單頁面應(yīng)用是指用戶在瀏覽器加載單一的頁面,后續(xù)請(qǐng)求都無需再離開此頁目標(biāo)旨在用為用戶提供了更接近本地移動(dòng)或桌面應(yīng)用程序的體驗(yàn)。流程第一次請(qǐng)求時(shí),將導(dǎo)航頁傳輸?shù)娇蛻舳?,其余?qǐng)求通過獲取數(shù)據(jù)實(shí)現(xiàn)數(shù)據(jù)的傳輸通過或遠(yuǎn)程過程調(diào)用。 什么是單頁面應(yīng)用(SPA)? 單頁面應(yīng)用(SPA)是指用戶在瀏覽器加載單一的HTML頁面,后續(xù)請(qǐng)求都無需再離開此頁 目標(biāo):旨在用為用戶提供了更接近本地...

    EasonTyler 評(píng)論0 收藏0
  • 前端面試題(3)現(xiàn)代技術(shù)

    摘要:什么是單頁面應(yīng)用單頁面應(yīng)用是指用戶在瀏覽器加載單一的頁面,后續(xù)請(qǐng)求都無需再離開此頁目標(biāo)旨在用為用戶提供了更接近本地移動(dòng)或桌面應(yīng)用程序的體驗(yàn)。流程第一次請(qǐng)求時(shí),將導(dǎo)航頁傳輸?shù)娇蛻舳?,其余?qǐng)求通過獲取數(shù)據(jù)實(shí)現(xiàn)數(shù)據(jù)的傳輸通過或遠(yuǎn)程過程調(diào)用。 什么是單頁面應(yīng)用(SPA)? 單頁面應(yīng)用(SPA)是指用戶在瀏覽器加載單一的HTML頁面,后續(xù)請(qǐng)求都無需再離開此頁 目標(biāo):旨在用為用戶提供了更接近本地...

    trigkit4 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

閱讀需要支付1元查看
<