vaadin/vaadin-gradle-plugin

stats.json not packaged to WAR

mvysny opened this issue · 8 comments

Currently the stats.json is generated into the build/vaadin-generated/META-INF/VAADIN/config/ folder, along with flow-build-info.json. However, stats.json is generated after Gradle copies stuff from build/vaadin-generated to build/resources/main, therefore stats.json file is not packaged. Vaadin is able to run without stats.json both in dev and in production mode, however certain things will not work (for example PolymerTemplate and LitTemplate).

Desktop (please complete the following information):

  • OS: [e.g. Windows, Ubuntu, iOS]
  • JDK version: [e.g. 8,9,10,11,12]
  • Gradle version: 6.8.3
  • Vaadin Plugin version: 0.20.0.0.alpha3

To Reproduce
TBD once the Gradle plugin 0.20.0.0.alpha3 is released.

Expected behavior
The stats.json is generated to build/resources/main which will then cause Gradle to package it correctly to WAR.

Additional context
The incorrect path can be seen in webpack.generated.js:

const mavenOutputFolderForResourceFiles = path.resolve(__dirname, 'build/vaadin-generated/META-INF/VAADIN');
...
const confFolder = path.resolve(mavenOutputFolderForResourceFiles, 'config');
const serviceWorkerPath = 'sw.js';
// file which is used by flow to read templates for server `@Id` binding
const statsFile = `${confFolder}/stats.json`;
  • The PluginAdapterBase.servletResourceOutputDirectory() returns build/vaadin-generated/META-INF/VAADIN
  • The PluginAdapterBase.webpackOutputDirectory() returns build/resources/main/META-INF/VAADIN/webapp/

Currently the flow-build-info.json is generated in build/vaadin-generated/META-INF/VAADIN/config/ (that is good); however is there a way to force stats.json to be generated elsewhere (in build/resources/main/META-INF/VAADIN/config/stats.json)?

  • Things to watch out for
  • Fix in flow
  • Fix in the Gradle plugin
  • Fix the IT tests to assert on the presence of the stats.json file

The reason that we can start the project without the stat.json is probably becaus Fusion adds the bundle into the index.html <script defer="defer" src="VAADIN/build/vaadin-bundle-433c776b2a8a219d4f73.cache.js"> which I guess is loaded when not using useDeprecatedV14Bootstrapping as then I guess we might use the IndexHtmlRequestHandler instead of the BootsrapHandler.

There is also a deeper issue here: the WAR file will package an older version of flow-build-info.json. I think it goes like this:

  • vaadinPrepareFrontend is run, which creates a first version of flow-build-info.json
  • Then, stuff is copied from build/vaadin-generated to build/resources/main
  • Then, vaadinBuildFrontend task is run, which modifies flow-build-info.json and creates stats.json.
  • However, they will be ignored by Gradle war plugin (and jar and Spring plugins) since they only copy stuff from build/resources/main.

So should the files just be directly created to build/resources/main instead of creating it to build/vaadin-generated?

Maybe.... I'm trying to remember the reason why we're using build/vaadin-generated instead of creating stuff simply in build/resources/main...

A fix could either be to generate stuff directly to build/resources/main, or alternatively I wonder what would happen if we configure Gradle to run processResources AFTER vaadinBuildFrontend like this:

project.tasks.getByName("processResources").mustRunAfter("vaadinBuildFrontend")

Let me investigate on this further.

There's some info on this here: #44

Uh-oh, using project.tasks.getByName("processResources").mustRunAfter("vaadinBuildFrontend") fails right away with

:classes
\--- :processResources
     \--- :vaadinBuildFrontend
          \--- :classes (*)

The vaadinBuildFrontend task needs to depend on classes, to be able to analyze e.g. @CssImport annotations used by the project.

But maybe it could be enough to only depend on compileJava according to https://docs.gradle.org/current/userguide/java_plugin.html? Not good - what about compileKotlin and possibly other tasks hooked to classes?

Generating token file to build/resources/main before processResources doesn't work: the processResources will delete the build/resources/main folder. Maybe run vaadinPrepareFrontend after processResources?

That works! However, running Intellij+Tomcat will invoke Gradle to build the war file, which in turn will invoke processResources, thus removing the flow-build-info.json file produced by vaadinPrepareFrontend? Investigate.

Just as I suspected: Intellij+Tomcat ignores stuff present in build/resources/main, making Vaadin fail that it can't locate pom.xml in tomcat/bin folder. A separate source folder is therefore needed.

The only way forward is to make vaadinPrepareFrontend to generate the token file to build/vaadin-generated as before, but then make vaadinBuildFrontend work in the scope of build/resources/main.