πŸ“œ ⬆️ ⬇️

Compiling a JavaScript project using Maven and Closure Compiler

Good afternoon, colleagues!

I wanted to share my experience in automating the javascript build process of a project using the Google Closure Compiler and the Google Closure Library with the help of Apache Maven. Project page https://github.com/urmuzov/closure-maven , there is also documentation on each of the components of the project.

about the project


The main component of the project is the archetype. The archetype combines all other components of the project, which, if desired, can be used separately from it.
')
The archetype provides the means to solve the most common tasks in the development, namely:


There is one limitation associated with the sources and sources-no-compile profiles, they will work if python is installed on the system. This limitation is due to the execution of the depswriter.py script, which forms the deps.js file, which is necessary for the Closure Library to work. Read more about depswriter here .

Project creation


Creating a project with this archetype is very simple, just run the command (you need maven version 3):
 mvn -DarchetypeRepository=http://urmuzov.github.com/maven-repository/releases/ \ -DarchetypeGroupId=com.github.urmuzov \ -DarchetypeArtifactId=closure-package-maven-archetype \ -DarchetypeVersion=1.0.2 \ -DgroupId=my.test.group \ -DartifactId=test-artifact \ -Dversion=1.0.0-SNAPSHOT \ -Dpackage=my.test.pkg \ archetype:generate 

com.github.urmuzov:closure-package-maven-archetype:1.0.2 this command you will tell maven to generate a project based on the com.github.urmuzov:closure-package-maven-archetype:1.0.2 archetype com.github.urmuzov:closure-package-maven-archetype:1.0.2 located in the repository urmuzov.github.com/maven-repository/releases urmuzov.github.com/maven-repository/releases with the group, the artifact and the version of your project will be my.test.group , test-artifact and 1.0.0-SNAPSHOT respectively, the main package of your project is my.test.pkg .

Maven will generate this hierarchy of directories and files: ( // )
 ~$ cd test-artifact/ ~/test-artifact$ tree . β”œβ”€β”€ pom.xml └── src └── main β”œβ”€β”€ python β”‚  └── closure-library //  python    deps.js β”‚  ... β”œβ”€β”€ resources β”‚  β”œβ”€β”€ jquery-1.4.4.min.js β”‚  └── my β”‚  └── test β”‚  └── pkg //,       β”‚  └── javascript //  ,      js   ,     externs       β”‚  β”œβ”€β”€ desktop.entry.js //     β”‚  β”œβ”€β”€ mobile.entry.js //     β”‚  └── sample //  js  β”‚  └── sample.js //     └── webapp β”œβ”€β”€ index.html // html     desktop.entry.js β”œβ”€β”€ META-INF β”œβ”€β”€ mobile.html // html     mobile.entry.js └── WEB-INF β”œβ”€β”€ web.xml └── wro.xml //  wro 14 directories, 19 files 

In order to figure out what is here for what, let's try to build a project.

Build project


In order to build a project, you must run the following command. Instead of compiled you can use any of the 5 profiles.
 ~/test-artifact$ mvn -P compiled clean install [INFO] Scanning for projects... [INFO] [INFO] ------------------------------------------------------------------------ [INFO] Building test-artifact 1.0.0-SNAPSHOT [INFO] ------------------------------------------------------------------------ ... [INFO] --- closure-package-maven-plugin:1.0.2:copy (default) @ test-artifact --- [INFO] [INFO] --- closure-compiler-maven-plugin:1.0.2:compile (compile-advanced) @ test-artifact --- [INFO] simplePasses: [desktop, mobile] [INFO] == SimplePass (/home/urmuzov/test-artifact/target/closure/javascript/desktop.entry.js -> /home/urmuzov/test-artifact/target/test-artifact/desktop.js) == [INFO] file size: desktop.js -> 1588 bytes [INFO] == SimplePass (/home/urmuzov/test-artifact/target/closure/javascript/mobile.entry.js -> /home/urmuzov/test-artifact/target/test-artifact/mobile.js) == [INFO] file size: mobile.js -> 1587 bytes ... [INFO] --- gmaven-plugin:1.0-rc-5:execute (property-setup) @ test-artifact --- [INFO] SimplePass[desktop]: For simple inclusion use ${desktop.entry.js} in your HTML file [INFO] SimplePass[mobile]: For simple inclusion use ${mobile.entry.js} in your HTML file ... [INFO] --- wro4j-maven-plugin:1.3.8:run (default) @ test-artifact --- ... [INFO] /home/urmuzov/java/target/test-artifact/target/all.js (78601bytes) has been created! ... [INFO] ------------------------------------------------------------------------ [INFO] BUILD SUCCESS [INFO] ------------------------------------------------------------------------ 

I removed large chunks of logs that are not interesting from the point of view of the archetype.

The compiled project looks like this:
 ~/test-artifact$ cd target/test-artifact/ ~/test-artifact/target/test-artifact$ tree . β”œβ”€β”€ desktop.js //    desktop.entry.js β”œβ”€β”€ index.html // html    desktop.entry.js β”œβ”€β”€ META-INF //  META-INF   javasript     β”œβ”€β”€ mobile.html // html    mobile.entry.js β”œβ”€β”€ mobile.js //    mobile.entry.js β”œβ”€β”€ target β”‚  └── all.js //   all  src/main/webapp/WEB-INF/wro.xml └── WEB-INF //  WEB-INF   javasript     


Assembly Operations


During the assembly, the following operations were performed:

  1. closure-package-maven-plugin looked at all <dependency> project in search of closure-packages, found the packed Closure Library and unpacked it into a special directory for the compiler
     <dependency> <groupId>com.github.urmuzov</groupId> <artifactId>closure-library-package</artifactId> <version>${closureMaven.version}</version> </dependency> 

  2. closure-compiler-maven-plugin based on the value of the <properties>...<passes>desktop mobile</passes>...</properties> property performed two β€œsimple passes” compilations for the desktop.entry.js and mobile.entry.js files mobile.entry.js compiled them into desktop.js and mobile.js . More information about the aisles, settings and the plugin in general can be found on this page .
  3. Using gmaven-plugin , properties were generated for quickly connecting js files from html files, in this case ${desktop.entry.js} and ${mobile.entry.js} . Immediately answer the question, "why do we need these properties at all?". The thing is that when using compiled or merged profiles, you need to include only one file with compiled code, for example like this:
     <script type="text/javascript" src="desktop.js"></script> 

    And when using the sources or sources-no-compile profiles, you need to include three files, like this:
     <script type="text/javascript" src="goog/base.js"></script> <script type="text/javascript" src="deps.js"></script> <script type="text/javascript" src="desktop.entry.js"></script> 

    Therefore, in order not to rewrite / annotate these lines in the html file when changing the profile, you can use the construction ${output.closure.js.prefix}desktop${output.closure.js.suffix} , which is converted into the necessary code for different profiles. For more convenience with the help of gmaven-plugin this construction is converted into ${desktop.entry.js} , an example of the html file can be found here
  4. With wro4j, the jquery-1.4.4.min.js file is converted to all.js. This operation basically makes little sense, but if there are several files with libraries, wro can merge them, minify them, and for css also include pictures with data: url.


IDE integration


In principle, all IDEs have similar functionality for working with maven.

To quickly switch modules in NetBeans, there is a drop-down list in the toolbar, profiles in the list appear automatically:


In IntelliJ IDEA is also selected from the drop-down list in the toolbar:

But manually added:


For Eclipse, I think everything is done in the same way.

Additional Information


In principle, this should be enough to understand the use of this archetype, but if that please contact me or the documentation, which so far only in Russian:

It is also possible that someone will be interested in this project from the point of view of using all the above-listed developments in one more complex project.

Well, as they say, Fork me on GitHub!

Source: https://habr.com/ru/post/130419/


All Articles