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();
}
}
})();
Related
I'm working on a multi-page site using AngularJS, and I want to write a utility that can be included in more than one page. I've looked at services and providers, and all the examples I find are single-page examples. I'm not sure how to generalize this to multiple apps used on different pages.
This is what I want to have for my two different pages/apps.
in app1.js:
var app1 = angular.module('app1',['myUtil'])
app1.controller('ctrl1',function ctrl1($scope,myUtil){...})
in app2.js:
var app2 = angular.module('app2',['myUtil'])
app2.controller('ctrl2',function ctrl2($scope,myUtil){...})
in myUtil.js:
??? Provider? Service? Module?
All the examples I have found for providers and services show them as being attached to a single app. Is this possible with AngularJS? If so, what am I missing?
The answer from zero298 is a nice answer as it's a great way of organising and reusing the utility module you create.
If you want a less broad and more "codey" answer, then one way of doing it would be to have some kind of utility module that houses whatever services you want to put in it, and then you can pass that in as a dependency for all apps that use it. This will all depend on your build process as to how you import/organise the files, but as a very basic example you could have a "utilsmodule" module with a "utils" service:
myUtils.js:
angular.module('utilsmodule', []);
// Service could be in another file
angular.module('utilsmodule').service('myutil', function() {
return {
myUtilFunction : function() {
return "This is from myutil";
}
};
});
Then in your app files you can pass in the module by name, which will give the app access to the 'myutil' service.
app1.js:
var app1 = angular.module('app1',['utilsmodule'])
app1.controller('ctrl1',function ctrl1($scope,myutil){...})
Then you would import the myUtils.js file before the app1.js file so that the "utilsmodule" module is registered with angular before your app is created. You do the same with app2 and the utility module should be available to both.
Example Plunker
This may be a bit too broad. However, what I would suggest you do is create a library module dedicated to the feature/utility that you want to make available to your projects.
I would suggest using npm to organize all of this. Give this feature module it's own package.json and add whatever code you need to make it run. In your consumer projects, add the library module as a dependency.
A good method to get this working locally (as well as quickly since you don't have to constantly push to the npm registry) is to use the npm link utility.
If your consumer projects are already npm oriented, the workflow would be as follows:
Create a new directory to contain your utility library module lets call it my-utility
cd to the new directory
npm init to create a package.json in this library
npm link to make the library available locally
cd to any of the consumer projects
npm link my-utility so that the consumer projects create a symlink to the local folder that contains your utility module
After that is setup, depending on how your consumer projects build or use dependencies, you can use your new utility library in your top level projects.
I'm writing a javascript library that contains a core module and several
optional submodules which extend the core module. My target is the browser
environment (using Browserify), where I expect a user of my module will only
want to use some of my optional submodules and not have to download the rest to
the client--much like custom builds work in lodash.
The way I imagine this working:
// Require the core library
var Tasks = require('mymodule');
// We need yaks
require('mymodule/yaks');
// We need razors
require('mymodule/razors');
var tasks = new Tasks(); // Core mymodule functionality
var yak = tasks.find_yak(); // Provided by mymodule/yaks
tasks.shave(yak); // Provided by mymodule/razors
Now, imagine that the mymodule/* namespace has tens of these submodules. The
user of the mymodule library only needs to incur the bandwidth cost of the
submodules that she uses, but there's no need for an offline build process like
lodash uses: a tool like Browserify solves the dependency graph for us and
only includes the required code.
Is it possible to package something this way using Node/npm? Am I delusional?
Update: An answer over here seems to suggest that this is possible, but I can't figure out from the npm documentation how to actually structure the files and package.json.
Say that I have these files:
./lib/mymodule.js
./lib/yaks.js
./lib/razors.js
./lib/sharks.js
./lib/jets.js
In my package.json, I'll have:
"main": "./lib/mymodule.js"
But how will node know about the other files under ./lib/?
It's simpler than it seems -- when you require a package by it's name, it gets the "main" file. So require('mymodule') returns "./lib/mymodule.js" (per your package.json "main" prop). To require optional submodules directly, simply require them via their file path.
So to get the yaks submodule: require('mymodule/lib/yaks'). If you wanted to do require('mymodule/yaks') you would need to either change your file structure to match that (move yaks.js to the root folder) or do something tricky where there's a yaks.js at the root and it just does something like: module.exports = require('./lib/yaks');.
Good luck with this yak lib. Sounds hairy :)
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
So i've come across an interesting use case where i'm using Browserify to bundle all of my assets together in a project, but a large external (external to the project) module needs to be loaded in when a certain in-app window is accessed. (It's a video player module made up of three scripts that get pulled in asynchronously when required).
At the moment i'm getting all kinds of errors from uncalled object errors if the requireJS module is loaded in before the Browserified app.js file, to cannot find module errors if loaded in after the Browserified code.
Is there anyway i can get Browserify and RequireJS to play nicely on the same page? I'm losing my mind!
TL;DR - use window.require in your browserified script.
Maybe it would still help someone.
I happen to use an 'external' dojo-based library totally based on requireJS-style AMD, which is absolutely un-"browserifyeble" and un-convertable to CommonJS or anything sane. My own code is totally Browserified. It's working OK like this:
Load the AMD loader (which defines the global require function) before the browserified script:
<script src="dojo/dojo.js"></script> <!-- RequireJS/AMD loader, defining a global 'require'-->
<script src="app/main.js"></script> <!-- The Browserify bundle -->
In your own js, call the require function on window object ('cause you'll have a local browserify-require shadowing the global one)
window.require(['dojo/dojo'], function (dojo) { ... });
The 'external' app or library, which calls require on its own to load submodules etc., works just fine 'cause that code is out of browserify context and the global require is not shadowed there.
Maybe if you have some pure nice standard RequireJS modules, you could somehow convert them to be Browserifiable, but in my case that wasn't an option.
There is a tool called browserify-derequire that resolves this issue by renaming browserify's require statmenets to avoid the naming collision.
It can be installed with npm using:
npm install -g browserify-derequire
Use it as a browserify plugin by changin your build command to:
browserify src/*.js -p browserify-derequire > module.js
There is more discussion on this issue at: https://github.com/substack/node-browserify/issues/790
For a gulp friendly solution (similar to what #Cride5 proposed) you can use gulp-derequire plugin.
Basic example from docs:
var derequire = require('gulp-derequire');
var browserify = require('browserify');
var source = require('vinyl-source-stream');
gulp.task('build', function() {
var bundleStream = browserify({entries: './index.js', standalone: 'yourModule'}).bundle();
return bundleStream
.pipe(source('yourModule.js'))
.pipe(derequire())
.pipe(gulp.dest('./build'));
});
Plugin is also based on derequire module so all options are supported.
I'm attempting to use a node module in a typescript application and I've included it in my TypeScript code via require().
I build my typescript to JS and all works well if I run it through node which is great.
I'm looking for a way to use the same code and run it through the browser. Browserify seemed like a sensible solution.
I popped a post build action on my VS project and I'm building a 206KB file via browserify (so it's certainly doing something!). Unfortunately my tiny bit of Typescript doesn't seem to be accessible when it's been browserified.
I'm not that familiar with what browserify should be generating so not quite sure whether what it's wrapped my .js code in is correct (can post snippets if it helps).
So my question is twofold really, I'm looking for the answer to either:
Is there a recommended way to write TypeScript post 0.9 to allow it to be run after it's been browserified?
Is there a way to simple tell TypeScript to pull in the 'require' dependency on its own?
Any thoughts or info in this area would be greatly appreciated.
EDIT:
Just to clarify, I'm generating my .js from the .ts during save/build, and in a post build action, pointing browserify to the output. An abridged js output looks like this:
var TestModule;
(function (TestModule) {
function launchDrone() {
var exports = require('ar-drone');
var client = exports.createClient();
}
})(TestModule || (TestModule = {}));
When I generate the browserified file from that, I can't access TestModule or launchDrone in any context (or certainly not from window. ) is there some trick to accessing the browserified code?
It looks like you potentially are not exporting TestModule? Your TestModule file should look like this:
module TestModule {
export function launchDrone() {
var exports = require('ar-drone');
var client = exports.createClient();
}
}
export = TestModule;
This way you should be able to launch TestModule and TestModule.launchDrone from the window.