Royall Spence's Blog

The Racket Package Publishing Experience

Yesterday, I published my first open source Racket package. It’s a loader for .env files. Nothing fancy, but it fills an obvious gap in the language’s library offerings. The process was largely painless, but understanding a few things up front would’ve helped me along the way.

Start With The Package Template

At first, I trawled through the package index, looking for anything with passing tests and documentation. I looked at package structures, function names, documentation, and anything else that looked like an important part of packaging. This was mostly unnecessary. Running raco pkg new dotenv would’ve set up a sane default directory for my package without any extra fuss.

Making Sense Of main.rkt

When you make the package template, you’ll want to get into main.rkt right away. It has a few interesting features that I didn’t understand on first reading. The module+ forms define the modules test and main. The test module is declared twice, but the module+ form actually concatenates them into one instead of redeclaring the same module. In dotenv, I removed the test module from main.rkt entirely and put it in its own file at private/tests.rkt. Inside, I declared the test module and put my test code inside. It’s a section of imperative code that sets up some boilerplate and checks the results of functions, one after the other. Just because it’s Racket doesn’t mean it needs to be impressive functional code.

To run your tests, type raco test . in your package directory. It’ll find and execute every module called test and output the results. Don’t make the same mistake I did and type raco test and assume that the empty output indicates success. You can also run raco test -x . to exclude loading of files that lack a test module. For my modest test suite, this cuts execution time from 4s to 2s.

There’s also a curious comment ;; Code here which seems to suggest that you start programming directly inside main.rkt. You could publish a perfectly fine package like this, but I prefer to leave main.rkt exclusively for package setup boilerplate. Instead, I moved my main code out to private/dotenv.rkt. This allowed me to provide every single function from dotenv.rkt for consumption by my unit tests while only providing a much smaller quantity of API functions via main.rkt.

info.rkt is more straightforward. One small disagreement I have with the default info.rkt is that it includes rackunit-lib as a runtime dependency by default. There’s really no reason an end user would ever run unit tests, so move it to build-deps instead. Unless I am mistaken, inclusion as a runtime dependency also means rackunit-lib would get built into any executable, which sounds like pointless bloat.

Publication

The actual act of publishing is by far the easiest part. The package repository on racket-lang.org is straightforward to use. Upload your code to some git repository, Github perhaps, and the package repository will handle the rest. It’ll build the package, build the docs, host the docs, and provide test results. One caveat is that unlike Composer, it does not track versions automatically. You’ll need to manually add each new version to your package description for it to know about anything besides the latest commit.

Writing Documentation

Racket features a unique documentation system called Scribble. It not only produces pleasing HTML output, but also creates links within your own documentation and links back to the main Racket documentation. Sure, you’ll want to have something in your readme.md, but the Scribble docs will be superior. To get started, you’ll want to add scribblings/*.js, scribblings/*.html, and scribblings/*.css to your .gitignore so you don’t end up committing built documentation files like I did. The next obvious change is to add your actual name and email address to the top. I didn’t spend enough time to really understand the Scribble docs, but I was able to eventually figure out that @author[@author+email["Royall Spence" "royall@royall.us"]] would add my name and email together.

My documentation for dotenv starts off with a section with concrete usage examples as a quickstart for my users. It’s easy to do, but it’s not featured in the default Scribble: @section{Usage Examples}. Just having other Scribble docs available was the best thing to help me get started. You might consider the one I wrote for dotenv to help you get started.

Community

If you’re having trouble with your own project, the best thing to do is get on the mailing list and describe your question. Racket has the friendliest community I’ve ever seen. When you get your package published, get on Twitter and tag the official Racket account with a release announcement. They’ll retweet so the wider Racket world knows of your new package.

Particular thanks to Jack Firth whose advice served as source material for half of this post.