LDSTechForumProjects

Using RequireJS in the Stack

Due to the rising popularity of RequireJS, we thought that we should provide support in the Stack to make it easier to use. However, due to the moving nature of RequireJS (and its not having reached a 1.0 release status), we wanted to provide support without tying ourselves into semantics of RequireJS that will probably change. That is to say this is probably not our final solution, but is a good way to get going in the mean time. With that in mind, I am including an example below of how you could possibly use Maven to generate your RequireJS files that will then be deployed as part of a war. To accomplish this, we have basically wrapped an Ant script in Maven to run require (don't get worried yet :). The concept is that we run require against the webapp/scripts directory and then place it in the target directory. Then we exclude the scripts directory from being copied when the war is generated by the Maven war plugin. In this way, we get everything that the war plugin creates (i.e. all the compiled Java class files, JSPs, web.xml, ...) but the scripts are generated by require. NOTE that while the resulting war has the combined/minified js files in it, the combined/minified js file(s) will not be utilized by Eclipse. Apparently Eclipse is too "smart" for this trickery and copies out the original files when the application is published. However, the non-minified/non-combined files are most likely what you would want to use in development anyway (or so I hope). But, when you deploy the war to other lanes it will of course use the minified/combined files.


RequireJS 0.26.0

NOTE: That you should jump to 0.26.0, as 0.25.0 issues <a href="https://github.com/jrburke/r.js/issues/16">16</a> and <a href="https://github.com/jrburke/r.js/issues/8">8</a> (which are duplicates of each other), are showstoppers for running this plugin using Rhino.

Anyway, things appear to have changed significantly between 0.24.0 and 0.26.0; not the least of which is that all of the optimization / building code is now bundled into one r.js file (normally in the format r-{version}.js as in r-0.26.0.js currently). In this way, require.js and the optimization code, r.js, can apparently be released separately - as outlined in the <a href="http://requirejs.org/docs/download.html#releasenotes">release notes</a>.

Anyway, let's use it. The configuration below is expecting that there is a requirejs folder in your application, located at src/main/requirejs (on the same level as the webapp folder), and that the app.build.js file is located in the root of the requirejs folder. Notice that this is not the norm for requirejs examples on the require site, which normally have the app.build.js in the scripts directory. To run the require optimizer in Java (Rhino), using a Maven plugin, you will need the require.js file, r-{version}.js, and the two dependencies /lib/closure/compiler.jar (if you use the closure compiler, or the uglify folder if you use uglify.js), and /lib/rhino/js.jar, which can be found <a href="https://github.com/jrburke/r.js">here</a> on Github.

- web
   - src
      - main
         - requirejs
              app.build.js
              require.js
            - dist
                 r-0.26.0.js
            - lib
                 -closure
                     compiler.jar
                 -rhino
                     js.jar
              ...
         - webapp
             - scripts
                  main.js
                  ...
             + styles
             + WEB-INF
         ...

Here is an example of the app.build.js build file (that would go in the root of your require.js folder). If you put it in a different location, be sure to modify the paths accordingly.

({
    appDir: "../webapp/scripts",
    baseUrl: ".",
    dir: "../../../target/require-web-1.0/scripts",
    //Comment out the optimize line if you want
    //the code minified by UglifyJS
    optimize: "closure",

    modules: [
        {
            name: "main"
        }
    ]
})

Next, you will need to add something like the following to your web/pom.xml to execute the require optimization via a Maven plugin. To get this to run correctly, rhino and the closure compiler must be on the classpath and then the plugin executes the r-{version).js -o command, telling the optimizer to optimize the files as outlined in the app.build.js file. The native command line result of this Maven execution is something like the following:

java -classpath C:/Projects/whatever/src/main/requirejs/lib/rhino/js.jar;C:/Projects/whatever/web/src/main/requirejs/lib/closure/compiler.jar org.mozilla.javascript.tools.shell.Main C:/Projects/whatever/web/src/main/requirejs/dist/r-0.26.0.js -o C:/Projects/whatever/web/src/main/requirejs/app.build.js

<build>
    <plugins>

        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-antrun-plugin</artifactId>
            <version>1.6</version>
            <executions>
                <execution>
                    <id>optimize</id>
                    <phase>prepare-package</phase>
                    
                    <configuration>
                       <target name="-optimize" description="Combine and minify files.">
                           <echo message="Running optimize." />

                           <property name="requirejs.dir" value="${basedir}/src/main/requirejs" />

                           <java classname="org.mozilla.javascript.tools.shell.Main" failonerror="true">
                               <classpath>
                                   <pathelement location="${requirejs.dir}/lib/rhino/js.jar" />
                                   <pathelement location="${requirejs.dir}/lib/closure/compiler.jar" />
                               </classpath>
                               <arg value="${requirejs.dir}/dist/r-0.26.0.js" />
                               <arg value="-o" />
                               <arg value="${requirejs.dir}/app.build.js" />	                              
                           </java>
                       </target>
                    </configuration>
                    
                    <goals>
                        <goal>run</goal>
                    </goals>
                </execution>
            </executions>
        </plugin>
        
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-war-plugin</artifactId>
            <configuration>
                <warSourceExcludes>**/scripts/**/*.*</warSourceExcludes>
            </configuration>
        </plugin>

    </plugins>
</build>

And now you should be up and running with RequireJS version 0.26.0. Hopefully the next release will be 1.0, and I am hopeful (as per some comments from James Burke the require.js author) that, the configuration will not change much from what is above, for the 1.0 release.


RequireJS 0.24.0

The configuration below is expecting that the requirejs folder is located at src/main/requirejs (on the same level as the webapp folder), and that the the app.build.js file is located in the root of the requirejs folder. Notice that this is not the norm for requirejs examples on the require site, which normally have the app.build.js in the scripts directory. Also note that I got the requirejs directory by going to the require site (http://requirejs.org/docs/download.html#latest) and downloading the Sample RequireJS + JQuery 1.5.x project, unzipping it, and then copying the requirejs folder in that project into my application. Anyway, your application directory might look something like the following:

+ web
   + src
      + main
         + requirejs
              app.build.js
              build
              bin
              require.js
              ...
         + webapp
              scripts
              styles
              WEB-INF
         ...

Anyway without further ado, here is an example of our app.build.js file:

({
    appDir: "../webapp/scripts",
    baseUrl: ".",
    dir: "../../../target/require-web-1.0/scripts",
    //Comment out the optimize line if you want
    //the code minified by UglifyJS
    //optimize: "none",

    modules: [
        {
            name: "main",
            //includeRequire: true,
            //exclude: ["jquery"]
        }
    ]
})

You will of course need to change the reference to require-web-1.0 to match your application name and version. Also note that in RequireJS (0.23), minification with closure was broken, but will be fixed in 0.24 as per - http://groups.google.com/group/requirejs/browse_thread/thread/a63e39dff07d5e8c. Some say that uglifyjs is better than closure at minifying files anyway, but it does not trim dead code branches, yet, like closure does. Our example above is using uglify by default, but if you are on RequireJS version 0.24 or greater, and wanted to use closure, you could do so by uncommenting the optimize: "none" line and changing it to optimize: "closure" in the app.build.js above.

Next you will need to add something like the following to your web/pom.xml

<build>
    <plugins>

        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-antrun-plugin</artifactId>
            <version>1.6</version>
            <executions>
                <execution>
                    <id>optimize</id>
                    <phase>prepare-package</phase>
                    
                    <configuration>
                        <target name="-optimize" description="Combine and minify files.">
                            <echo message="Running optimize." />
                            
                            <property name="requirejs.build.dir" value="${basedir}/src/main/requirejs/build" />
                            
                            <java classname="org.mozilla.javascript.tools.shell.Main" failonerror="true">
                                <classpath>
                                    <pathelement location="${requirejs.build.dir}/lib/rhino/js.jar" />
                                    <pathelement location="${requirejs.build.dir}/lib/closure/compiler.jar" />
                                </classpath>
                                <arg value="${requirejs.build.dir}/../bin/x.js" />
                                <arg value="${requirejs.build.dir}" />
                                <arg value="${requirejs.build.dir}/build.js" />
                                <arg value="${requirejs.build.dir}/../app.build.js" />
                            </java>
                        </target>
                    </configuration>
                    
                    <goals>
                        <goal>run</goal>
                    </goals>
                </execution>
            </executions>
        </plugin>
        
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-war-plugin</artifactId>
            <configuration>
                <warSourceExcludes>**/scripts/**/*.*</warSourceExcludes>
            </configuration>
        </plugin>

    </plugins>
</build>

Obviously don't remove any plugins already in build. I am just including the complete configuration for clarity.

This page was last modified on 26 August 2011, at 09:58.

Note: Content found in this wiki may not always reflect official Church information. See Terms of Use.