TLDR; I decided to write down some of the takeaways, pain points, lessons learned, etc. of building my first commercial plugin for the JetBrains plugin marketplace Spellbook. If you've built a cool plugin, or have a cool plugin idea for JetBrains IDEs and are looking for a good solution to monetize it KEEP READING...
Ever since JetBrains announced a marketplace for third party plugin developers to sell their work I've been curious to try to build something and test the waters of the JetBrains marketplace solution. I'm pretty stoked to say that I have just recently completed development of my first commercial plugin, Spellbook, and released it via the JetBrains plugin marketplace! WOOT! WOOT! 🎉 🥳!
As awesome as this milestone is for me, I must say it was not as easy as I had imagined it would be; not just to build the plugin, but also to go through the process of releasing the plugin in the marketplace. I figured I'd write some takeaways and lessons learned here, to solidify the process in my mind for the next plugin I plan to build, but also to provide some information to other devs out there who may be interested in building a plugin of their own!
Do you like Java and SWING? I hope so...
JetBrains IDEs are desktop apps built with Java and the Swing GUI toolkit. As such, any extensions to the IDE UI are also developed using Java and Swing. It appears that Kotlin is now also supported for plugin development, but I didn't try to use Kotlin, so I'm not sure how deep the support goes.
The Intellij IDE has some pretty awesome built in tools to get you going with development, including template projects, debugging tools, and IDE development instances for testing your plugin during development. I guess in theory you could use any text editor or IDE that supports Java for development, but IMO Intellij definitely provides the goods needed to quickly get going and sustain you during the development process.
You'll need to use the Intellij APIs to do most of the UI work for your plugin. Many of the components provided in the APIs are very customized implementations of various Swing components. You probably could use only Swing UI widgets to build your plugin's UI, but to ensure consistent look and feel across JetBrains IDEs, its better to use the Intellij API components whenever you can. Extending them to add additional functionality is generally pretty trivial.
Buidling with Gradle and running an IDE instance
There are two options for building your plugin in order to run it: DevKit or Gradle. Gradle is the more modern way to build plugins against JetBrains products and its use is recommended by JetBrains for new plugin projects. DevKit is the older tool used for building plugin projects and although it is outdated, it is still an option if you'd like to go that route. I chose Gradle because of JetBrains recommendation and because I'm more familiar with it. I also liked that I could manage my plugin's library dependencies alongside my plugin's build tasks.
When you create a new plugin project using the template project starter in Intellij, a plugin.xml file and a build.gradle file are generated for you. The build.gradle file is generated with a bunch of tasks that you'll need for building the plugin and also for running the plugin in an IDE instance, and deploying the plugin to the plugin repository if required. The plugin.xml file is essentially your plugin's descriptor file. It contains, among other things, declarations for any actions your plugin will execute, services your plugin will provide, and tool windows your plugin will utilize. This is also where you will specify administrative details for your plugin, (i.e. vendor info, versioning info, etc.).
You'll need to run your plugin at some point to see all the sweet features you've been building. Obviously, you'll need an IDE instance for your code to run against. Well, when the build.gradle file was created for you by Intellij's project starter, it also created a task called 'runIde'. When executed, this task launches a development instance of an IDE with your plugin code enabled. I won't go too deep into the rabbit hole here about how to control the settings for the development instance as it is quite detailed. But you can find some extremely useful info about it here.
Using other libs alongside Intellij APIs
I generally like to use Spring/Spring Boot for most of the Java development projects I work on. Spring IOC and dependency injection are usually a must for me when it comes to projects with more than a few classes and interfaces. Unfortunately, I had a good bit of trouble getting Spring to play nice when it came to the plugin platform. I especially had trouble getting beans properly initialized.
Usually with Spring Boot, you simply specify an initialization class with a main method that executes and initializes the Spring context when the application is run. Plugins don't work like that though. In order to run code at application startup for a plugin, you have to define an application component in the plugin.xml and then write an implementation class for the application component. I'm not really sure why, but no matter what I tried, I could not get a Spring context initialized in an application component. I tried both Spring Boot, and vanilla Spring, and could never get either to initialize properly. I eventually ended up moving on without dependency injection and IOC, which was definitely missed, but I managed OK without it 😉.
Documentation and examples for JetBrains specific stuff was scarce...
I had a somewhat difficult time finding good resources online supporting JetBrains plugin developers. Besides the official JetBrains SDK documentation, Intellij API documentation was scant. I couldn't find any JavaDoc'ed reference documentation for the Intellij APIs, which was kinda frustrating when I needed to reference method parameters and return types, or just to see a description of a particular class or interface. A lot of times, I ended up just having to navigate to the compiled classes in Intellij to view comments and specifics for parameters and such. This is obviously less than ideal, but still doable. And... there maybe better documentation out there, I just couldn't find it.
As far as examples and sample code of how to do stuff with the Intellij APIs, I had a little bit more luck, but still couldn't find a whole lot on the web. Here is a list of some of the resources I found online that helped me along the way while I was developing my plugin:
-
JetBrains SDK Dev Guide
- The SDK Dev Guide is definitely the place to go to get started. The Dev Guide is full of useful information about the plugin platform architecture, how to develop against specific products, testing strategies, etc. Keep in mind though, the Dev Guide has lots of useful info, but there is very little sample code or examples of how to do stuff here.
-
Plugin-Dev
- Plugin-Dev is a blog by the creator of the Bash Support and Bash Support Pro plugins for Intellij (Joachim Ansorg). He's posted some very useful articles here that provide info and example code for how to do a few vital tasks for developing quality plugins. His articles encompass things like implementing proper error reporting, plugin initialization code, and code completion. Unfortunately, there isn't a whole lot of content on this blog. But the stuff that is there is money 💵!
-
GitHub - Intellij SDK code samples
- This GitHub repo contains lots of samples for common Intellij API specific implementations. Implementing actions, working with the editor, and tool window basics are a just a few of the tasks that this blog helped me with while I was developing my plugin.
-
Baeldung
- The great Baeldung Java blog also a sweet post about writing plugins for Intellij. Though the information presented is pretty useful, its also a fairly simple plugin example. This post isn't much use if you are looking for samples of more advanced plugin implementations.
These are the resources I found on the web that helped me along the way. If you decide to build a plugin of your own, hopefully you'll be able to find a few more useful resources than I was able to.
Finally ready to release and launch 🚀!
So you've finished building and testing your awesome plugin...now what? Before JetBrains introduced the plugin marketplace, all you had to do was optionally obfuscate your codebase, build the archive file for your plugin, and upload it to the plugin repo. Easy right? The only problem with this is that the plugin you poured blood, sweat, and time into was publicly available to anybody for FREE. If you wanted to monetize your hard work, you'd need to either build your own licensing and sales solution, or find a good one to use on the web.
The JetBrains plugin marketplace has opened up the opportunity for plugin developers to make money off the hard work they've put into their product. Although the process for releasing a plugin into the marketplace still seems to be a work in progress, overall, I've been pretty impressed with everything so far.
The marketplace provides the same licensing and sales solution that JetBrains themselves use for licensing their IDE products. They provide a few different licensing options that you can take advantage of, including perpetual fallback licenses, but all of their license options appear to be subscription based (i.e. monthly or annually). I was actually a little disappointed that there was no simple perpetual license (one-time payment) option. Some products just don't fit a subscription business model, and having a one time payment option would be beneficial I think. Supposedly, they are working on offering that option for the near future though 🤞🏽.
The process for getting a plugin approved for release in the marketplace is pretty straightforward:
- Send a request to sell plugins in the marketplace.
- Upon request acceptance, JetBrains will issue you a product code for your plugin.
- Add the product code to your plugin.xml file.
- Optionally obfuscate your plugin's codebase.
- NOTE: I tried to obfuscate my plugin's codebase with ProGuard and it broke some of my plugin's functionality. I think it had something to do with the obfuscation of the Intellij API. I only tried one obfuscator, maybe another obfuscator (i.e. Zelix Klassmaster) would work better.
- Test your plugin in the demo marketplace.
- So JetBrains has gone through the trouble of standing up a test marketplace for us plugin devs to test out the marketplace solution. JetBrains staff works with you directly to ensure you have everything needed to get your plugin uploaded to the demo marketplace for testing. They even go so far as to set up a Slack channel to communicate with you while you are testing your plugin. It's pretty awesome 😀!
- Release your plugin into the wild!!!
I found the process very thorough, but not overly complicated.
So...what did I build?
After all that, you may be wondering what I built that spawned this thought dump. Well...I wrote a pretty nice post about the plugin that I just finished building and releasing in the plugin marketplace right here on DEV. Check it out!
The post kinda says it all so I'll keep it short and simple here... I built a useful notes plugin that integrates the Evernote note taking service right into your JetBrains IDE. The plugin works in ALL JetBrains IDEs (i.e. Intellij IDEA, PyCharm, WebStorm, PhpStorm, etc.) and makes for a pretty sweet code snippet tool that you can use without ever having to leave the cozy confines of your development environment.
So if you are a JetBrains user and need a boost to your productivity, check out Spellbook or the FREE but limited Spellbook Basic.
Conclusion
So I hope I haven't scared anyone away from deciding to build commercial plugins for the JetBrains plugin marketplace. Though there are some pain points, the overall experience was not bad at all, and at the end of the day there's a plugin that I worked my ass off on in the marketplace that can maybe make me a buck or two some day 🤞🏽🙏🏽. I'm super pumped that JetBrains has released this solution to support their plugin devs and look forward to building more in the future. After all, anybody who puts their all into building something deserves to be paid for it.
Cheers 🍻!
Top comments (0)