intellij-platform-gradle-plugin icon indicating copy to clipboard operation
intellij-platform-gradle-plugin copied to clipboard

Merge all plugin jars into single one for new plugin model

Open Undin opened this issue 4 years ago • 2 comments

IntelliJ platform 2021.2 introduced new plugin model to make support for dynamic unloading easier and more stable. Now the plugin can declare some modules inside it (slightly modified optional dependency from plugin model 1.0) with own dependencies on other plugins or modules. At the same time, the implementation of new plugin model supposes that all manifests (plugin.xml or module manifests) are located in single jar file to make classloading faster. As a result, it forces plugin writers to assemble all plugin jars into single jar file.

And it's a quite complex task for plugin writers if their plugin project consists of several Gradle modules. You can't just "hack" jar task of the root plugin module to create single jar because the current PrepareSandboxTask implementation collects all jars of plugin project into single directory that's supposed to be archived into plugin artifact and you have to come up with some workaround not to pack classes from submodules twice and at the same time not to miss jar files of external dependencies. As a result, it leads to quite weird implementations like this one in EduTools plugin or this one in Perl plugin. And strictly speaking, my implementation in EduTools plugin works by accident because we declare external dependencies for all Gradle modules including root one (where they are redundant) for some reason. But if we remove these "unnecessary" dependencies from the root module, the plugin artifact won't contain jars of external dependencies.

You may note that the platform doesn't force you to migrate to the new plugin model (at least, for now). But it's not strictly true because:

  • dynamic unloading should work properly only with the new plugin module
  • if you have a dependency on another plugin, you may face with issues like https://github.com/intellij-rust/intellij-rust/issues/7448 [^1] at any moment and, as I understand, there are only two solutions:
    • hack platform not to throw an exception in your specific case. It was done for Rust plugin to fix https://github.com/intellij-rust/intellij-rust/issues/7448 but it's not a good solution for any external plugin
    • migrate your plugin to new plugin model to provide proper dependencies

So it would be really great to simplify migration to new plugin model for all plugin writers outside of IntelliJ repository and provide proper plugin artifact creation out of the box

[^1]: Situation: you have a dependency on plugin P and you use some class C from it. At one moment, plugin P is migrated to new plugin mode and class C is moved to new module M of plugin P. After this, you will start to get exceptions like com.intellij.diagnostic.PluginException: Class `C` must be not requested from main classloader of `P` plugin [Plugin: %your.plugin.id%] without any change from your side. And the proper solution is to declare a dependency on module M but you can't do it from old plugin model

Undin avatar Oct 15 '21 10:10 Undin

Grazie Pro would also benefit from both fat jar and v2-style optional dependencies

donnerpeter avatar Feb 09 '22 09:02 donnerpeter

Hello, I created a small PR that adds option to use other Jar task (custom Gradle Jar or Gradle Shadow plugin) by passing in name of such task. With this I was able to create plugin fat jar out of 1 main and 5 supporting modules.

zielu avatar Jul 26 '22 17:07 zielu