7/27/2016 Update: As of this merged pull request, it’s now possible to install the SignalR JavaScript client via npm with the following command:

npm i -S https://github.com/signalr/bower-signalr

Alternatively, you can target the commit responsible for making this possible via SHA as follows:

npm i -S https://github.com/signalr/bower-signalr.git#b46644962828760b0d5a0ee3c6f1dbf1fab4cc04

The approach described below still works as well.

Last Updated: 7/19/2016

Up the Creek Without a Paddle

I recently needed to incorporate ASP.NET SignalR into an ASP.NET MVC / React Single Page Application (SPA) to enable bi-directional communication between the server and client via Web Sockets. This would allow the server to notify any connected clients once a decision had been made regarding a loan application. Much to my surprise, I quickly encountered a design conundrum and saw no clean means to extricate myself from this situation. Namely, no Microsoft-sponsored npm package existed for the SignalR JavaScript client.

The seasoned .NET developer in me instinctively pondered installing the SignalR NuGet package to just be done with it; however, this approach felt passé. I’d be installing both the .NET binaries and the requisite JavaScript client assets in a single shot via NuGet. Microsoft’s best practices acknowledge that NuGet is indeed the optimal vehicle for acquiring the .NET binaries; however, a package manager akin to Bower or Packman should be used for acquiring the client-side assets. Up until now, I had been using npm exclusively to acquire this asset type (libraries/frameworks such as React, Lodash, Bootstrap, etc.). I wasn’t about to disrupt the pattern for the sake of effortlessness. The last thing I wanted was to introduce a third package manager, which by the way, would be used solely for the SignalR JavaScript client.

The Life Raft

After much research and some asking around on mailing lists, a fellow Microsoft MVP (David Paquette) suggested that I look at napa. This npm module was the timely life raft which would allow me to install Microsoft’s official Bower package for the JavaScript client. This allowed me to meet my design goal of using a Microsoft-authored package, for acquiring only the JavaScript client, without introducing Bower. What follows are the steps I took to solve the problem.

Step 1: Install napa locally as a development dependency:

npm i -D napa

Step 2: Configure napa in package.json:


"napa-config": {
"cache": true,
"cache-path": "./.napa-cache",
"log-level": "info"
}

view raw

package.json

hosted with ❤ by GitHub

In this gist, napa’s package caching feature is enabled; and, all cached packages installed via napa will be dumped into a .napa-cache folder at the same level as the package.json file. By the way, this .napa-cache folder should be barred from check-ins via an entry in a .tfignore, a .gitignore, or a similar file. Finally, the logging verbosity level is set to informational messages only.

Step 3: Define an npm script:


"scripts": {
"install": "napa signalr/bower-signalr#v2.2.0:signalr"
}

view raw

package.json

hosted with ❤ by GitHub

This “install” lifecycle event script was defined such that invoking the npm i command in step 5 below will run napa. We’re specifically requesting the tagged release of “v2.2.0” in this example. This script can now be invoked as a shortcut, thus eliminating the need to commit the lengthy napa command to memory.

Step 4: Install jQuery locally as a runtime dependency:

npm i -S jquery@2.2.4

We need to install jQuery as a runtime dependency, since it’s a required component of the JavaScript client. The jQuery 3.x release is incompatible with this version of the JavaScript client. As such, the latest compatible version was targeted (2.2.4). It’s important to note that the jQuery dependency won’t be installed by napa, since napa essentially performs a git clone on the signalr-bower registry.

Step 5: Install the SignalR JavaScript client via napa:

npm i

Upon completion of this command, glance at the contents of your project’s node_modules folder. Within it, notice the new signalr folder. Its contents will mirror that of the corresponding GitHub repository, with the addition of a package.json file:


{
"name": "signalr",
"version": "0.0.0",
"description": "",
"repository": {
"type": "git",
"url": ""
},
"readme": "",
"_napaResolved": "https://github.com/signalr/bower-signalr/archive/v2.2.0.zip"
}

view raw

package.json

hosted with ❤ by GitHub

If you’ve followed along with the steps above, the completed package.json file for your project might resemble this:


{
"name": "test_app",
"version": "1.0.0",
"description": "Sample app demonstrating SignalR JS client installation with napa",
"author": "Scott Addie",
"private": true,
"license": "MIT",
"scripts": {
"install": "napa signalr/bower-signalr#v2.2.0:signalr"
},
"napa-config": {
"cache": true,
"cache-path": "./.napa-cache",
"log-level": "info"
},
"dependencies": {
"jquery": "2.2.4"
},
"devDependencies": {
"napa": "2.3.0"
}
}

view raw

package.json

hosted with ❤ by GitHub

Step 6: Add the following 2 JavaScript files to your page: jquery.js and jquery.signalR.js.

This final step could be as straightforward as including a couple script tags on the page or as complex as using a module bundler, such as Webpack, to traverse the dependency tree and to decipher the necessary dependencies. Remember, the jquery.js file is located in the node_modules\jquery folder; and, the jquery.signalR.js file is located in the node_modules\signalr folder.

Conclusion

Even though SignalR was used as the example in this blog post, this approach can be adapted to virtually any open source project available on GitHub. The absence of a package.json file, which is inherent to npm packages, no longer poses a problem. Additionally, the napa options used here only scratch the surface. Refer to the project’s documentation for a complete rundown of features.

Use this as an opportunity to consolidate package managers and to bolster your justification for using npm on “all the things”. While this napa approach may seem hacky to some, it does work quite well and continues to solve my team’s needs in the rare case that an npm package is unavailable. It’s my hope that Microsoft decides to publish an official npm package for the JavaScript client, thus rendering the rigmarole above useless. Until then, consider borrowing this technique, and let me know how it works!

1 Comment »

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s