devsoap / ds-gradle-vaadin

Gradle plugin for building Vaadin Flow 10/11/12/13/14/15 apps
https://devsoap.com/gradle-vaadin-flow-plugin
Other
36 stars 13 forks source link

Pathing jar: bootRun can't resolve frontend resources #254

Closed dawiemalan closed 5 years ago

dawiemalan commented 5 years ago

Desktop (please complete the following information):

Describe the bug Created a multi-module project using Srping Boot 2.1.5.RELEASE. Run bootJar task and open in browser.

To Reproduce Steps to reproduce the behavior:

  1. Example project: https://github.com/dawiemalan/vaadin-gradle-multi-module
  2. Run Gradle task 'bootRun'
  3. Open in browser: http://127.0.0.1:8080/
  4. See error '(Reference Error) Polymer is not defined'

Expected behavior No error

Screenshots image

Artur- commented 5 years ago

I don't know Gradle enough to say where the problem is but the root cause seems to be that webjars are not on the classpath when doing gradlew bootRun. If you instead do

gradlew build
java -jar build/libs/vaadin-app-0.0.1-SNAPSHOT.jar

then it works as expected

johndevs commented 5 years ago

In https://github.com/dawiemalan/vaadin-gradle-multi-module/blob/master/vaadin-app/build.gradle#L58 you are manually setting the classpath for bootRun to only have the project files and a single custom jar that does not contain all transitive dependencies. This most likely won't work as bootRun will repackage the jar to become runnable and needs all required dependencies on the classpath (including the webjars).

The plugin can't do much if you manually set the classpath so not much that can be done here for the plugin.

dawiemalan commented 5 years ago

I can confirm running without pathingJar works. This is still a problem for us though as we need a pathingJar when running on Windows due to command line length limitation.

I will try to debug this to see what the classpath should be to make this work.

johndevs commented 5 years ago

What I quickly saw was that the task used the configurations.runtimeClasspath but all Vaadin dependencies are in the compile configuration.

For bootRun you probably want to use configurations.compileClasspath instead so it pulls in the Vaadin dependencies into the manifest.

dawiemalan commented 5 years ago

That does not work either. I seems that the Vaadin frontend resource loader does not support loading of resources from the manifest of a pathing jar.

The following solution works though (excluding webjars from the pathing jar, and adding them separately to the class path:

task pathingJar(type: Jar) {

    dependsOn configurations.runtime
    archiveAppendix = 'pathing'

    doFirst {
        manifest {

            def jars = new HashSet<String>(configurations.runtimeClasspath.files.collect {
                it.toURI().toURL().toString().replaceFirst(/file:\/+/, '/').replaceAll(' ', '%20')
            })
            jars.removeAll{it.contains('org.webjars')}
            attributes "Class-Path": jars.join(' ')
        }
    }
}

bootRun {

    dependsOn pathingJar
    doFirst {

        def webjars = new HashSet<String>(configurations.compileClasspath.files.findAll {it.canonicalPath.contains('org.webjars')})
        classpath = files(sourceSets.main.output.files, sourceSets.main.resources, webjars, pathingJar.archiveFile)
    }

    systemProperties System.properties
}

I pushed this to the example project.

Thanks for everyone's assistance with this.

dawiemalan commented 5 years ago

The solution above does not work in a multi-module project when the root build.gradle file's subprojects has a repositories closure. The webjars collection still contains the same dependencies, so it does not make sense.

Example:

subprojects {

    group "$rootProject.group"
    version "$rootProject.version"

    repositories {
        mavenLocal()
        mavenCentral()
    }
}