2014-10-09 68 views
6

我正在使用angular和browserify進行項目工作,這是我第一次將這兩個工具結合使用,所以我想請教一些關於require文件與browserify 。需要圖案Browserify/Angular

我們可以導入不同的方式對這些文件,到現在爲止我嘗試這樣:

角應用:

app 
    _follow 
    - followController.js 
    - followDirective.js 
    - followService.js 
    - require.js 
- app.js 

對於每個文件夾在我創建了一個require.js文件插件的文件和在其中我需要該文件夾的所有文件。像這樣:

var mnm = require('angular').module('mnm'); 

mnm.factory('FollowService', ['Restangular',require('./followService')]); 
mnm.controller('FollowController',['$scope','FollowService',require('./followController')]) 
mnm.directive('mnmFollowers', ['FollowService',require('./followDirective')]); 

,然後要求在名爲app.js獨特的文件中的所有require.js文件將產生bundle.js

問:

這樣要求的文件可以是一個很好的結構,或者當我需要測試時會遇到一些問題?我想看看你的方式來實現良好的結構與角度和browserify

回答

5

AngularJS和browserify不是,可悲的是,一個偉大的比賽。當然不喜歡React和browserify,但我離題了。

對我而言,每個文件都是作爲AngularJS模塊(因爲每個文件已經是CommonJS模塊),並讓這些文件導出他們的AngularJS模塊名稱。

所以,你的例子是這樣的:

app/ 
    app.js 
    follow/ 
    controllers.js 
    directives.js 
    services.js 
    index.js 

app.js會是這個樣子:

var angular = require('angular'); 
var app = angular.module('mnm', [ 
    require('./follow') 
]); 
// more code here 
angular.bootstrap(document.body, ['mnm']); 

follow/index.js會是這個樣子:

var angular = require('angular'); 
var app = angular.module('mnm.follow', [ 
    require('./controllers'), 
    require('./directives'), 
    require('./services') 
]); 
module.exports = app.name; 

follow/controllers.js看起來像這樣:

var angular = require('angular'); 
var app = angular.module('mnm.follow.controllers', [ 
    require('./services'), // internal dependency 
    'ui.router' // external dependency from earlier require or <script/> 
    // more dependencies ... 
]); 
app.controller('FollowController', ['$scope', 'FollowService', function ...]); 
// more code here 
module.exports = app.name; 

依此類推。

這種方法的優點是可以儘可能保持您的依賴性(即在實際需要它們的CommonJS模塊內),並且CommonJS模塊路徑和AngularJS模塊名稱之間的一對一映射可防止令人討厭的意外。

您的方法最明顯的問題是,您將保持注入的實際依賴關係與期望它們的函數分開,因此如果函數的依賴關係發生更改,則必須觸及兩個文件而不是一個文件。這是一種代碼味道(即壞事)。

對於可測試性,任何一種方法都應該像Angular的模塊系統一樣是一個巨大的blob,並且導入兩個定義相同名稱的模塊將相互覆蓋。


EDIT(兩年後):其他一些人(在這裏和其他地方)建議的替代方法,所以我也許應該解決這些問題,什麼權衡取捨:

  1. 有一個全局AngularJS模塊爲你的整個應用程序,只是做副作用需要(即沒有子模塊導出任何東西,但操縱全局角對象)。

    這似乎是最常見的解決方案,但有種蒼蠅在面對有模塊。這似乎是最實用的方法,但是如果你使用的是AngularJS,那麼你已經對全局造成了污染,所以我猜測純粹以副作用爲基礎的模塊是你的體系結構問題中最少的。

  2. 在之前將您的AngularJS應用代碼連接到Browserify。

    這是「讓我們結合AngularJS和Browserify」的最直接的解決方案。如果你從傳統的「只是盲目地連接你的應用程序文件」的位置開始,並且希望爲第三方庫添加Browserify,那麼這是一個有效的方法,所以我想這是有效的。

    就你的應用結構而言,儘管增加了Browserify,但這並不能真正改善任何事情。

  3. 與1一樣,但每個index.js都定義了自己的AngularJS子模塊。

    這是Brian Ogden建議的樣板方法。這受到1的所有缺點,但在AngularJS中創建了一些類似的層次結構,至少你有多個AngularJS模塊,並且AngularJS模塊名稱實際上與你的目錄結構相對應。

    但是,主要的缺點是您現在有兩組名稱空間來擔心(您的實際模塊和您的AngularJS模塊),但沒有強化它們之間的一致性。您不僅需要記住導入正確的模塊(這又是純粹依賴副作用),但您還必須記住將它們添加到所有正確的列表中,並將相同的樣板添加到每個新文件。這使得重構變得難以置信,這使得我認爲這是最糟糕的選擇。

如果我今天不得不選擇,我會去2,因爲它給了AngularJS和Browserify能夠統一所有的僞裝,只是留下既做自己的事情。此外,如果您已經擁有一個AngularJS構建系統,它實際上意味着爲Browserify添加額外步驟。

如果您沒有繼承AngularJS代碼庫,並想知道哪種方法最適合啓動新項目:請勿在AngularJS中啓動新項目。選擇支持真實模塊系統的Angular2,或切換到不受此問題影響的React或Ember。

+0

這工作完全 - 感謝經歷的時間,使這一點。我設法做了一些非常類似於require.js的事情,並且幫助我從AMD的瘋狂中走出來:D – marksyzm 2015-02-06 00:07:51

+0

@AlanPlum哇,難怪你不喜歡Browserify如何與Angular混合。這是一些瘋狂的代碼,不是一個好的模式。不需要module.exports,也不需要在角度模塊實例化中...使用AngularJS和browserify https:// github查看更好的模式。com/Sweetog /另一種角度樣板 – 2016-08-22 07:13:23

+0

一旦你將它們添加到正確的列表中,你不必記得再次添加它們,樣板不是每個文件,只是模塊和index.js每個目錄,因爲每個目錄都是一個Angular模塊 – 2016-08-22 17:36:03

0

我正在嘗試使用與Angular的browserify,但發現它有點混亂。我不喜歡創建命名服務/控制器的模式,然後從其他位置請求它,例如,

angular.module('myApp').controller('charts', require('./charts')); 

控制器名稱/定義在一個文件中,但函數本身在另一個文件中。如果您在IDE中打開大量文件,還會有大量的index.js文件,這讓您感到非常困惑。

所以我整理了這篇一飲而盡插件,gulp-require-angular它允許您使用標準的角語法寫的角度,所有的JS包含角模塊是require()它出現在你的主模塊的依賴關係樹倒是成生成角模塊的依賴關係文件條目文件,然後將其用作您的browserify條目文件。

你仍然可以使用require()你的代碼庫中的外部庫拉(例如lodash)到服務/過濾器/指令的需要。

Here's the latest Angular seed forked and updated使用gulp-require-angular

+0

我投票給你,因爲你做了一個很好的工作與該插件(我沒有嘗試,但看起來不錯),但我會留在browserify 。 – Fabrizio 2014-10-30 13:49:34

0

我使用一種混合的方法很像pluma。我創建了NG-模塊,像這樣:

var name = 'app.core' 

angular.module(name, []) 
.service('srvc', ['$rootScope', '$http', require('./path/to/srvc')) 
.service('srvc2', ['$rootScope', '$http', require('./path/to/srvc2')) 
.config... 
.etc 

module.exports = name 

我覺得不同的是,我沒有定義個人NG模塊作爲依賴於主NG模塊,在這種情況下,我不會定義一個服務爲ng模塊,然後將其列爲ng模塊的dep。我儘量保持它儘可能平坦:

//srvc.js - see below 
module.exports = function($rootScope, $http) 
{ 
    var api = {}; 
    api.getAppData = function(){ ... } 
    api.doSomething = function(){ ... } 
    return api; 
} 

關於代碼氣味的評論,我不同意。雖然這是一個額外的步驟,但它在針對模擬服務的測試方面提供了很好的可配置性。比如我用這個頗有幾分測試agains服務,可能沒有一個現有的服務器API準備:

angular.module(name, []) 
// .service('srvc', ['$rootScope', '$http', require('./path/to/srvc')) 
    .service('srvc', ['$rootScope', '$http', require('./path/to/mockSrvc')) 

因此,任何控制器或對象依賴srvc不知道哪個是越來越。我可以看到這在服務依賴於其他服務方面變得有些複雜,但對我而言這是糟糕的設計。我更喜歡使用ng的事件系統來進行通信。服務,以便您保持聯繫。

0

艾倫·梅的回答是不是個很棒的答案,或者至少不是CommonJS的模塊和Browserify有角有很大的示範。與React相比,Browserify與Angular不能很好地融合的說法並不正確。

Browserify和CommonJS的模塊模式的工作原理偉大的角度,讓您的功能,而不是類型的組織,保持瓦爾了全球範圍內的地共享跨應用角度模塊。更何況,您不需要再次向您的HTML添加一個<script>,這要歸功於Browserify查找所有依賴關係。

Alan Plum的答案中有什麼特別的缺陷是不允許在每個index.js中爲每個文件夾指定Angular模塊,控制器,服務,配置,路由等的依賴關係。在Angular中不需要單個需求.module實例化,也不是單個模塊。在Alan Plum的答案中提到的上下文中引用。

在這裏看到一個更好的模塊模式的角度使用Browserify:https://github.com/Sweetog/yet-another-angular-boilerplate

+0

我刪除了我的意見,贊成編輯我的答案以解決您的建議(以及其他地方提出的問題)。 – 2016-08-22 08:33:38