Hey guys, Daniel here again, trying to create a place of information for Jam, many of you know its not supported anymore, but I am a fan of old code bases so I created this hub as a cool place to see old info, Hope you enjoy.
Installation
Before getting Jam, make sure you install Node.js.
Jam can then be installed using NPM (Node Package Manager), which comes installed with Node.js.
npm install -g jamjs
Using packages
Installing
Jam installs packages to ./jam
by default (this can be easily configured in you project's package.json). This directory contains your installed packages and a specially configured require.js
you can use to load them in the browser.
$ jam install jquery
This will download the latest version of jQuery from the package repository and install it. You can list installed packages using jam ls
.
$ jam ls * jquery 1.7.2
Jam will also fetch any dependencies for the target package.
$ jam install backbone
installing from repositories backbone Building version tree...
repositories checking "backbone"
repositories checking "underscore"
downloading http://packages.jamjs.org/backbone/backbone-0.9.2.tar.gz
downloading http://packages.jamjs.org/underscore/underscore-1.3.3.tar.gz
extracting /home/caolan/.jam/cache/backbone/0.9.2/backbone-0.9.2.tar.gz
extracting /home/caolan/.jam/cache/underscore/1.3.3/underscore-1.3.3.tar.gz
installing underscore@1.3.3
installing backbone@0.9.2
updating jam/jam.json
updating jam/require.config.js
updating jam/require.js
OK
When using jam ls
, packages that are in your jam.dependencies
property in package.json
(direct dependencies) are prefixed with an asterisk, other packages (indirect dependencies) are not. Packages that are not directly depended on may be marked as unused if your project's dependencies change.
$ jam ls underscore 1.3.3
* jquery 1.7.2
* backbone 0.9.2
Loading
To use the packages you've installed, include the specially configured require.js
script in the page. All your other dependencies can then be loaded using the require
function.
<script src="jam/require.js"></script>
<script>
require(['jquery'], function ($) {
$(document.body).text('Hello, world!'); });
</script>
You can load any number of modules in this way, without polluting the global namespace. Jam can also bundle the immediately useful modules into a single file for production use, and you can load less frequently used code in the background when it's needed. All of this can be done without changing the above code.
The first argument to require
is an array of module names to load, these are then passed to the callback containing the code you want to run. For more information, see the RequireJS docs.
Original or alternative require.js
<script src="https://requirejs.org/docs/release/2.0.1/minified/require.js"></script>
<script src="jam/require.config.js"></script>
If you want to use a non-configured version of RequireJS (perhaps from a CDN, or existing app) you can use jam/require.config.js
to set up the correct paths for the installed jam packages. However, you probably want to avoid the extra request and just include the jam/require.js
file instead.
Creating a project dependency list
If you've used Node.js and NPM, you may be familiar with keeping a list of dependencies in a project-level package.json
file. You can also put a list of Jam dependencies in this file, which allows you to lock to specific versions of dependencies.
{ "name": "myproject", "version": "0.0.1", "description": "An example Node.js project", "dependencies": { // NPM dependencies go here...
"async": "0.1.22"
}, "jam": { "dependencies": { // Jam dependencies go here...
"jquery": "1.7.1", "underscore": null
} } }
Of course, it doesn't have to be a Node.js project for you to add a package.json
file with your Jam packages!
Custom install paths
If you'd prefer to install JavaScript dependencies to a location other than ./jam
, you can set the jam.packageDir
property in package.json
. You can also use jam.baseUrl
to tell Jam which directory to make relative package paths from. For example:
{ "jam": { "packageDir": "public/vendor", "baseUrl": "public", "dependencies": { ... } } }
This will install packages to public/vendor
and set up the package paths so you can include public/vendor/require.js
from a file at public/*
. Remember, these are file paths relative to package.json
, not URLs.
Upgrading
When a new version of a library is released it can be a pain to keep your projects up to date. With Jam, when packages are updated you can upgrade to all the latest versions with just one step.
$ jam upgrade
Running this command will check the package repositories for any updates and install any upgraded packages. You can also specify individual packages to upgrade:
$ jam upgrade jquery
Version locking
Of course, automatically upgrading to the latest version isn't always a good idea. If an installed package depends on a specific version of a library, then the correct version will always be retained. Dependencies with specific version requirements in your project's package.json
will also not be upgraded. To upgrade these, you should modify the acceptable versions in package.json
first. If you don't care which version is installed, you can set the version to just null
.
Packages tied to a specific version also show up when doing jam ls
$ jam ls underscore 1.3.3
* jquery 1.6.2 [locked 1.6.2]
* backbone 0.9.2
Removing
To remove a package:
$ jam remove jquery
If you remove a package that has dependencies installed, and those dependencies are not used by any other packages, you can remove them using jam clean
. This will prompt you to remove any packages not included in your package.json
(and not a dependency of one of those packages). If you decide you need to keep a package from this list, you should add the package to your package.json
to make sure it is not removed by mistake.
$ jam clean Building version tree...
The following directories are not required by packages in package.json and will be REMOVED: jam/underscore
Continue [Y/n]:
Production
Compilation
For best performance in production, you should always compile modules into a single file. It's much quicker than waiting for require.js to parse then have it make the requests asynchronously. For complex applications, which use modules only in specific circumstances or on a few pages, you may want to compile a base set of modules that are needed immediately, then load the additional modules in the background only when they are needed.
Jam offers an easy to use command which combines and minifies your installed packages, and can even include code from your own project.
$ jam compile output.js
This will combine all the packages you have installed into a single file, including the configured require.js
library. You can include this file in place of require.js
and get all the benefits of the optimized download without having to change any JavaScript code in your application. In fact, you may find it useful to replace jam/require.js
with the output of the compile command, so you don't even have to change the script tag which includes it. By doing this you get the benefits without having to change anything in your application.
$ jam compile jam/require.js
Of course, the next time you jam install
or otherwise modify the package list, the jam/require.js
file will be rewritten and will not include the compiled modules from before. You would have to re-run the compilation command. Because of this, it makes sense to add this step to your build system. Add it to a Makefile or script you normally use to create production versions of your code, preferably creating a new copy of the whole project (eg myapp/dist
) and running the jam compile
step in the new directory.
Including specific modules
You may not want to include all the installed packages in the compiled output, or you may want to include some modules from your project that are not being managed by Jam. Thankfully, you can specify individual modules to include in the compiled output.
$ jam compile -i myapp/base -i jquery -o output.js
You can use package names or paths to AMD modules from your own application. The output will include the specified modules and their dependencies. Any modules not included will still be accessible using require.js
, they'll just be loaded asynchronously as you need them.
Almond
If you know you won't be loading additional resources in the background you can add --almond
to the compile command to have it use the almond.js shim to provide the require and define functions. This saves a little off the download size, which may be significant on mobile devices.
Best practice
Make it easy to find dependencies
If you're specifying individual modules to include in jam's compiled output, you can make it easier to manage by using a single, top-level module for your application. This module should include all the other modules and top-level dependencies you need. Then, when doing jam compile
you need only specify this file and Jam will find all the dependencies from there.
myapp/app.js
define('myapp/app', [ 'jquery', 'myapp/foo'
],
function ($, foo) {
return { init: function () {
// add you app initialization code here
// ...
} };
});
index.html
<script src="jam/require.js"></script>
<script>
require(['myapp/app'], function (app) {
app.init(); });
</script>
Then, to include all the immediately required files into a single download, simply do:
$ jam compile -i myapp/app -o output.js
By doing it this way, you can add that command to your build script and not have to update it when your app's dependencies or module structure changes. Instead, you just manage compiled dependencies in myapp/app.js
.
Load large, infrequently used resources on demand
In the majority of cases, you'll want to just include your modules in a single compiled download. Occasionally, however, you may have large resources which are only needed in very specific circumstances. In this situation, it can be useful to load the resources in the background only once they are needed.
The following examples build on the files from the previous section: "Make it easy to find dependencies".
index.html
<button id="testbtn">Test</button>
<script src="jam/require.js"></script>
<script>
require(['myapp/app'], function (app) {
app.init(); });
</script>
myapp/app.js
define('myapp/app', [ 'jquery', 'myapp/foo'
],
function ($, foo) {
return { init: function () {
$('#testbtn').click(function () {
// by making a require call here, we can load this
// asynchronously, only once we've clicked the button!
require(['myapp/bar'], function (bar) {
alert(bar.message); });
}); } };
});
myapp/bar.js
define('myapp/bar', [], function () {
return {message: 'Hello, world!'}; });
Now, if you were to compile according to the previous section, including only myapp/app
:
$ jam compile -i myapp/app -o jam/require.js
Then open index.html
in the browser, you should notice that on page load only require.js
is fetched (since it has myapp/foo
and jquery
compiled). But, when you click the "Test" button the myapp/bar
module is fetched in the background.
Developing packages
Package.json
The package.json
file inside each package directory provides Jam with important meta-data, including description, version information and required dependencies. It is loosely based on the Package Descriptor File format described in the Packages 1.0 specification available as part of CommonJS. Often, you'll find that these files are compatible with the package.json
used for publishing to NPM.
Short example
{ "name": "example", "version": "0.0.1", "description": "An example Jam package", "jam": { "dependencies": { "jquery": ">1.4.2", "underscore": ">1.3.1"
}, } }
These are the essential properties every package.json
must have, though you might omit the dependencies field if the package has no dependencies. Ideally, you should provide as much information about the package as possible.
Full example
{ "name": "example", "version": "0.0.1", "description": "An example Jam package", "homepage": "http://example.com", "keywords": [ "package", "example"
], "jam": { "dependencies": { "jquery": ">1.4.2", "underscore": ">1.3.1"
}, "main": "example.js", "shim": { "deps": ["jquery"], "exports": "Example"
}, "include": [ "example.js", "README"
] }, "maintainers": [ { "name": "Bill Smith", "email": "bills@example.com", "web": "http://www.example.com" } ], "contributors": [ { "name": "Mary Brown", "email": "maryb@example.com", "web": "http://www.example.com" } ], "bugs": { "mail": "dev@example.com", "web": "http://www.example.com/bugs" }, "licenses": [ { "type": "MIT", "url": "http://www.opensource.org/licenses/mit-license.php", } ], "repositories": [ { "type": "git", "url": "http://github.com/example/example.git"
} ], "github": "http://github.com/example/example"
}
Required fields
name | The name of the package. Ideally, this should be all lowercase, and if necessary, use a "-" as a separator between words (eg, "example-package"). |
---|---|
version | A version string conforming to the Semantic Versioning requirements (http://semver.org). See the section on versioning for more information. |
description | A brief description of the package. |
Additional fields
homepage | URL string for the package website. | ||||||||
---|---|---|---|---|---|---|---|---|---|
keywords | An Array of string keywords to assist users searching for the package. | ||||||||
jam |
| ||||||||
maintainers | Array of maintainers of the package. Each maintainer is a hash which must have a "name" property and may optionally provide "email" and "web" properties. | ||||||||
contributors | Array of hashes each containing the details of a contributor. Format is the same as for maintainers. | ||||||||
bugs | URL for submitting bugs. Can be mailto or http. | ||||||||
licenses | Array of licenses under which the package is provided. Each license is a hash with a "type" property specifying the type of license and a url property linking to the actual text. If the license is one of the official open source licenses the official license name or its abbreviation may be added with the "type" property. If an abbreviation is provided (in parentheses), the abbreviation must be used. | ||||||||
repositories | Array of repositories where the package can be located. Each repository is a hash with properties for the "type" and "url" location of the repository to clone/checkout the package. A "path" property may also be specified to locate the package in the repository if it does not reside at the root. | ||||||||
github | The appropriate GitHub page for the package. This mean the package details page on the jam website will display a link to GitHub and a watchers count in search results. This can sometimes be inferred from the repositories property. |
Linking packages
During development, you may want to use your package in a project while continuing to work on it. Using jam link
you can create a symlink to the package directory and add it to your paths in jam/require.js
.
$ jam link /path/to/dev-package
Remember that your symlink locations are unlikely to be useful to anyone else that checks your code out. This should only be used during development until it makes sense to install a copy in your project.
To stop Jam from trying to upgrade linked packages you should add "linked"
as the version in your project's package.json
for the package you are linking.
Versioning
Jam uses semantic versioning (http://semver.org). Loosely speaking, this translates to MAJOR.MINOR.PATCH
, for example 1.2.3
.
If you are directly publishing a library from it's source repository, without modifications, then you can simply publish it with the version number of the library itself (provided it conforms to the semantic versioning requirements). If you make any modifications to the upstream library to prepare it for publishing to the Jam repositories, you should add a Jam version number. For example 1.2.3-jam.1
, 1.2.3-jam.2
. This allows you to update the Jam-specific code without changing the upstream version number.
Publishing
To publish a package so others can install it, you must first sign-up for an account on this site. Once you have an account, just do jam publish
inside your package directory to pack and upload it. Then repeat the publish command every time you want to release a new version. If you make a mistake and want to publish over an existing version, use the -f
or --force
flag. Be warned, this is not recommended, since it will not prompt people using the previously published copy to update.
If you would like to remove a package from the Jam repositories, use jam unpublish PACKAGE
, where PACKAGE
is the name of the package you'd like to remove. You can specify a single version to remove by doing jam unpublish PACKAGE@VERSION
, eg jam unpublish example@1.2.3
.
Categories
To make your package easy to find, you can use a number of pre-defined categories in your package.json
file. You can see the list of available packages on the packages page. The categories must be typed exactly as shown, and are case-sensitive.
{ "categories": ["Frameworks", "DOM"], ... }