diff --git a/README.md b/README.md index a904cdb6..977ce42b 100644 --- a/README.md +++ b/README.md @@ -79,11 +79,9 @@ All configuration options follow. Note that you **RARELY** need to change anythi The plugin will automatically register this as an additional resource folder, which should then be picked up by the IDE. That will allow the app to run for example in Intellij with Tomcat. - For example the `flow-build-info.json` goes here. See [webpackOutputDirectory] - for more details. -* `webpackOutputDirectory = File(buildOutputDirectory, "META-INF/VAADIN/")`: - The folder where webpack should output index.js and other generated files. - In the dev mode, the `flow-build-info.json` file is generated here. + For example the `flow-build-info.json` goes here. +* `webpackOutputDirectory`: The folder where webpack should output index.js and other generated + files. Defaults to `build/resources/main/META-INF/VAADIN/`. * `npmFolder: File = project.projectDir`: The folder where `package.json` file is located. Default is project root dir. * `webpackTemplate: String = "webpack.config.js"`: diff --git a/src/functionalTest/kotlin/com/vaadin/gradle/AbstractGradleTest.kt b/src/functionalTest/kotlin/com/vaadin/gradle/AbstractGradleTest.kt index 41416057..cfa63779 100644 --- a/src/functionalTest/kotlin/com/vaadin/gradle/AbstractGradleTest.kt +++ b/src/functionalTest/kotlin/com/vaadin/gradle/AbstractGradleTest.kt @@ -28,6 +28,7 @@ abstract class AbstractGradleTest { */ protected val testProjectDir: File get() = testProject.root protected val buildFile: File get() = File(testProjectDir, "build.gradle") + protected val settingsFile: File get() = File(testProjectDir, "settings.gradle") /** * Runs build on [testProjectDir]; a `build.gradle` [buildFile] is expected diff --git a/src/functionalTest/kotlin/com/vaadin/gradle/MiscMultiModuleTest.kt b/src/functionalTest/kotlin/com/vaadin/gradle/MiscMultiModuleTest.kt new file mode 100644 index 00000000..19a66d9d --- /dev/null +++ b/src/functionalTest/kotlin/com/vaadin/gradle/MiscMultiModuleTest.kt @@ -0,0 +1,39 @@ +package com.vaadin.gradle + +import org.junit.Test + +class MiscMultiModuleTest : AbstractGradleTest() { + /** + * Tests https://github.com/vaadin/vaadin-gradle-plugin/issues/38 + */ + @Test + fun `vaadinPrepareFrontend waits for artifacts from dependent projects`() { + settingsFile.writeText("include 'lib', 'web'") + buildFile.writeText(""" + plugins { + id 'java' + id 'com.vaadin' apply false + } + repositories { + jcenter() + } + project(':lib') { + apply plugin: 'java' + } + project(':web') { + apply plugin: 'war' + apply plugin: 'com.vaadin' + + dependencies { + compile project(':lib') + } + } + """.trimIndent()) + testProject.newFolder("lib") + testProject.newFolder("web") + + // the vaadinPrepareFrontend task would work erratically because of dependent jars not yet produced, + // or it would blow up with FileNotFoundException straight away. + build("web:vaadinPrepareFrontend") + } +} diff --git a/src/main/kotlin/com/vaadin/gradle/VaadinFlowPluginExtension.kt b/src/main/kotlin/com/vaadin/gradle/VaadinFlowPluginExtension.kt index da312e41..b05a4569 100644 --- a/src/main/kotlin/com/vaadin/gradle/VaadinFlowPluginExtension.kt +++ b/src/main/kotlin/com/vaadin/gradle/VaadinFlowPluginExtension.kt @@ -40,9 +40,12 @@ open class VaadinFlowPluginExtension(project: Project) { /** * The folder where webpack should output index.js and other generated - * files. Defaults to `build/resources/main/`. + * files. Defaults to `null` which will use the auto-detected value of + * resoucesDir of the main SourceSet, usually `build/resources/main/META-INF/VAADIN/`. + * + * In the dev mode, the `flow-build-info.json` file is generated here. */ - var webpackOutputDirectory = File(File(project.buildDir, "resources/main"), Constants.VAADIN_SERVLET_RESOURCES) + var webpackOutputDirectory: File? = null /** * The folder where `package.json` file is located. Default is project root diff --git a/src/main/kotlin/com/vaadin/gradle/VaadinPlugin.kt b/src/main/kotlin/com/vaadin/gradle/VaadinPlugin.kt index 3a4e6704..62fcf54a 100644 --- a/src/main/kotlin/com/vaadin/gradle/VaadinPlugin.kt +++ b/src/main/kotlin/com/vaadin/gradle/VaadinPlugin.kt @@ -16,10 +16,13 @@ package com.vaadin.gradle import com.moowork.gradle.node.NodePlugin +import com.vaadin.flow.server.Constants import org.gradle.api.Plugin import org.gradle.api.Project import org.gradle.api.plugins.JavaPlugin +import org.gradle.api.plugins.JavaPluginConvention import org.gradle.api.tasks.SourceSetContainer +import java.io.File /** * @author mavi @@ -47,9 +50,15 @@ class VaadinPlugin : Plugin { } project.afterEvaluate { - val extension: VaadinFlowPluginExtension = VaadinFlowPluginExtension.get(project) + val extension: VaadinFlowPluginExtension = VaadinFlowPluginExtension.get(it) + // calculate webpackOutputDirectory if not set by the user + if (extension.webpackOutputDirectory == null) { + val sourceSets: SourceSetContainer = it.convention.getPlugin(JavaPluginConvention::class.java).sourceSets + val resourcesDir: File = sourceSets.getByName("main").output.resourcesDir!! + extension.webpackOutputDirectory = File(resourcesDir, Constants.VAADIN_SERVLET_RESOURCES) + } - // add a new source-set folder for generated stuff, by default vaadin-generated + // add a new source-set folder for generated stuff, by default `vaadin-generated` val sourceSets: SourceSetContainer = it.properties["sourceSets"] as SourceSetContainer sourceSets.getByName("main").resources.srcDirs(extension.buildOutputDirectory) } diff --git a/src/main/kotlin/com/vaadin/gradle/VaadinPrepareFrontendTask.kt b/src/main/kotlin/com/vaadin/gradle/VaadinPrepareFrontendTask.kt index 7a3211af..4ca0777f 100644 --- a/src/main/kotlin/com/vaadin/gradle/VaadinPrepareFrontendTask.kt +++ b/src/main/kotlin/com/vaadin/gradle/VaadinPrepareFrontendTask.kt @@ -21,6 +21,8 @@ import com.vaadin.flow.server.frontend.NodeTasks import elemental.json.Json import elemental.json.JsonObject import org.gradle.api.DefaultTask +import org.gradle.api.Task +import org.gradle.api.artifacts.ProjectDependency import org.gradle.api.tasks.TaskAction import org.gradle.api.tasks.bundling.War import java.io.File @@ -44,6 +46,18 @@ open class VaadinPrepareFrontendTask : DefaultTask() { // if the vaadinPrepareNode task is going to be invoked, it needs to run before this task, // in order to prepare the local copy of node.js mustRunAfter("vaadinPrepareNode") + + // make sure all dependent projects have finished building their jars, otherwise + // the Vaadin classpath scanning will not work properly. See + // https://github.com/vaadin/vaadin-gradle-plugin/issues/38 + // for more details. + val dependentProjectTasks: List = project.configurations.getByName("runtimeClasspath") + .allDependencies + .withType(ProjectDependency::class.java) + .toList() + .map { it.dependencyProject } + .mapNotNull { it.tasks.findByName("assemble") } + dependsOn(*dependentProjectTasks.toTypedArray()) } @TaskAction @@ -52,7 +66,7 @@ open class VaadinPrepareFrontendTask : DefaultTask() { Files.createDirectories(extension.frontendDirectory.toPath()) Files.createDirectories(extension.buildOutputDirectory.toPath()) - Files.createDirectories(extension.webpackOutputDirectory.toPath()) + Files.createDirectories(extension.webpackOutputDirectory!!.toPath()) // propagate build info val configFolder = File("${extension.buildOutputDirectory}/META-INF/VAADIN/config") @@ -77,7 +91,7 @@ open class VaadinPrepareFrontendTask : DefaultTask() { val builder: NodeTasks.Builder = NodeTasks.Builder(getClassFinder(project), extension.npmFolder, extension.generatedFolder, extension.frontendDirectory) - .withWebpack(extension.webpackOutputDirectory, extension.webpackTemplate, extension.webpackGeneratedTemplate) + .withWebpack(extension.webpackOutputDirectory!!, extension.webpackTemplate, extension.webpackGeneratedTemplate) .createMissingPackageJson(true) .enableImportsUpdate(false) .enablePackagesUpdate(false) diff --git a/src/main/kotlin/com/vaadin/gradle/VaadinUtils.kt b/src/main/kotlin/com/vaadin/gradle/VaadinUtils.kt index c84565a2..4ffdd5f3 100644 --- a/src/main/kotlin/com/vaadin/gradle/VaadinUtils.kt +++ b/src/main/kotlin/com/vaadin/gradle/VaadinUtils.kt @@ -47,6 +47,13 @@ internal fun getClassFinder(project: Project): ClassFinder { ?: listOf() val apis: Set = (runtimeClasspathJars + classesDirs + servletJar).toSet() + + // eagerly check that all the files/folders exist, to avoid spamming the console later on + // see https://github.com/vaadin/vaadin-gradle-plugin/issues/38 for more details + apis.forEach { + check(it.exists()) { "$it doesn't exist" } + } + val apiUrls: List = apis .map { it.toURI().toURL() } return ReflectionsClassFinder(*apiUrls.toTypedArray())