NPM Packages in Maven Central with NPM WebJars

A few months ago I launched Bower WebJars which provides a way for anyone to deploy Bower packages into Maven Central through WebJars. Since then 539 packages have been deployed! Today I’ve added NPM WebJars which is built on the same foundation as Bower WebJars but for NPM packages.

Give it a try and let me know how it goes. If you are curious about the changes to make this happen, check out the pull request.

Scaling the WebJars Project with On-Demand Bower Packages

WebJars has been my hobby project for almost 3 years and thanks to tons of help from the community the project now has almost 900 JavaScript libraries in Maven Central. In February 2015 there were over 500,000 downloads of WebJars! Up until now all of the WebJars have been manually created, deployed, and maintained. Today I’m happy to launch Bower WebJars, an on-demand service that allows users to deploy new WebJars from Bower packages.

If a WebJar doesn’t exist for the library you need, but it does exist in Bower, then select the Bower package & version and deploy it! Under the covers the Bower package is converted to a Maven package (including transitive dependency definitions), deployed to BinTray, and then synced to Maven Central. Check out the code.

Bower WebJars should work for most Bower packages but I’ve noticed a few packages that do not follow standard dependency versioning practices or do not have standard OSS licenses. So if you have any problems file an issue and we’ll see if there is something we need to fix on our side or if we can work with the package provider to resolve the issue.

We’ve started with packaging Bower libraries but it would be logical to also do this for NPM. We are discussing teaming up with the npmaven folks to do this. So stay tuned.

A huge thanks to Fred Simon (Founder at JFrog) and the rest of the folks behind BinTray. At the WTF Conference a few weeks ago, Fred helped me get a handle on the BinTray REST APIs which really kick-started this project. Since then the BinTray folks have been ridiculously helpful and instrumental in getting the Bower WebJar stuff working seamlessly.

I hope the new Bower WebJars are useful for you. Let me know what you think.

Introducing Force WebJars: Add JavaScript Libs to Salesforce With a Click

The typical method of adding JavaScript and CSS libraries (e.g. jQuery, Bootstrap, and AngularJS) to Salesforce environments is to locate a library’s download, download it, then upload it to Salesforce, then figure out the structure of the files so that you can use them from Visualforce. Using WebJars as a basis, I’ve created an easy way to add libraries to Salesforce, called Force WebJars.

Here is a quick demo:

Give it a try and let me know how it goes!

BTW: The source is on GitHub.

Presenting in SF: sbt-web & Reactive All the Way Down

This week I will be presenting twice in San Francisco at SF Scala:

  • Thursday April 10: Introducing sbt-web – A Node & WebJar Compatible Asset Pipeline for the Typesafe Platform

    sbt-web is a new web asset pipeline for Play Framework and other sbt-based frameworks. It can pull dependencies from both Node and WebJars. The pipeline covers all of the phases of client-side development, including: linting, compiling (CoffeeScript, LESS, etc), minification, concatenation, fingerprinting, and gzipping. This session will give you an introduction to sbt-web and show you how to get started using it.

  • Friday April 11: Reactive All the Way Down

    The world is going Reactive but not just for the back-end; UIs are also becoming Reactive. In this session we will walk through how to build an end-to-end Reactive application with Scala, Play Framework, Akka, and AngularJS.

Hope to see you there!

WebJars Now on the jsDelivr CDN

WebJars were created to work well with Content Deliver Networks (CDNs) and now thanks to jsDelivr there is a great public CDN hosting all of the WebJar assets! jsDelivr is “a free super-fast CDN for developers and webmasters.” What a perfect match for WebJars!

Here is how it works… Just prefix //cdn.jsdelivr.net in front of your WebJar asset URLs. That’s it! For instance, if the URL you setup to jquery.js is /webjars/jquery/2.1.0/jquery.js then to use the jsDelivr CDN the URL would be: //cdn.jsdelivr.net/webjars/jquery/2.1.0/jquery.js

Because I’m on planes a lot and sometimes have flaky internet, I still like to use my local WebJar assets when doing development. But when I’m running in production I want to switch my apps to pull the WebJar assets from the CDN. Luckily this is now really easy to setup. Here is how you would do it with Play Framework.

Step 1) Create a new controller in controllers/StaticWebJarAssets.scala containing:

package controllers
 
import play.api.mvc.Controller
import play.api.Play
import play.api.Play.current
 
object StaticWebJarAssets extends Controller {
 
  def at(file: String) = Assets.at("/META-INF/resources/webjars", file)
 
  def getUrl(file: String) = {
    val maybeContentUrl = Play.configuration.getString("contentUrl")
 
    maybeContentUrl.map { contentUrl =>
        contentUrl + controllers.routes.StaticWebJarAssets.at(file).url
    } getOrElse controllers.routes.StaticWebJarAssets.at(file).url
  }
 
}

This wrapper around Play’s Assets controller enables setting a contentUrl config parameter that turns the CDN on and off for this app.

Step 2) Update the conf/routes file to use this new controller for WebJar requests:

GET     /webjars/*file                    controllers.StaticWebJarAssets.at(file)

Step 3) Change the server-side templates to use the new StaticWebJarAssets.getUrl reverse routing wrapper so that the URLs in a page change based on the configuration. For example:

<link rel='stylesheet' href='@StaticWebJarAssets.getUrl(WebJarAssets.locate("css/bootstrap.min.css"))'>
<script type='text/javascript' src='@StaticWebJarAssets.getUrl(WebJarAssets.locate("jquery.min.js"))'></script>

Step 4) In the conf/application.conf file set the contentUrl config parameter, like:

contentUrl="//cdn.jsdelivr.net"

This will make your local development environment use the CDN. Instead you can just set this in your production config. The webjars.org site uses the following config:

contentUrl=${?CONTENT_URL}

This syntax sets the contentUrl config if a CONTENT_URL environment variable is present, otherwise it does not set it.

That is all I had to do to move the static asset handling for webjars.org to the jsDelivr CDN! Pretty awesome stuff.

A big huge thank you to jsDelivr and Dmitriy Akulov (who works for MaxCDN) for stepping up to help out WebJars!!! I emailed Dmitriy out-of-the-blue not expecting that they’d would be interested in helping WebJars but he quickly responded and helped me get everything setup in a matter of hours! With that kind of service I’m definitely looking into the MaxCDN services for my non-open source projects.

Official Support for RequireJS in WebJars

WebJars Locator now has direct support for RequireJS! For a while the WebJars Play helper library has had support for RequireJS which was great but it had a few issues and wasn’t useful outside of Play.

There is now a org.webjars.RequireJS.getSetupJavaScript(String webjarUrlPrefix) method that produces the RequireJS configuration for the WebJars you are using. If you are using only the jQuery WebJar then that JavaScript configuration looks like:

var webjars = {
    versions: { 'requirejs': '2.1.10', 'jquery': '2.1.0' },
    path: function(webjarid, path) {
        return '/webjars/' + webjarid + '/' + webjars.versions[webjarid] + '/' + path;
    }
};
 
var require = {
    callback: function() {
        // no-op webjars requirejs plugin loader for backwards compatibility
        define('webjars', function () {
            return { load: function (name, req, onload, config) { onload(); } }
        });
 
        // all of the webjar configs from their webjars-requirejs.js files
 
        // webjar config for jquery
        requirejs.config({
            paths: { "jquery": webjars.path("jquery", "jquery") },
            shim: { "jquery": { "exports": "$" } }
        });
    }
}

This sets up the paths for RequireJS modules in WebJars and pulls in any other custom configuration from the WebJar’s RequireJS config. To use this setup JavaScript with RequireJS you can add something like the following to your web page:

<script>
// the following includes the setup JavaScript directly in the page
// (in this case using Play's server-side templating)
@Html(org.webjars.RequireJS.getSetupJavaScript("/webjars/"))
 
// alternatively you can create a controller that returns the JavaScript
// and then use a src="blah" to load the setup JavaScript
</script>
 
<!-- The following can use the WebJars Locator to avoid hard-coding the full path -->
<script data-main="/assets/index" src="/webjars/requirejs/2.1.10/require.min.js"></script>

The WebJars Play library now has a new helper that wraps all that up into a nice function:

@Html(org.webjars.play.RequireJS.setup("index"))

That loads the setup JavaScript and loads RequireJS with the right data-main. Check out a full example of this with AngularJS in the Play Angular Seed Activator template.

Now using RequireJS is just normal syntax (no more webjars! prefix), like:

require(["jquery"], function(jquery) {
    console.log(jquery)
});

All of this was added very recently so make sure you are using at least webjars-locator version 0.12 and webjars-play version 2.2.1-2. Also this change may cause some incompatibilities in the WebJar RequireJS config files (webjars-requirejs.js) so if you experience strange behavior please file an issue on the WebJar.

Let me know how it goes!

WebJars Took Off in 2013

A little over a year ago I launched WebJars with the goal of bringing some simplicity and sanity to how client-side JavaScript and CSS libraries are used in the JVM ecosystem. Since then WebJars has grown to 237 libraries and around 40,000 downloads per month! Check out the stats from Maven Central:

Note: It seems that some of the download stats for September are counted as October since averaging the two produces a more likely curve.

In the past year not only has the number of WebJars grown but the number of JVM web frameworks that support WebJars has also grown. There are now nine documented approaches for using WebJars in Play Framework, Servlet 3 containers, JSF, Grails, Dropwizard, Spring MVC, Apache Tapestry, Apache Wicket, and Ring (Clojure). The community has really stepped up to help support the effort by contributing documentation, new WebJars, and version bumps.

2013 was a great year for WebJars! A huge thanks to everyone who contributed. Lets hit 100k downloads a month in 2014!

WebJars Officially Launched!

Check it out: webjars.org

Back in April I started an experiment called “WebJars” to see if it would be useful to package web libraries (JavaScript, CSS, etc) as Jar files. WebJars allow you to declaratively set client-side application dependencies just like we do for the server-side. A nice side effect of this is transitive dependencies. For instance, if you specify Bootstrap 2.2.1 as a dependency, then you automatically also get jQuery 1.8.2 as well. WebJars also make it easy to know what versions of web libraries are being used since not all web libraries use versions in their naming conventions.

Today WebJars are moving from an experiment to something real! I’ve launched the new webjars.org site and released all of the WebJars to Maven Central. The new site has a list of all the WebJars and documentation on how to use WebJars in Play 2, Servlet 3, Dropwizard, and Spring MVC apps.

I hope that WebJars help you build modern web applications! Let me know what you think of WebJars. Thanks!

WebJars in Spring MVC

Last week I announced the WebJars project that allows you to specify your web libraries (JavaScript, CSS, etc) as dependencies in your Java web applications. With some help from Jeremy Grelle I was able to get a simple WebJars Spring MVC example working.

First you will need to add the WebJars repository to your build. For Maven, just add the following to your “pom.xml” build file:

    <repositories>
        <repository>
            <id>webjars</id>
            <url>http://webjars.github.com/m2</url>
        </repository>
    </repositories>

Then add a WebJar dependency, like Twitter Bootstrap:

        <dependency>
            <groupId>com.github.twitter</groupId>
            <artifactId>bootstrap</artifactId>
            <version>2.0.2</version>
        </dependency>

Then you need to add a resource handler to Spring MVC that maps requests from a given path to files in the classpath. The WebJars are all inside of a “public” directory. If you are using Java configuration in Spring then you would do the following:

@Configuration
@EnableWebMvc
public class WebConfig extends WebMvcConfigurerAdapter {
 
  @Override
  public void addResourceHandlers(ResourceHandlerRegistry registry) {
    registry.addResourceHandler("/public/**").addResourceLocations("classpath:/public/");
  }
}

Or if you are using XML config then add the following to your Spring config:

<mvc:resources mapping="/public/**" location="classpath:/public/"/>

Then you can reference a WebJar’s assets with something like:

<link rel='stylesheet' media='screen' href='/public/stylesheets/bootstrap.min.css'>

How easy is that? Now you are managing your web libraries as versioned dependencies and you even get transitive dependencies! Check out the full source code for this example on GitHub: https://github.com/jamesward/spring_webjars_demo

Right now there are only a couple of WebJars so if you need something else then simply request a new one via a new issue on GitHub.

Please let me know what you think about this. Thanks!