How to use RequireJS optimizer in Play framework?

2020-06-20 07:57发布

问题:

As advertised, the rjs in Play can

ensure that any JavaScript resources referenced from within a WebJar are automatically referenced from the jsdelivr CDN. In addition if any .min.js file is found then that will be used in place of .js. An added bonus here is that there is no change required to your html!

However, I cannot seem to get any of that to work.

  1. I tried running my Play app in production mode, and all my webjar javascripts are still being referenced as local.
  2. I do not see the .min version of javascript files being used in production.
  3. I cannot get dependency injection to work in production mode. For example, when I want to inject jquery in my code like this

    define(['jquery'], function ($) { 'use strict'; console.log($.grep); return { sum: function (a, b) { return a + b; } }; });

I can get this to work fine in dev mode, but in production mode, the rjs failed saying

[info] Error: ENOENT, no such file or directory '/Users/khanguyen/Desktop/rjsdemo/target/web/rjs/build/js/jquery.js'
[info] In module tree:
[info]     main
[info]       app
[info] 
[info] Error: Error: ENOENT, no such file or directory '/Users/khanguyen/Desktop/rjsdemo/target/web/rjs/build/js/jquery.js'
[info] In module tree:
[info]     main
[info]       app
[info] 
[info]     at Error (native)

Obviously it is looking at the wrong location for jQuery, despite the config setup generated by Webjar

requirejs.config({"paths":{"jquery":["/webjars/jquery/1.11.1/jquery","jquery"]},"shim":{"jquery":{"exports":"$"}},"packages":[]})    }

to have the correct location for jquery.

I am using Play 2.4.0, with pipelineStages := Seq(rjs, digest) setup in my build.sbt.

Please let me know where I got it wrong.

Thanks!

回答1:

It turns out that RequireJS optimization support does not apply to all Webjars, but rather limited to Classic Webjars.

Even then, a webjar build file has to be included with the regular module in order for rjs to work.

If you look at the jQuery classic webjar, for example, you will see that a special webjar build instruction is included. Take a look at that file for your information.

Once you have identify a webjar that is RequireJS ready, you can let sbt-rjs does it thing. Here is my setup for reference:

/** javascripts/main.js **/
'use strict';

requirejs.config({
    paths:{
        'jquery': ['../lib/jquery/jquery'],
        'react': ['../lib/react/react'],
        'bootstrap': ['../lib/bootstrap/js/bootstrap'],
        'react-bootstrap': ['../lib/react-bootstrap/react-bootstrap']
    },
    shim: {
        'bootstrap': {
            deps: ['jquery']
        },
        'react-bootstrap': {
            deps: ['react']
        }
    }
});

Remember to have square brackets, otherwise CDN replacement will not happen.

For the non-requirejs ready scripts, you should not have square brackets when declaring the paths. Otherwise, rjs will refuse to build with error path fallback not supported. Of course, you won't get the CDN benefit. Just a side note, RequireJS css optimization works, too. But only limited to inlining the css, like the regular Requirejs does.