2014-10-09 21 views
6

Sto lavorando a un progetto con angolare e browserify, questa è la prima volta che utilizzo questi due strumenti insieme, quindi vorrei un consiglio su quale sia il modo di creare i file require con browserify .Richiedi pattern Browserify/Angular

Possiamo importare i file in modi diversi, fino ad ora ho sperimentato in questo modo:

angolare App:

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

Per ogni cartella con dei file per un plugin ho creato un file require.js e in esso richiedo tutti i file di quella cartella. In questo modo:

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

e quindi richiedere a tutti i require.js i file in un unico file denominato app.js che genereranno il bundle.js

Domanda:

Questo modo di richiedere i file possono essere una buona struttura , o avrà qualche problema quando ho bisogno di testare? Mi piacerebbe vedere il tuo modo di ottenere una buona struttura con angolazione e browserify

risposta

5

AngularJS e browserify non sono, purtroppo, una grande partita. Certamente non piace React e browserify, ma sto divagando.

Ciò che ha funzionato per me è avere ciascun file come un modulo AngularJS (poiché ogni file è già un modulo CommonJS) e con i file esportare il nome del modulo AngularJS.

Così il vostro esempio sarà simile a questa:

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

Il app.js sarebbe simile a questa:

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

Il follow/index.js sarebbe simile a questa:

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

Il follow/controllers.js sarebbe simile a questa:

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; 

E così via.

Il vantaggio di questo approccio è che si mantengono le proprie dipendenze il più esplicite possibile (cioè all'interno del modulo CommonJS che ne ha effettivamente bisogno) e la mappatura uno-a-uno tra i percorsi del modulo CommonJS ei nomi dei moduli AngularJS impedisce brutte sorprese.

Il problema più ovvio del tuo approccio è che stai mantenendo le dipendenze effettive che verranno iniettate separatamente dalla funzione che si aspetta, quindi se cambiano le dipendenze di una funzione, devi toccare due file invece di uno. Questo è un odore di codice (cioè una cosa negativa).

Per testabilità, l'approccio dovrebbe funzionare in quanto il sistema di moduli di Angular è essenzialmente un gigantesco blob e l'importazione di due moduli che entrambi definiscono lo stesso nome si sovrascriveranno.


EDIT (due anni dopo): Alcune altre persone (sia qui che altrove) hanno suggerito approcci alternativi quindi dovrei probabilmente li rivolgo e ciò che i compromessi sono:

  1. Avere uno modulo AngularJS globale per l'intera app e richiede solo effetti secondari (cioè non i sub-moduli esportano nulla ma manipolano l'oggetto angolare globale).

    Questa sembra essere la soluzione più comune ma il tipo di mosche di fronte ai moduli. Questo sembra essere l'approccio più pragmatico e se stai usando AngularJS stai già inquinando i globals quindi suppongo che avere solo moduli basati sugli effetti collaterali sia l'ultimo dei tuoi problemi architettonici.

  2. Concatenare il codice dell'app AngularJS prima del passandolo a Browserify.

    Questa è la soluzione più letterale per "combinare AngularJS e Browserify". È un approccio valido se stai partendo dalla tradizionale posizione "just beffly concatenate i tuoi file app" di AngularJS e vuoi aggiungere Browserify per le librerie di terze parti, quindi suppongo che lo renda valido.

    Per quanto riguarda la struttura dell'app, questo non migliora nulla aggiungendo Browserify.

  3. Come 1 ma con ogni index.js che definisce il proprio sottomodulo AngularJS.

    Questo è l'approccio standard proposto da Brian Ogden. Questo soffre di tutti gli inconvenienti di 1 ma crea una parvenza di gerarchia all'interno di AngularJS in quanto almeno hai più di un modulo AngularJS e i nomi dei moduli AngularJS corrispondono effettivamente alla tua struttura di directory.

    Tuttavia, il principale svantaggio è che ora ci si deve preoccupare di due gruppi di spazi dei nomi (i moduli effettivi e i moduli AngularJS), ma nulla impone la coerenza tra di essi. Non solo devi ricordarti di importare i moduli giusti (che di nuovo si basano esclusivamente sugli effetti collaterali) ma devi anche ricordarti di aggiungerli a tutte le liste giuste e aggiungere lo stesso numero di riferimento ad ogni nuovo file. Questo rende il refactoring incredibilmente ingombrante e rende questa la peggiore opzione a mio avviso.

Se dovessi scegliere oggi, vorrei andare con 2 perché dà su ogni pretesa di AngularJS e Browserify essere in grado di essere unificati e lascia solo sia per fare quello che vogliono. Inoltre, se hai già un sistema di build AngularJS, significa letteralmente aggiungere un ulteriore passaggio per Browserify.

Se non si eredita una base di codice AngularJS e si desidera sapere quale approccio è più efficace per avviare un nuovo progetto: non avviare un nuovo progetto in AngularJS. Scegli Angular2 che supporta un vero modulo di sistema, o passa a React o Ember che non soffrono di questo problema.

+0

Questo funziona perfettamente - grazie per passare attraverso il tempo di fare questo. Sono riuscito a fare qualcosa di molto simile con require.js e mi hai aiutato a passare da quella follia di AMD: D – marksyzm

+0

@AlanPlum wow non mi stupisco che non ti piace come Browserify si mescola con Angular. Questo è un codice pazzo, non un buon modello. non c'è bisogno di module.exports né di inserimento nelle istanze dei moduli angolari ... verificate questo aspetto per un modello migliore usando AngularJS e browserify https: // github.com/Sweetog/yet-another-angular-boilerplate –

+0

Una volta che li aggiungi agli elenchi giusti, non devi mai ricordarti di aggiungerli di nuovo, e il boilerplate non è in ogni file, solo i moduli e un index.js per directory come ogni directory è un modulo angolare –

0

Stavo cercando di usare browserify con Angular ma ho trovato un po 'confuso. Non mi piaceva lo schema di creazione di un servizio/controller nominato che lo richiedesse da un'altra posizione, ad es.

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

Il nome del controller/definizione è in un unico file, ma la funzione stessa è in un altro.Anche avere molti file index.js rende davvero confuso se molti file si aprono in un IDE.

così ho messo insieme questo plugin gulp, gulp-require-angular che consente di scrivere angolare utilizzando la sintassi angolare normale tutte js file che contengono i moduli angolari e le dipendenze di moduli angolari che appaiono nel vostro albero principale dipendenze dei moduli sono require() 'D in un generato file di immissione, che verrà quindi utilizzato come file di immissione di browser.

È ancora possibile utilizzare require() nella base di codice per inserire librerie esterne (ad esempio lodash) in servizi/filtri/direttive, se necessario.

Here's the latest Angular seed forked and updated per utilizzare gulp-require-angular.

+0

Ti ho votato, perché hai fatto un buon lavoro con quel plugin (non l'ho provato ma sembra buono) ma rimarrei con browserify . – Fabrizio

0

Ho utilizzato un approccio ibrido simile a pluma. Ho creato NG-moduli in questo modo:

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 

Penso che la differenza è che io non definisco singoli ng-moduli come dipendenze alla principale ng-modulo, in questo caso non vorrei definire un servizio come un modulo ng e quindi elencarlo come dep del modulo ng app.core. Cerco di mantenerlo il più piatto possibile:

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

Per quanto riguarda il commento di odore di codice, non sono d'accordo. Mentre è un passo in più, consente una grande configurabilità in termini di test contro i servizi di simulazione. Per esempio io uso questo un bel po 'per testare i servizi agains che potrebbero non disporre di un server-API esistente pronto:

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

Quindi qualsiasi controller o di un oggetto dipende srvc non sa che si sta facendo. Ho potuto vedere questo un po 'complicato in termini di servizi che dipendono da altri servizi, ma che per me è un cattivo design. Preferisco usare il sistema di eventi di ng per comunicare tra loro. servizi in modo da mantenere basso il loro accoppiamento.

0

La risposta di Alan Plum non è una buona risposta o almeno non una grande dimostrazione di moduli CommonJS e Browserify con Angular. L'affermazione che Browserify non si combina bene con Angular, rispetto a React, non è vera.

Browserify e un modello di modulo CommonJS funzionano perfettamente con Angular, che consente di organizzarsi in base alle funzionalità anziché ai tipi, mantenere le vars fuori dall'ambito globale e condividere facilmente i moduli angolari tra le app. Per non parlare del fatto che non è necessario aggiungere mai più un singolo <script> al codice HTML grazie a Browserify che trova tutte le tue dipendenze.

Ciò che è particolarmente difettoso nella risposta di Alan Plum non è lasciare che sia necessario in ogni index.js per ogni cartella dettare dipendenze per moduli angolari, controller, servizi, configurazioni, percorsi, ecc. Non è necessario un singolo requisito nell'angolare .modulo di istanza, né un singolo modulo.esporta come nel contesto suggerito dalla risposta di Alan Plum.

Vedi qui per un migliore modello di modulo per la Angular utilizzando Browserify: https://github.com/Sweetog/yet-another-angular-boilerplate

+0

Ho cancellato i miei commenti a favore di una modifica alla mia risposta per indirizzare il tuo suggerimento (e altri fatti altrove). –