Tuesday 13 May 2014

Spring Boot + Grunt + Bower

After I wrote some comments about the integration of Grunt + Bower with Maven, it happens that I had to apply this in the context of Spring Boot.

Out of the box, Spring Boot allows you serve some static content by placing it in the resources under /static (or /public, or other locations, but let's stick to /static in this blog entry). It is all very nice if you need only to serve a few pages and files, but if you need to code a complex Javascript application and wish to use proper tools like Grunt or Bower, you may have an issue.

It seems obvious that you cannot setup your Grunt project directly under the /src/main/resources/static directory. That would mean an awkward SCM setup and an even more awkward URL pattern.

What I chose to do was to create a separate Maven module to hold my Grunt project, and to follow the guidelines I had established previously, with a few differences.

The general idea is that in development mode, the Spring Boot application would serve the static content directly from the target/dev directory of the Grunt module, and that in release mode, the target/prod directory of the Grunt module would be copied into the /src/main/resources/static directory of the Spring Boot module, and packaged together with the resulting JAR file.

Development mode

In development mode, I needed to find a way to tell Spring Boot to serve the static content from target/dev directory of the Grunt module. It is easily done by defining a ResourceHandler for the development profile only:

@Configuration
@Profile("dev")
public class DevWebConfig extends WebMvcConfigurerAdapter {

    @Autowired
    private DevSettings devSettings;

    /**
     * At development time, we want the static resources served directly
     * from the <code>myproject-web</code> project, under the <code>target/dev</code>
     * directory.
     */
    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        String staticDir = devSettings.getStaticDir();
        String prefix = "file:";
        registry.addResourceHandler("/app/**").addResourceLocations(prefix + staticDir + "/app/");
        registry.addResourceHandler("/assets/**").addResourceLocations(prefix + staticDir + "/assets/");
        registry.addResourceHandler("/vendor/**").addResourceLocations(prefix + staticDir + "/vendor/");
        registry.addResourceHandler("index.html").addResourceLocations(prefix + staticDir + "/index.html");
    }
}

Additionally, I needed a configuration object to map the application properties:

@Component
@ConfigurationProperties(prefix = "myproject.dev")
public class DevSettings {

    private String target;
    private String staticDir;

    // Getters & setters...
    
}

In the application-dev.properties, activated by the "dev" profile, I just define the following properties:

myproject.dev.target=target/dev
myproject.dev.staticDir=${user.dir}/myproject-web/${myproject.dev.target}

When I want to run the application, I just have to run the Web module in watch mode:

cd myproject-web
grunt watch

and to launch my Boot application with "dev" profile enable by adding --spring.profiles.active=dev to the program arguments.

Release mode

When the application has to be released, I active a release Maven profile in order to enable the following code in the Spring Boot POM:

<profile>
    <id>release</id>
    <build>
        <pluginManagement>
            <plugins>
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-resources-plugin</artifactId>
                    <executions>
                        <execution>
                            <id>release-web-resources</id>
                            <phase>compile</phase>
                            <goals>
                                <goal>copy-resources</goal>
                            </goals>
                            <configuration>
                                <outputDirectory>
                                   ${project.basedir}/src/main/resources/static
                                </outputDirectory>
                                <resources>
                                    <resource>
                                        <directory>
                                          ../myproject-web/target/prod
                                        </directory>
                                    </resource>
                                </resources>
                            </configuration>
                        </execution>
                    </executions>
                </plugin>
            </plugins>
        </pluginManagement>
    </build>
</profile>

I have added the myproject-web Grunt module into my dependencies in order to make sure it is ready before the copy:

<dependency>
    <groupId>${project.groupId}</groupId>
    <artifactId>myproject-web</artifactId>
    <version>${project.version}</version>
    <scope>runtime</scope>
</dependency>

And that's it! Again, in order to see the details of how the Grunt project itself is integrated with the Maven lifecyle, have a look at Grunt + Bower with Maven.

8 comments:

  1. After seeing your article I want to say that the presentation is very good and also a well-written article with some very good information which is very useful for the readers....thanks for sharing it and do share more posts like this.
    Data Science training in Chennai
    Data science online training

    ReplyDelete
  2. This is quite educational arrange. It has famous breeding about what I rarity to vouch. Colossal proverb. This trumpet is a famous tone to nab to troths. Congratulations on a career well achieved. This arrange is synchronous s informative impolites festivity to pity. I appreciated what you ok extremely here 

    Data Science Training in Indira nagar
    Data Science Training in btm layout
    Data Science Training in Kalyan nagar
    Data Science training in Indira nagar
    Data Science Training in Marathahalli

    ReplyDelete
  3. Nice post it was. I was checking constantly this blog and I was impressed!It was Extremely helpful information speciall development I care for such info a lot.
    Java training in Chennai

    Java training in Bangalore

    Java training in Hyderabad

    Java Training in Coimbatore

    Java Online Training

    ReplyDelete