Require pattern Browserify / Angular - javascript

I'm working in a project with angular and browserify, this is the first time for me to use this two tools together, so I would like some advice on which is the way to require files with browserify.
We may import those files in different ways, Until now I experimented this way:
Angular App:
app
_follow
- followController.js
- followDirective.js
- followService.js
- require.js
- app.js
For each folder with in the files for a plugin I created an require.js file and in it I require all the files of that folder. Like so:
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')]);
and then require all require.js files in a unique file called app.js that will generate the bundle.js
Question:
This way to require the files can be a good structure, or it will have some problem when I need to test? I would like to see your way to achieve good structure with angular and browserify

AngularJS and browserify aren't, sadly, a great match. Certainly not like React and browserify, but I digress.
What has worked for me is having each file as an AngularJS module (because each file is already a CommonJS module) and having the files export their AngularJS module name.
So your example would look like this:
app/
app.js
follow/
controllers.js
directives.js
services.js
index.js
The app.js would look something like this:
var angular = require('angular');
var app = angular.module('mnm', [
require('./follow')
]);
// more code here
angular.bootstrap(document.body, ['mnm']);
The follow/index.js would look something like this:
var angular = require('angular');
var app = angular.module('mnm.follow', [
require('./controllers'),
require('./directives'),
require('./services')
]);
module.exports = app.name;
The follow/controllers.js would look something like this:
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;
And so on.
The advantage of this approach is that you keep your dependencies as explicit as possible (i.e. inside the CommonJS module that actually needs them) and the one-to-one mapping between CommonJS module paths and AngularJS module names prevents nasty surprises.
The most obvious problem with your approach is that you're keeping the actual dependencies that will be injected separate from the function that expects them, so if a function's dependencies change, you have to touch two files instead of one. This is a code smell (i.e. a bad thing).
For testability either approach should work as Angular's module system is essentially a giant blob and importing two modules that both define the same name will override each other.
EDIT (two years later): Some other people (both here and elsewhere) have suggested alternative approaches so I should probably address them and what the trade-offs are:
Have one global AngularJS module for your entire app and just do requires for side-effects (i.e. don't have the sub-modules export anything but manipulate the global angular object).
This seems to be the most common solution but kind of flies in the face of having modules at all. This seems to be the most pragmatic approach however and if you're using AngularJS you're already polluting globals so I guess having purely side-effect based modules is the least of your architectural problems.
Concatenate your AngularJS app code before passing it to Browserify.
This is the most literal solution to "let's combine AngularJS and Browserify". It's a valid approach if you're starting from the traditional "just blindly concatenate your app files" position of AngularJS and want to add Browserify for third-party libs, so I guess that makes it valid.
As far as your app structure goes this doesn't really improve anything by adding Browserify, though.
Like 1 but with each index.js defining its own AngularJS sub-module.
This is the boilerplate approach suggested by Brian Ogden. This suffers from all the drawbacks of 1 but creates some semblance of hierarchy within AngularJS in that at least you have more than one AngularJS module and the AngularJS module names actually correspond to your directory structure.
However the major drawback is that you now have two sets of namespaces to worry about (your actual modules and your AngularJS modules) but nothing enforcing consistency between them. Not only do you have to remember to import the right modules (which again purely rely on side-effects) but you also have to remember to add them to all the right lists and add the same boilerplate to every new file. This makes refactoring incredibly unwieldy and makes this the worst option in my opinion.
If I had to chose today, I would go with 2 because it gives up all pretense of AngularJS and Browserify being able to be unified and just leaves both to do their own thing. Plus if you already have an AngularJS build system it literally just means adding an extra step for Browserify.
If you're not inheriting an AngularJS code base and want to know which approach works best for starting a new project instead: don't start a new project in AngularJS. Either pick Angular2 which supports a real module system out of the box, or switch to React or Ember which don't suffer from this problem.

I was trying to use browserify with Angular but found it got a bit messy. I didn't like the pattern of creating a named service / controller then requiring it from another location, e.g.
angular.module('myApp').controller('charts', require('./charts'));
The controller name / definition is in one file, but the function itself is in another. Also having lots of index.js files makes it really confusing if you lots of files open in an IDE.
So I put together this gulp plugin, gulp-require-angular which allows you write Angular using standard Angular syntax, all js files which contain angular modules and dependencies of angular modules which appear in your main module dependency tree are require()'d into a generated entry file, which you then use as your browserify entry file.
You can still use require() within your code base to pull in external libraries (e.g lodash) into services / filters / directives as needed.
Here's the latest Angular seed forked and updated to use gulp-require-angular.

I've used a hybrid approach much like pluma. I created ng-modules like so:
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
I think the difference is that I don't define individual ng-modules as dependencies to the main ng-module, in this case I wouldn't define a Service as an ng-module and then list it as a dep of the app.core ng-module. I try to keep it as flat as possible:
//srvc.js - see below
module.exports = function( $rootScope, $http )
{
var api = {};
api.getAppData = function(){ ... }
api.doSomething = function(){ ... }
return api;
}
Regarding the comment of code-smell, I disagree. While it's an extra step, it allows for some great configurability in terms of testing against mock-services. For instance I use this quite a bit for testing agains services that might not have an existing server-API ready:
angular.module(name, [])
// .service('srvc', ['$rootScope', '$http', require( './path/to/srvc' ))
.service('srvc', ['$rootScope', '$http', require( './path/to/mockSrvc' ))
So any controller or object dependent on srvc doesn't know which it is getting. I could see this getting a bit convoluted in terms of services being dependent on other services, but that to me is bad design. I prefer to use ng's event system to communicate betw. services so that you keep their coupling down.

Alan Plum's answer is just not a great answer or at least not a great demonstration of CommonJS modules and Browserify with Angular. The claim that Browserify does not mix well with Angular, compared to React is just not true.
Browserify and a CommonJS module pattern work great with Angular, allowing you to organize by features instead of types, keep vars out of global scope and share Angular Modules across apps easily. Not to mention you do not need to ever add a single <script> to your HTML ever again thanks to Browserify finding all your dependencies.
What is particular flawed in Alan Plum's answer is not letting requires in each index.js for each folder dictate dependencies for Angular modules, controllers, services, configurations, routes etc. There is no need for a single require in the Angular.module instantiation, nor a single module.exports as in the context that Alan Plum's answer suggests.
See here for a better module pattern for Angular using Browserify: https://github.com/Sweetog/yet-another-angular-boilerplate

Related

Using a node module in my Angularjs app

I have come across a few modules i would like to use in my Angular app but am at a crossroads on how to make work in my angular app as i will need to "require()" in my factory file.
Heres the node module im interested in: https://github.com/TimNZ/node-xero
On this current project i am using Gulp Angular in Yeoman to generate my boilerplate and am having a hard time figuring out how i should make this work if i need to modify any of the gulp scrips.
I was thinking i can just "Browserify" the single file that will use require() but is this the wrong approach? should i just browserify all the project files? is this standard practice?
Any advice is appreciated, currently has me at a stand still.
All the modules i want to use in relation to Xero all seem to be node modules.
The simplest starting point would be to use Browserify to build a standalone bundle that uses a global of your choice.
To do this, you could create a JS file that requires the node module(s) you want to use. You could create a file named bundle-index.js with this content:
exports.xero = require('node-xero');
You could then run this command to build a standalone module:
browserify --standalone the_global bundle-index.js > bundle.js
Where the_global is a name you find appropriate for the global object that will contain the exports. With the bundle.js file included in a script element, you would be able use it like this:
var privateApp = new window.the_global.xero.PrivateApplication({ ... });
Doing things this way would involve the least amount of disruption to your current project. And if you are only needing to use Browserify to require third party libraries that don't change frequently, you could start with a simple manual process for building the standalone bundle.
Note that you can export other required modules by adding additional exports to bundle.js:
exports.xero = require('node-xero');
exports.someOtherModule = require('some-other-module');
(function(){
var xero = require('node-xero');
angular
.module('app')
.factory('myFactory', myFactory);
function myFactory(){
var helper = {
myMethod: myMethod,
};
return helper;
function myMethod(){
xero.doStuff();
}
}
})();

Naming convention for angular module dependencies

I just started learning AngularJS and got chance to look different angular examples. I have a question regarding angular.module dependencies. How can we know the name of dependencies to be used and from where (or which directory) angular inject those dependencies ?
for example
var clientApp = angular.module('clientApp', ['ui.bootstrap', 'hljs', 'common', 'smart-table',
'bootstrap.fileField', 'toaster', 'ngAnimate', 'angulartics', 'angulartics.google.analytics']);
in the above clientApp they have used nine dependencies. I am confused on the names used for injecting those dependencies like ui.bootstrap,hljs etc. Is there any standard convention for those names ? Also how angular fetch the required modules from lib folder ? This is my directory structure
+---js
¦ appctrl.js
+---lib
+---components
+---angular
¦ angular.js
¦ angular.min.js
+---angular-animate
¦ angular-animate.js
¦ angular-animate.min.js
+---angular-bootstrap
¦ ui-bootstrap-tpls.js
¦ ui-bootstrap-tpls.min.js
¦ ui-bootstrap.js
¦ ui-bootstrap.min.js
The clientApp will get all the modules without fail. I wonder how it can access these directory without specifying.
The injection of module dependencies depends on your code. Either one or more dependencies are injected based on the need of a code. If you are redirecting between pages using angular 'ngRoute' will be injected. If you are injecting 'ngRoute', you must specify "angular-route.js" in the script header. Another example is ngAnimate. This is used when an animation is required. This shall be used when a menu appears or disappears to make the transition smooth. The angular-animate.js should be added.
The ui-bootstrap is list of bootstrap components developed in angular. If you intend to use any of the directives in the following URL, you will inject the ui-bootstrap. https://angular-ui.github.io/bootstrap/
Toaster is a third part library. The another common one is gridster.
There are hundreds modules that can be injected into angular modules. Do inject only the modules that are used in the code as explained above. You must add related js files to your HTML script section. If you do not add the js script, angular code will not understand the injection.
Do let me know if you expect more details
The dependencies you are injecting to the module are named the same way your clientApp angular module is, because they are also angular modules.
So in your case, I could require your app by passing 'clientApp' into my module's dependency array.
As for the file fragments clientApp needs to require, it depends on how you build your app. You can wrap all of your JS in Immediately Invoked Function Expressions AKA IIFEs like such:
(angular.module(function () {}))()
Then you just have to include each script separately in your index.html the way you would any javascript file. Their names are declared roughly in the same way as the module. Ex:
.service('sampleSvc', ['$window', 'modalSvc', function($window, modalSvc){})])
When your IIFEs are executed, these functions are registered on your app module and can then be called by name. In this case, sampleSvc.
Or you can dive into the world of build tools... Personally, I like NPM to do everything and wrote all my own shell commands for each part of the build cycle. I prefer browserify in conjunction with that. However for someone just getting started, you might want to check out grunt and gulp. (Controversial opinion time: Gulp is faster)
Also: +1 to the recommendation to study John Papa's Angular Styleguide. If I'm not mistaken it was endorsed by the angular team. Also check out his ng-demos for more robust examples.

maintainable way of injecting dependencies in angularjs

I am wondering how can I inject dependencies in more readable way in angular. I am more interested in AMD(requirejs) way. Like following:
define(function (require) {
var ModuleOne = require("ModuleOne"),
ModuleTwo = require("ModuleTwo");
var ThisModule = (function () {
// code here
})();
return ThisModule;
});
Is it possible to inject dependencies above way in angularjs or is there any better way to do it then current way in angularjs?
From the Angular JS official website
Angular modules solve the problem of removing global state from the
application and provide a way of configuring the injector. As opposed
to AMD or require.js modules, Angular modules don't try to solve the
problem of script load ordering or lazy script fetching. These goals
are orthogonal and both module systems can live side by side and
fulfil their goals.
Hence, purpose of both the libraries(RequireJS and AngularJS) is totally different. The dependency injection system built into AngularJS deals with the objects needed in a component; while dependency management in RequireJS deals with the modules or, JavaScript files.
In requireJS, Objects of loaded modules are cached and they are served when same modules are requested again. On the other hand, AngularJS maintains an injector with a list of names and corresponding objects. In this case, Object is served whenever it is referenced using the registered name.
Generally we inject dependencies in angularJS like
someModule.controller('MyController', function($scope,greeter){
});
If you want an alternative way to inject dependencies in angularJS, you may do something like.
var MyController = function($scope, greeter) {
// ...
}
MyController.$inject = ['$scope', 'greeter'];
someModule.controller('MyController', MyController);
Hope it helps!

Where to specify module dependencies?

I'm following the standard practice of organizing my angular assets by feature; e.g. AngularJS Folder Structure and AngularJS Best Practices: Directory Structure.
Which file should I put my module / dependency declaration in?
I'm trying to solve the following problems:
I'd like to be able to sort my <script> references alphabetically for maintenance reasons, but I can't because that breaks my Angular bootstrap (for some modules).
I've tried keeping them in the alphabetically-first *.js file in the module, but I spend a lot of time as my app grows moving my dependency declarations around.
I often have to hunt around to find module declarations.
I end up staring at Angular's relatively uninformative module error too often for related reasons.
Regardless, attaching the module declaration to a specific controller seems to imply a direct correlation that doesn't exist.
Here's an example:
metric/
_module.js // Should I create this file?
detail-controller.js
detail.html
search-filter.js
selector-controller.js
selector-directive.js
selector.html
Currently, for this module, that line of code exists in one of my module's controllers, you guess which one! ;)
As a possible solution that I'm not entirely happy with, should I put each module definition in its own tiny, one-line file?
angular.module('metric', ['lib', 'ngSanitize', 'ui.select', 'data']);
How do you do this? Am I missing some other clever or obvious solution?
p.s. as a related problem, if you feel like it, how do to track which components of your module are the source(s) of the dependency?
I would break it up even further.
metric/
metric.js
controllers/
detail-controller.js
selector-controller.js
directives/
selector-directive.js
filters/
search-filter.js
templates/
detail.html
selector.html
Now that I've been working with it for a while, and because I've started pre-compiling my javascript with gulp, the one-line module declaration file seems to be the best solution for me.
I name that file <special-character>module.js, so that it sorts visually and at compile-time to the top. Because my layout convention is one folder = one module, this works schematically. My special character is dash, YMMV. My individual .js file names don't show up in the production compiled version anyway.
It initially bothered me that there was a one-line file in my project, but now I appreciate it. It gets compiled in to my application javascript with gulp, so it's not a performance issue. Also, there's an obvious place to look for dependencies, clear trail in revision control logs of dependency changes, and simple process to document dependencies from my sources with my own custom tools.

Use r.js to package a library written using RequireJS for reuse in other RequireJS applications

So lets say I have some small bit of library code that I develop and test in isolation. I use RequireJS during development and have a root level file that depends on 1 other file. So it's define looks something like...
// lib/main.js
define(['lib/dep1'] function(dep1) {
...
})
I run r.js on the code which results in dist/myLibrary.js, which looks something like this:
define('lib/dep1',[], function(){...})
define('lib/main',["lib/dep1"], function(dep1){...})
If I pull myLibrary.js straight into another project it won't work. Nothing is defining itself as the module for that file. But if I append an actual module definition, it works.
define('lib/dep1',[], function(){...})
define('lib/main',["lib/dep1"], function(dep1){...})
define(['lib/main'], function(lib) {
return lib;
})
And the ['lib/main'] seems to be scoped to the module, because if I have an actual lib/main in my app, it doesn't get used.
Questions:
Regarding the scoping, is that the normal behavior? The fact that lib/main is recognized as a module id from the same file rather than going to look for it someplace else. If I import 10 such libraries that all have a lib/main, they won't collide?
Is there a better way? I am at least initially unconcerned about supporting the non-AMD use case as this is all internal lib development and we all use RequireJS. So within a fully AMDed environment, is there another, better way to do this? Assuming there's no pitfall to this approach, it seems fairly simple and boilerplate to support.

Categories