spring-bootwro4j

Hot swapping in IntelliJ with Spring Boot and wro4j


I am currently developing the front-end/webapp for an embedded server (packaged in a .jar file, running as Tomcat) with AngularJs. The server has some API Endpoints which i want to be able to use in the front-end.

My current approach is to use webjars to load the angularjs version of my choice and then just build the application inside the webapp folder. The structure is like this:

├───src
│   ├───main
│   │   ├───docker
│   │   ├───java
│   │   │   └───com
│   │   │       └───...    
│   │   ├───resources
│   │   └───webapp
│   │       └───public
│   │           ├───css
│   │           └───js
│   │               └───controllers
└───target
    ├───classes
    │   ├───com
    │   │   └───... 
    │   └───public
    │       ├───css
    │       └───js
    │           └───controllers
    ├───generated-sources
    │   └───annotations
    ├───generated-test-sources
    │   └───test-annotations
    └───test-classes
        └───com
            └───...

The files i am editing are inside the src/main/webapp/public folder and they are getting "compiled" into the target/classes/public folder. If i want to reload a file while the server is running i have to execute Run -> Reload Changed Classes, which works reasonable fine while developing.

But since i initially come from "standalone" AngularJs development i became accustomed to having real livereload and a build chain which minifies and concatenates the js/css files for optimization (grunt, bower).

Now i already looked into wro4j and was able to set it up just fine. The one thing which is still missing there for me is the hot-reloading. Even the above approach is no longer working with wro4j and thus the only option was to recompile the whole application to see changes inside css/javascript or HTML. Is there an easy way around this?

My preferred way would be to work on the unminified/unconcatenated version while developing (running the server in debug) and only execute the whole build-chain when the application is deployed (or just Run)

What are my options?


Solution

  • What i ended up doing was maybe a bit of an overkill, but i did not find any other suitable solution.

    I built a Gruntfile.js (based on the yeoman generator for angularjs) to be able to have the livereload and build-chain features (concat, minify etc.). With this i was also able to work on the frontend without necessarily having to fire up the server. The only "dirty hack" in this file is that grunt build copies it's dist folder to the /src/main/resources/static folder, so that it gets "compiled" into the .war file.

    I used some maven plugins to be able to execute the needed commands in build time (npm install, bower install, grunt build, grunt clean)

    <plugin>
     <groupId>com.github.eirslett</groupId>
     <artifactId>frontend-maven-plugin</artifactId>
     <version>0.0.22</version> <!-- last version supported by maven 2 -->
     <dependencies>
         <dependency>
             <groupId>org.codehaus.plexus</groupId>
             <artifactId>plexus-utils</artifactId>
             <version>2.1</version>
         </dependency>
     </dependencies>
     <configuration>
         <nodeVersion>v0.10.18</nodeVersion>
         <npmVersion>1.3.8</npmVersion>
         <workingDirectory>src/main/frontend</workingDirectory>
     </configuration>
     <executions>
         <execution>
             <id>install node and npm</id>
             <goals>
                 <goal>install-node-and-npm</goal>
             </goals>
             <phase>generate-resources</phase>
         </execution>
         <execution>
             <id>npm install</id>
             <goals>
                 <goal>npm</goal>
             </goals>
    
             <configuration>
                 <arguments>install</arguments>
             </configuration>
         </execution>
         <execution>
             <id>bower install</id>
             <goals>
                 <goal>bower</goal>
             </goals>
    
             <configuration>
                 <arguments>install</arguments>
             </configuration>
         </execution>
         <execution>
             <id>npm rebuild</id>
             <goals>
                 <goal>npm</goal>
             </goals>
    
             <configuration>
                 <arguments>rebuild node-sass</arguments>
             </configuration>
         </execution>
         <execution>
             <id>grunt build</id>
             <goals>
                 <goal>grunt</goal>
             </goals>
    
             <configuration>
                 <arguments>build</arguments>
             </configuration>
         </execution>
         <execution>
             <id>npm install before clean</id>
             <goals>
                 <goal>npm</goal>
             </goals>
    
             <phase>clean</phase>
    
             <configuration>
                 <arguments>install</arguments>
             </configuration>
         </execution>
         <execution>
             <id>grunt clean</id>
             <goals>
                 <goal>grunt</goal>
             </goals>
    
             <phase>clean</phase>
    
             <configuration>
                 <arguments>clean</arguments>
             </configuration>
         </execution>
     </executions>
    </plugin>
    

    I hope this gives a broad idea for my approach. This is certainly not perfect, especially because it adds quite a bit to the build time for the whole project.