Creating Packages

Juho Teperi edited this page Sep 12, 2016 · 21 revisions

Packaging up a JavaScript library for use in ClojureScript is usually not too difficult.

While it's the rare case please note that some JS libraries are written in a Google Closure compatible way and do require a slightly different process. See this discussion

The following list goes through the process, step-by-step. If you encounter any problems, consult README for link to project discussion channel.

1. Fork this repository and create a branch

You'll do your work in this branch in order to submit the package later.

2. Find the library's source code

This will usually be via a service like GitHub, CDNJS or the library's homepage. A zip file with the source is fine.

3. Create a directory structure for the package

Use the library's name (without "js" or ".js") as the top-level directory and create the following directory structure:

└── resources
    └── cljsjs
        └── <library-name>
            └── common

4. Add an externs file for the library

If you aren't familiar with externs, read about what they are and how to create them.

Add your externs file to the following location:

└── resources
    └── cljsjs
        └── <library-name>
            └── common
                └── <library-name>.ext.js

Note: In addition to your externs file, any additional assets (css, images) that ship with the JS library should be added to the common directory.

5. Add build.boot and README.md files

Consult existing library packages for examples. Files can be copied from existing packages to get started.

5.1 build.boot

This file will describe how the package can be built and should reside in the library's top-level directory.

All builds should minimally contain the following:

  • Version vars:
(def +lib-version+ "x.y.z")
(def +version+ (str +lib-version+ "-0"))

The names of vars should be these, as our build script uses simple regex to parse versions from build.boot files. The lib version should be exactly the same as version used by the library. You can use +lib-version+ var to construct the URL to be downloaded. Cljsjs version (used for Clojars) is based on lib version with a build identifier appended.

5.2 README.md

This file should reside in the library's top-level directory and contain the following:

  • the package's name and a placeholder for the version number.
  • any specific instructions for its usage

6. Writing the package task

After running the package task in any CLJSJS package, the fileset contents should be as follows. You can check these by using show --fileset task or by writing fileset contents to a directory using target task.

├── cljsjs
│   └── <library-name>
│       ├── common
│       │   └── <library-name>.ext.js
│       ├── development
│       │   ├── <library-name>.inc.js
│       │   └── <library-name>.inc.css
│       └── production
│           ├── <library-name>.min.inc.js
│       │   └── <library-name>.min.inc.css
└── deps.cljs

File details:

  • *.inc.js and *.min.inc.js were copied from a downloaded file
  • *.inc.css and *.min.inc.css were copied from a downloaded file
  • If only minified file is available, you can only include that for JS/CSS. If no minified file is available, you can add just the normal file or create minified file using minify task. If only one file is available, you could add it to common directory, or either of specific directories.
  • *.ext.js was copied from your resources directory
  • deps.cljs was generated by boot, and required by cljs compiler

Thus, the package task basically needs to be a program doing the following:

  • download your library from a URL, verify checksum, and unzip if needed
  • move downloaded files to proper path
  • optionally minify files, if no minified files are available upstream
  • generate the deps.cljs

download task can verify the file using an MD5 checksum, to ensure the exactly same version is used to deploy the package as you intend. If the :checksum option is empty string or incorrect, and error containing the real MD5 checksum is displayed and you can use this to fix the value.

7. Install your package locally and try it out

You test the package by locally installing the package to your local Maven repository with the following command:

boot package install target

You can now use the package by depending on it on your project. To include the library in build artifact, you need to require provided namespaces from one of Cljs namespaces, e.g. (:require cljsjs.react). To check that it is working as excpected, try accessing the variables defined by the library (e.g. js/React). To test the externs, you need to compile your app using :advanced optimizations.

8. Submit a Pull Request

That's it! Thank you for making the effort! Please do open issues if you have any suggestions how to improve the packaging process or have other ideas you'd like to discuss.