How to add generated web-client to final jar?

Hi!

I am rather new to gradle but I am currently switching from Maven to it (finally).

However, I am failing at the last step where I need to add the compiled web-client to the final server.jar under BOOT-INF/classes/static such that it is being served by the Spring Boot server.
In my despair I even considered adding those files using jar (the executable) but that’s not working anyway.

The “simple” question is: How can this be done?

Imo there are three options:

First, I could copy the files to build/classes/static and let Spring Boot package management take care of everything. The problem here is that the jar seems to get created before I can run a copy { }.

Second, The other option is to add those files after the .jar file was build using the jar command.

And third, set mobile-client/build as a static resource for the Spring Boot server. But even if I knew how to do that I would probably have the same problem again: The jar will be built before the client got generated

This here is my project structure:

web-client/     # Angular Client
  build/
  build.gradle  

server/         # Spring Boot Application
  build/
  build.gradle  

build.gradle    # The "parent" project. Works on web-client and server

And this here is the build.gradle file of the “parent”:

task buildWebApp {
    outputs.dir('mobile-client/build')
    dependsOn ':mobile-client:buildWebApp'
}

task copyWebApp {
    doFirst {
        copy {
            from 'mobile-client/build'
            into 'server/build/classes/static'
        }
    }
    dependsOn tasks.buildWebApp
}

assemble.dependsOn copyWebApp

Thanks for any help on this …

See also: related stackoverflow question

You need to shift your thinking a bit. Model your build domain and let Gradle do what needs to be done. Don’t script out actions. Rarely should you explicitly copy files yourself, and never across project boundaries. The file path of your built webapp should stay encapsulated in your web-client project and not leak into the configuration of other projects. Rather, it should be exposed as an artifact of the project. Consumption of those artifacts should be via project dependencies.

For example, in web-client/build.gradle, in addition to your regular build tasks, you would add:

configurations {
    webapp // create a configuration for the webapp
}

artifacts {
    webapp(file("${buildDir}")) { // add the build directory as the artifact of the webapp configuration - can use a specific subdirectory if desired
        builtBy(buildWebApp) // guarantees buildWebApp runs before another project tries to consume the artifact
    }
}

In your server project, you do something similar, but configure the actual concepts that matter. Don’t worry about the implementation details of where Spring Boot would want them vs. where they would be in an ordinary project:

configurations {
    staticResources // create a configuration for all static resources
}

dependencies {
   // declare a project dependency on any static resource you want to include - infinitely expandable to many modules
    staticResources project(path: ':web-client', configuration: 'webapp')
}

// include the contents of the staticResources configuration in the static folder of your resoures
// you don't do anything special for Spring Boot because you've modeled it correctly
// Spring Boot will automatically relocate these from the normal location to `BOOT-INF/classes`
processResources {
    from(configurations.staticResources) {
        into 'static'
    }
}

Hi! Thanks for helping me our here.

Unfortunately, I did not tell the full story. Before I can build the web-app, I need to build an API-Client. For that I have to literally start the server in order to export a file.

How could I encorporate an additional dependency? I’d need something like a dependsOn for the artifact I think?

These are files which, at the time, have to be located in the web-app project. It’s not ideal, I know. It would be better to push the client to an npm-repository and pull it as a package-dependency.

But at the time being I use local source files for this.

artifacts {
  webapp(file("${buildDir}")) {
    builtBy(buildWebApp)
    dependsOn generateAndCopyApiClientCode
  }
}