I’ve recently spent a lot of time with my newest obsession, HTMX, and it’s seriously great. However, a challenge I face frequently is how to manage JavaScript dependencies in my ASP.NET Core applications. There’s NPM, Yarn, Gulp, Grunt, Webpack, Parcel, Rollup, and likely a hundred more package managers. Each option comes with its strengths and frustrating headaches. Luckily for HTMX users like me, the library ships ready to use without the need to transpile to a final form. In a sense, I could link directly to the artifacts and call it a day, with the glaring disadvantage of updating my HTML with every new release.

I decided to ask Twitter what options folks were using, and many pointed me to LibMan. So this post will explore what Libman is and how you can use it in your ASP.NET Core projects to manage JavaScript dependencies.

What Is Libman?

Short for Library Manager, Libman is a lightweight tool designed explicitly for client-side library acquisition. Client-side libraries are typically ready to be used by a client, and some examples include Bootstrap.js, JQuery, Vue, d3, and HTMX. Libman also supports some of the more popular CDNs that can host JavaScript libraries: CDNJS, jsDelivr, and unpkg. LibMan will retrieve specified libraries and place them in a target location. The tool is for developers who work with final assets and don’t need a build pipeline.

To be clear, LibMan is not a package management system like NPM or Yarn, and it doesn’t have the same facilities as WebPack, Rollup, or Parcel. As a result, it cannot replace those tools but offers folks a more straightforward choice.

Installing LibMan

To get started with LibMan, you’ll first need .NET installed. Once the SDK is installed and the dotnet CLI is available, you can run the following command in a terminal. Note, you can only install LibMan globally. Local installs (without -g) will fail..

dotnet tool install -g Microsoft.Web.LibraryManager.Cli

Once you’ve installed the tool, you can test that it’s installed correctly and accessible by typing the following.

libman --version

Now you should be ready to start using LibMan in your ASP.NET Core projects.

LibMan and ASP.NET Core projects

You’ll need to start with an ASP.NET Core application with a wwwroot folder. Typically you’ll have a public content directory with folders for css, js, and lib. Where your assets go isn’t essential, but typically external assets are placed in the lib folder under wwwroot.

You’ll want to run the following command from the root of the web project to initialize LibMan.

libman init

You can change the DefaultProvider value from cdnjs to either unpkg or jsDelivr. We’ll also be able to specify the provider when adding libraries. After running libman init, you should see a new libman.json file.

{
  "version": "1.0",
  "defaultProvider": "cdnjs",
  "libraries": []
}

You’ll notice the libraries array is empty. So let’s add a new asset! Type the following command into your terminal, still being at the root of your web project.

libman install htmx

LibMan will ask you where you’d like to place the assets; by default, it will be wwwroot/lib/<library name>. Feel free to change the target or hit enter.

➜ libman install htmx
Destination [wwwroot/lib/htmx]: 
wwwroot/lib/htmx/ext/ajax-header.js written to disk
wwwroot/lib/htmx/ext/ajax-header.min.js written to disk
wwwroot/lib/htmx/ext/class-tools.js written to disk
wwwroot/lib/htmx/ext/class-tools.min.js written to disk
wwwroot/lib/htmx/ext/client-side-templates.js written to disk
wwwroot/lib/htmx/ext/client-side-templates.min.js written to disk
wwwroot/lib/htmx/ext/debug.js written to disk
wwwroot/lib/htmx/ext/debug.min.js written to disk
wwwroot/lib/htmx/ext/event-header.js written to disk
wwwroot/lib/htmx/ext/event-header.min.js written to disk
wwwroot/lib/htmx/ext/include-vals.js written to disk
wwwroot/lib/htmx/ext/include-vals.min.js written to disk
wwwroot/lib/htmx/ext/json-enc.js written to disk
wwwroot/lib/htmx/ext/json-enc.min.js written to disk
wwwroot/lib/htmx/ext/method-override.js written to disk
wwwroot/lib/htmx/ext/method-override.min.js written to disk
wwwroot/lib/htmx/ext/morphdom-swap.js written to disk
wwwroot/lib/htmx/ext/morphdom-swap.min.js written to disk
wwwroot/lib/htmx/ext/path-deps.js written to disk
wwwroot/lib/htmx/ext/path-deps.min.js written to disk
wwwroot/lib/htmx/ext/preload.js written to disk
wwwroot/lib/htmx/ext/preload.min.js written to disk
wwwroot/lib/htmx/ext/rails-method.js written to disk
wwwroot/lib/htmx/ext/rails-method.min.js written to disk
wwwroot/lib/htmx/ext/remove-me.js written to disk
wwwroot/lib/htmx/ext/remove-me.min.js written to disk
wwwroot/lib/htmx/htmx.js written to disk
wwwroot/lib/htmx/htmx.min.js written to disk
Installed library "htmx@1.6.1" to "wwwroot/lib/htmx"

After the installation, LibMan will update our libman.json file with the installed library.

{
  "version": "1.0",
  "defaultProvider": "cdnjs",
  "libraries": [
    {
      "library": "htmx@1.6.1",
      "destination": "wwwroot/lib/htmx"
    }
  ]
}

Now we can serve these assets when and where we need them. Great! When newer versions of a library are released, we can use the update command to fetch the latest version.

libman update htmx

Great! Most folks can stop here, but you can check out the next section if you don’t want to check-in assets into source control.

Restore Assets on Build with LibMan

I recommend checking in the JavaScript library asset files into source control, but I can see why folks wouldn’t want to do that. It can be a lot of additional noise to see all those JavaScript files in a pull request. I’m happy to tell those folks there’s a package for that for folks who would like to resolve assets at build time!

Install the following NuGet Package as part of your web project.

dotnet add package Microsoft.Web.LibraryManager.Build

Once installed, you should see the following message in your build output (between all the other build messages).

1 libraries restored in 0.2 seconds

If you’re concerned about restorations being slow, don’t be. Restores are loaded and cached on your local machine. Caching should help keep your local and remote builds feeling snappy with limited overhead.

Conclusion

LibMan is an excellent alternative for folks trying to avoid the complexity of the Node ecosystem. You can keep all your client-side libraries up to date with a few commands. LibMan is perfect for me, and it all just works. Let me know if you use LibMan and what your experience has been. As always, thank you for reading, and I hope you learned something new.

References