96

Although there are great solutions to manage dependencies on the server side, I could not find any that satisfies all my needs to have a coherent client side JavaScript dependency management workflow. I want to satisfy these five requirements:

  1. Manage my client-side dependencies in a format similar to npm's package.json or Bower's bower.json

  2. It should have the flexibility to point to a Git repository or actual JavaScript files (either on web or locally) in my dependency.json file for lesser known libraries (npm let you point to Git repositories)

  3. It should minify and namespace all libraries into a single file like Ender - that's the only JavaScript file I would need to put in my <script> tag in the client side

  4. It should have out of box support for CoffeeScript like BoxJS4 (now dead)

  5. In the browser, I should be able to use either require style:

     var $ = require('jquery');
     var _ = require('underscore');
    

    Or better yet, do headjs style:

     head.js(['jquery', 'underscore', 'mylib'], function($, _, mylib) {
       // Executed when all libraries are loaded
     });
    

If no one such single tool exists, what is the best combination of tools i.e. a tool-chain that I can combine using something like Volo (or Grunt)?

I have already researched all the tools I have linked to in here and they satisfy only up to three of my requirements at best individually.

So, please don't post again about these tools. I would only accept an answer that provides a single tool that satisfies all five of my requirements or if someone posts a concrete workflow/script/working example of a toolchain of multiple such tools that also satisfies all my requirements.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
pathikrit
  • 32,469
  • 37
  • 142
  • 221
  • 6
    something like http://requirejs.org/ ? – Chandra Sekhar Walajapet Oct 15 '12 at 09:51
  • 1
    For a more "node-style" solution that ports node's `require` syntax to the browser consider [browserify](http://https://github.com/substack/node-browserify) – smithclay Oct 16 '12 at 00:06
  • 1
    Can you be more explicit? Out of the 5 bullet-points in my question, I think requirejs/browserify only satisfy one or two points. I am looking for a tool (or tool-chain) that lets me do ALL five of my requirements – pathikrit Oct 17 '12 at 04:27
  • 3
    I didn't tried it yet, but perhaps http://yeoman.io/ is a good candidate too – Guillaume86 Nov 06 '12 at 13:52
  • 1
    I just heard about onejs - it sounds somewhat related: https://github.com/azer/onejs – dsummersl Feb 11 '13 at 12:39
  • A deleted duplicate is *[Dependency manager that runs in a browser?](https://stackoverflow.com/questions/41807065/dependency-manager-that-runs-in-a-browser)*. – Peter Mortensen Nov 23 '22 at 10:50

16 Answers16

44

RequireJS does everything you need.

My answer to this question may help you.

Example:

Client app project hierarchy:

sampleapp
    |___ main.js
    |___ cs.js
    |___ require.js

main.js is where you initialize your client application and configure RequireJS:

require.config({
    baseUrl: "/sampleapp",
    paths: {
        jquery: "libs/jquery", // Local
        underscore: "http://underscorejs.org/underscore-min.js", // Remote
        backbone: "https://github.com/documentcloud/backbone/blob/master/backbone-min.js" // Remote on GitHub
    },
    shim: {
        backbone: {
            deps: ["underscore", "jquery"] // Backbone depends on jQuery and Underscore.js
        }
    }
});

require(["cs!someCoffeescriptFile", "jquery", "backbone", "underscore"], function (SomeCoffeescriptFile, $, Backbone, _) {
    // Dependencies are loaded...
    // Execute code
});

Dependencies will use the cs plugin when prepended by "cs!". The cs plugin compiles the CoffeeScript file.

When you go in production, you can precompile your whole project with r.js.

node ./node_modules/requirejs/bin/r.js -o buildclientconfig.js

Here are your requirements:

  • Manage my client side dependencies in a format similar to npm's package.json or Bower's component.json file. Different but as good!

  • I should have the flexibility to point to a Git repository or the actual JavaScript files (either on web or locally) in my dependency.json file for lesser-known libraries (npm lets you point to Git repositories). Yes

  • It should minify and namespace all libraries into a single file like Ender. That's the only JavaScript file I would need to put in my script-tag on the client side. Yes with r.js.

  • It should have out of box support for CoffeeScript, like Box. Yes

  • In the browser I can use either require style or headjs. Yes

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Jean-Philippe Leclerc
  • 6,713
  • 5
  • 43
  • 66
  • If I use `r.js`, can I simply pull in non-minified versions of all libraries, or how should I decide between minified and non-minified libraries? – Domi Apr 28 '14 at 09:57
  • The only problem is this requireJS crap that you have to carry with minified code. – pronebird Aug 25 '14 at 16:36
  • 1
    @Andy not necessarily! You can use Almond instead which is a lot smaller! – Adam B Oct 26 '14 at 00:24
24

RequireJS is the one you are looking for, I believe.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
  • 3
    I am confused. How exactly can requirejs pull in an arbitrary javascript file from the internet (I am not talking about the ones in its repo like jquery but less famous ones)? Can it read a package.json file? And it does not work with CoffeeScript... Am I missing something?? – pathikrit Oct 17 '12 at 04:22
  • I am looking for one single tool (or a toolchain of multiple tools) that satisfies all 5 of my requirements and I think (correct me if I am wrong) - requirejs only satisfies about one or two of my five bullet-point – pathikrit Oct 17 '12 at 04:31
  • It meets 2, 3, and 5 [edit: apparently it can compile coffeescript!]. It does compile CoffeeScript files for you or you could do that server-side (e.g. when user requests foo.js, load from disk foo.coffee, compile it and return it). And there's no format needed; it's not a full blown package manager. But you can specify your dependencies all in one place and their short names, and then just reference them by their short name in the actual require statement. – Ricket Feb 22 '13 at 04:32
15

As Guillaume86, I think Hem will get you the closest to where you want to be.

In Hem, dependencies are managed using a combination of npm and Hem. Use npm to explicitly install all of your projects external dependencies. Use Hem to specify which dependencies (both external and local) should be stitched together for you client side operations.

I created a skeleton project of this, so you can see how this would work. You can see it at Client-side Hem.

Adding dependencies

Use npm to search for a specific dependency and then modify the package.json file to ensure that the dependency is tracked in the future. Then specify the dependency for your application in slug.json.

For example, suppose you wanted to add the CoffeeScript dependency. Just use npm to install the dependency and save it to your package.json file:

  1. npm --save install coffee-script
  2. Manually edit the slug.json file. Add "coffee-script" to "dependencies".

Suppose you wanted to include your own module 'bloomfilters' and it wasn't in the npm registry. You could add it to your project in the following way:

  1. npm --save install https://github.com/dsummersl/bloomfilters/tarball/master
  2. Manually edit the slug.json file. Add "bloomfilters" to "dependencies".

Local modules

If you want to include your own CoffeeScript or JavaScript code, you can do so by adding those files to the app/ folder. Note that in order to expose your script via the 'require' method you must make it a CommonJS module. It is very simple—see the Hem documentation.

Local files

If you want to include non-CommonJS non 'require' code, you can also stitch that by referencing your custom JavaScript or CoffeeScript code via the 'libs' list in file slug.json.

CSS

Hem will stitch together your CSS too, if you want. See the Hem documentation.

Building

Once you have your dependencies listed, you can use hem to stitch them all together.

# Make sure all dependencies are present:
npm install .

# Make public/application.js
hem build

# See your minified js in public/application.js

Notes

Hem was meant for the Spine.js project - but you don't have to use it for that. Ignore any documentation mentioning spine as you wish...

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
dsummersl
  • 6,588
  • 50
  • 65
11

There is also Browserify.

  1. supports the package.json format
  2. uses npm underneath which can use a GitHub (or any Git) repository as a package source
  3. minifies and concatenates all dependencies into a single file.
  4. supports CoffeeScript if you include it in your dependencies
  5. require style all the way.
  6. supports source maps
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Floby
  • 2,306
  • 17
  • 15
  • you can use any github repo (or bower package) with browserify? Does that require something like `napa` or no? https://www.npmjs.org/package/napa – Connor Leech May 21 '14 at 14:44
9

I'm pretty sure Hem meets your requirements (I use a personal fork with additional compilers, Jade and Stylus. It's easy to customize to your needs). It uses npm to manage dependencies.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Guillaume86
  • 14,341
  • 4
  • 53
  • 53
  • From the reading of this particular question I think this solves 1,3,5 fairly well out of the box. For #2 you can put your own local JS packages in node_modules (it uses local npm), and you can use git submodule for any dependencies only on git. For #4 I think you're stuck having to compile coffee to js yourself prior to running hem (which is easy). – dsummersl Oct 24 '12 at 19:03
  • Thanks for the comment, but hem compiles my coffeescript without problems :), it was initially made for Spine.js wich is a coffeescript oriented framework so it's was a basic requirement – Guillaume86 Oct 24 '12 at 19:45
  • I understand that it would for spine like apps (ie putting coffee in app/...) but what about external modules that contain coffeescript? I think thats what wrick is asking, but I could be totally wrong... – dsummersl Oct 25 '12 at 02:21
  • 1
    Ok I don't know if it compiles coffeescript for external modules but I don't think it's usefull, external modules usually provide the compiled JS :) – Guillaume86 Oct 25 '12 at 08:27
  • Yes, I concur. It gets into the realm of make a cakefile/grunt... – dsummersl Oct 30 '12 at 13:01
  • Looks like what the OP needs, satisfies all conditions reasonably. – user568109 Feb 17 '13 at 14:57
5

You might want to take a look at Yeoman, which uses several techniques to help you with your requirements.

Our workflow is comprised of three tools for improving your productivity and satisfaction when building a web app: Yo (the scaffolding tool), Grunt (the build tool) and Bower (for package management).

Built-in support for CoffeeScript, Compass and more. It works with r.js (RequireJS), unit testing, etc.

As for your requirements:

  1. Bower is used for dependency management
  2. Bower can work with local files, git://, http:// and more
  3. Built-in support for minification and concatenation (even for your images)
  4. Built-in support to automatically compile CoffeeScript and Compass (with LiveReload)
  5. As stated in the build process: if you're using AMD, I will pass those modules through r.js so you don't have to.

All features:

Lightning-fast scaffolding — Easily scaffold new projects with customizable templates (e.g HTML5 Boilerplate, Twitter Bootstrap), RequireJS and more.

Great build process — Not only do you get minification and concatenation; I also optimize all your image files, HTML, compile your CoffeeScript and Compass files, if you're using AMD, I will pass those modules through r.js so you don't have to.

Automatically compile CoffeeScript & Compass — Our LiveReload watch process automatically compiles source files and refreshes your browser whenever a change is made so you don't have to.

Automatically lint your scripts — All your scripts are automatically run against JSHint to ensure they're following language best-practices.

Built-in preview server — No more having to fire up your own HTTP Server. My built-in one can be fired with just one command.

Awesome Image Optimization — I optimize all your images using OptiPNG and JPEGTran so your users can spend less time downloading assets and more time using your app.

Killer package management — Need a dependency? It's just a keystroke away. I allow you to easily search for new packages via the command-line (e.g. bower search jquery), install them and keep them updated without needing to open your browser.

PhantomJS Unit Testing — Easily run your unit tests in headless WebKit via PhantomJS. When you create a new application, I also include some test scaffolding for your app.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
MarcoK
  • 6,090
  • 2
  • 28
  • 40
4

Bower may suit your needs (1). And (2) for the rest you have RequireJS.

From the README:

Bower is a package manager for the web. Bower lets you easily install assets such as images, CSS and JavaScript, and manages dependencies for you.

To install a package:

bower install jquery
bower install git://github.com/maccman/package-jquery.git
bower install http://code.jquery.com/jquery-1.7.2.js
bower install ./repos/jquery
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
user18428
  • 1,216
  • 11
  • 17
  • I have researched all the ones I linked to in my OP (including Bower) and none of them happen to satisfy more than 3 out of my 5 requirements. I am looking for one single tool (or a combination of tools) that would address all 5 of my issues. – pathikrit Oct 23 '12 at 18:45
  • Don't know if that deserve a downvote, i stated that bower+requirejs mays suits your need. You said that you were also open for 'the best combination of tools'. Good luck with your search though – user18428 Oct 23 '12 at 18:48
  • What's wrong with this : (1) bower (2) also bower (3)requirejs build (4) you already have node installed no? (5) requirejs – user18428 Oct 23 '12 at 18:54
2

Look at the Jam package manager. Following is the description from its homepage

For front-end developers who crave maintainable assets, Jam is a package manager for JavaScript. Unlike other repositories, we put the browser first.

It seems a lot similar to npm in how it works.

Install the package like below:

jam install backbone

Keep the packages up-to-date by executing:

jam upgrade
jam upgrade {package}

Optimize packages for production

jam compile compiled.min.js

Jam dependencies can be added in package.json file.

For complete documentation, read the Jam documentation.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
himanshu
  • 2,087
  • 1
  • 13
  • 13
2

I just came across inject.js

Some of the features, from the project site:

Inject (Apache Software License 2.0) is a revolutionary way to manage your dependencies in a Library Agnostic way. Some of its major features include:

  • CommonJS Compliance in the Browser (exports.*)
  • View the full CommonJS Support Matrix
  • Cross domain retrieval of files (via easyXDM)
  • localStorage (load a module once)
Veverke
  • 9,208
  • 4
  • 51
  • 95
  • I like inject. It is much cleaner than RequireJS, and almost exactly like writing with node. – Mardok Oct 16 '15 at 16:45
1

There are a couple of options:

  • Browserify which allows you to import modules
  • RequireJS addresses the same problem
  • One that seems to be in active development is JoinJS

Component might also be of interest. It does not manage dependencies per se, but it allows you to use chopped up versions of otherwise large libraries.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
JoelKuiper
  • 4,362
  • 2
  • 22
  • 33
1

I use Hem with npm, and I wanted to add some additional benefits that I think weren't covered so far.

  • Hem has a self-contained web server (Strata) so you can develop your code without even needing to recompile. I never use hem build unless I am publishing an application.
  • You don't need to use Spine.js to use Hem. You can use it to compile arbitrary CoffeeScript packages if you set up file slug.json correctly. Here's one of my packages that is auto-compiled with cakefile: TurkServer
  • Speaking of the above, Hem allows you to link other dependencies on your local system in with an npm link and combines them seamlessly even when you are using the Strata server. In fact, you needn't even use the cake method above; you can just link directly to CoffeeScript from dependent projects.
  • Hem supports eco (embedded CoffeeScript) for views and Stylus for CSS, and compiles all that, along with your CoffeeScript code, into one JavaScript file and one CSS file.

Here's a basic list for getting set up with a Spine.js, Hem, and CoffeeScript application. Feel free to ignore the Spine.js parts. In fact, sometimes I use spine app to set up a directory structure for a non-Spine.js application, then edit file slug.json to change to a different compilation structure.

  1. Install NPM: curl http://npmjs.org/install.sh | sh on a Unix-like system. I'll assume it's available from the command line.

  2. Install Hem globally (npm install -g hem). Development has branched as of late, so you might want to get it straight out of GitHub, checkout a branch, and npm install -g . in that folder.

  3. npm install -g spine.app will make spine available as a global command

  4. spine app folder will make a Spine project called app in folder, generating the right directory structure and a bunch of skeleton files to get started.

  5. cd to folder and edit file dependencies.json for the libraries you need. Add them to file slug.json, so that Hem knows where to find them as well.

  6. Optional: npm link any of your local packages in development to folder node_modules, and you can add them to file slug.json for Hem (either an index.js file to include directly or an index.coffee file if you want hem to compile it.)

  7. npm install . to download all the dependencies you just entered in.

  8. If you take a look at the default spine configuration, there is a app/lib/setup.coffee where you require all the libraries you need from your dependencies. Examples:

     # Spine.app had these as dependencies by default
     require('json2ify')
     require('es5-shimify')
     require('jqueryify')
    
     require('spine')
     require('spine/lib/local')
     require('spine/lib/ajax')
     require('spine/lib/manager')
     require('spine/lib/route')
    
     # D3.js was installed via file 'dependencies.json'
     require 'd3/d3.v2'
    
  9. In file index.coffee, you just do require lib/setup and load the main controller for your application. In addition, you need to do require on any other classes in those other controllers. You can use spine controller something or spine model something to generate templates for controllers and models. A typical Spine controller looks like the following, using Node.js' require:

     Spine = require('spine')
     # Require other controllers
     Payment = require('controllers/payment')
    
     class Header extends Spine.Controller
       constructor: ->
         # Initialize the class
    
       active: ->
         super
         @render()
    
       render: ->
         # Pull down some eco files
         @html require('views/header')
    
     # Makes this visible to other controllers
     module.exports = Header
    
  10. The default generated index.html file will usually be fine for loading your application, but modify as necessary. Per your requirements, it only pulls in one .js and one .css file, which you never need to modify.

  11. Edit your stylus files as necessary in the css folder. It's a lot more flexible than CSS :)

  12. From folder, run hem server to start a Hem server, and navigate to localhost:9294 to see your application (if you installed Hem globally). It has some hidden arguments, for example, --host 0.0.0.0 listens on all ports.

  13. Build the rest of your application using proper MVC techniques, and use stylus for CSS and eco for views. Or don't use Spine at all, and Hem will still work great with CoffeeScript and npm. There are many examples of projects using both models.

One more thing: normally, hem server will update automatically as you update your code and save files, which makes it a cinch to debug. Running hem build will compile your application into two files, application.js, which is minified and application.css. If you run hem server after this, it will use those files and no longer update automatically. So don't hem build until you actually need a minified version of your application for deployment.

Additional references: Spine.js and Hem: Getting started

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Andrew Mao
  • 35,740
  • 23
  • 143
  • 224
1

Here's a solution that takes a very different approach: package up all the modules into a JSON object and require modules by reading and executing the file content without additional requests.

Pure client-side demo implementation: http://strd6.github.io/editor/

https://github.com/STRd6/require/blob/master/main.coffee.md

STRd6/require depends on having a JSON package available at runtime. The require function is generated for that package. The package contains all the files your app could require. No further HTTP requests are made because the package bundles all dependencies. This is as close as one can get to the Node.js style require on the client.

The structure of the package is as follows:

entryPoint: "main"
distribution:
  main:
    content: "alert(\"It worked!\")"
  ...
dependencies:
  <name>: <a package>

Unlike Node.js a package doesn't know its external name. It is up to the package including the dependency to name it. This provides complete encapsulation.

Given all that setup here's a function that loads a file from within a package:

loadModule = (pkg, path) ->
  unless (file = pkg.distribution[path])
    throw "Could not find file at #{path} in #{pkg.name}"

  program = file.content
  dirname = path.split(fileSeparator)[0...-1].join(fileSeparator)

  module =
    path: dirname
    exports: {}

  context =
    require: generateRequireFn(pkg, module)
    global: global
    module: module
    exports: module.exports
    PACKAGE: pkg
    __filename: path
    __dirname: dirname

  args = Object.keys(context)
  values = args.map (name) -> context[name]

  Function(args..., program).apply(module, values)

  return module

This external context provides some variable that modules have access to.

A require function is exposed to modules so they may require other modules.

Additional properties such as a reference to the global object and some metadata are also exposed.

Finally we execute the program within the module and given context.

This answer will be most helpful to those who wish to have a synchronous Node.js style require statement in the browser and are not interested in remote script loading solutions.

danronmoon
  • 3,814
  • 5
  • 34
  • 56
Daniel X Moore
  • 14,637
  • 17
  • 80
  • 92
1

Check out Cartero if you are using Node.js or Express.js on the backend.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Brave Dave
  • 1,300
  • 14
  • 9
0

I'd suggest to check out the Dojo Toolkit which seems to meet most of your requirements. The one I'm not sure about is CoffeeScript.

Dojo works with modules written in the Asynchronous Module Definition (AMD) format. It has a build system with packages and you can aggregate them in one or several files (called layers). Apparently it accepts Git type repositories, and more details on the build system are on Creating Builds.

For the record, v1.9 beta is expected next month.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Christophe
  • 27,383
  • 28
  • 97
  • 140
0

Another framework that satisfies all my criteria released recently is http://duojs.org/ (and it also supports treating other resources, like CSS, as dependencies).

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
pathikrit
  • 32,469
  • 37
  • 142
  • 221
0

Dependency injection with asynchronous loading and Browserify will be another good choice, compares to RequireJS.

asynchronous-frontend-dependency-management-without-AMD

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
fantasyni
  • 9
  • 1
  • 1
    This is a little sparse. [It would be preferable](http://meta.stackoverflow.com/q/8259) to include more of the answer here, and provide the link for reference. – Nathan Tuggy Dec 25 '14 at 01:24