Creating Packages - cljsjs/packages GitHub Wiki
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
- Best place is the official browserified files from npm package, often under
dist/
, these can be downloaded from unpkg, e.g. https://unpkg.com/[email protected]/dist/ - Links from libraries homepage
- Cdnjs
- Archive file from Github
- As last option, one can download the source and build browserified code using
webpack
or other tools (using official files is less error prone and simpler).
3. Create a directory structure for the package
Use the library's name as the top-level directory and create the following directory structure:
└── resources
└── cljsjs
└── <library-name>
└── common
Folder name, Cljsjs artifact name and foreign-lib names should match the librarys name e.g. on npm.
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.
build.boot
and README.md
files
5. Add Consult existing library packages for examples. Files can be copied from existing packages to get started.
build.boot
5.1 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.
If the library depends on other JS libs packaged on Cljsjs, you should also declare the dependencies.
README.md
5.2 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
package
task
6. Writing the 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. So the command boot package show --fileset
will output something like:
├── 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 tocommon
directory, or either of specific directories. *.ext.js
was copied from your resources directorydeps.cljs
was generated by boot-cljsjsdeps-cljs
task or copied from resource-paths
Thus, the package task basically needs to be a program doing the following:
- download your library from a URL, and unzip if needed
- move downloaded files to proper path
- optionally minify files, if no minified files are available upstream
- generate the deps.cljs
- call validate task (this will validate checksums, deps.cljs file and that the JS files can be parsed by Google Closure)
deps-cljs
only knows how to generate deps.cljs
file for simple single file libraries. If you need something else, consult for example following examples:
- Simple deps.cljs: https://github.com/cljsjs/packages/blob/master/preact-compat/resources/deps.cljs
- Additional entries generated using custom task: https://github.com/cljsjs/packages/blob/master/highlight/build.boot#L25-L41
validate-checksums
can check file checksums against boot-cljsjs-checksums.edn
file in the working directory.
Task will automatically ask the user if the file should be updated if the checksums don't match with the current checksum file. Checksum validation ensures that CI will download exactly the same files as intended. (And also forces the user to run package task locally, to validate it works.)
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.
(optional) Update CODEOWNERS file
If you are prepared to provide support (i.e. prepared to provide updates when package updates or users ask for them) for the package, you can add the package folder and your Github handle to CODEOWNERS -file.