Working in a large monorepo with a long-term project has its oddities. Every time I started a new feature, I turned from a developer into a “file manager.” Create a folder, organize files, write boilerplate code, copy imports from a neighbor file, and don’t forget to clean up the mess… Each action only takes a minute, but over a week, it really adds up. Most importantly, this routine drains energy. Instead of keeping my focus on business logic, I wasted my attention on mechanical copy-pasting and checking paths.
At first, I wanted to solve the problem the “easy way” - by configuring standard File and Code Templates in WebStorm. But I quickly hit a wall: templates can’t handle paths flexibly, they can’t properly convert MyComponent to my-component inside the code, and sharing settings with the whole team is a nightmare. The tool that was supposed to help started to annoy me.
Then I thought: “What if I stop configuring the IDE and start programming it?” This thought led me to create my own plugin. And you know what? It wasn’t as scary as people say. I didn’t have to learn Java or read manuals for years. It turned out that for a Frontend developer, modern Kotlin looks suspiciously like TypeScript.
In this article, I’ll share how I went from a simple desire to make a template to building a full-fledged tool, and why you should stop tolerating a bad Developer Experience (DX).
The Problem: Infinite Copy-Paste and “Blind” Navigation
Dozens of developers work on our project in a single repository. This imposes strict restrictions on code style. For example, any React component is always separated into a presentation part (view.tsx) and logic (index.tsx), and styles lie nearby in a separate file. Forgot to wrap the component in memo? Props are not destructured in the first line? You won’t pass Code Review.
The Trap of Simple Solutions: Why File Templates Failed
When I finally got fed up with the routine, I dug into the settings. The ideal scenario in my head looked like this: one click — and I generate the whole bunch of files (component, view, styles).
It turned out WebStorm can do this! Deep in the settings (Settings -> Editor -> File and Code Templates), there is a feature to create not just files, but hierarchies via “Child Templates”.
I quickly set up a configuration:
- Parent template (Standard TSX Component):
- Name:
React Component Folder - Extension:
tsx - File Name: ${NAME}/index
- Code:
- Name:
import { memo } from 'react'
import View from './view'
type Props = {}
export const ${NAME} = memo((props: Props) => {
const {} = props
return <View />
})
- Child files (via
Create Child Templatebutton):- View (view.tsx):
- File Name: ${NAME}/view
- Extension: tsx
- Code:
- View (view.tsx):
import { memo } from 'react';
import styles from './styles.module.less';
type Props = {};
export default memo((props: Props) => {
return <div className={styles.container}></div>;
});
- Styles (styles.module.less):
- File Name: ${NAME}/styles.module
- Extension: less
- Code: (
empty file)
Voila! Victory? I choose the template, enter the folder name and file name, and the IDE creates the folder and organizes the files itself. I felt like an automation genius… for exactly two days.
The euphoria vanished when I faced the harsh reality of Apache Velocity (the IDE template engine):
- Naming problems: Converting
MySuperComponenttomy-super-componentfor the import paths and back toMY_SUPER_COMPONENTfor constants inside the template is painful. You have to write terrible macros that break constantly.
- Limited access to file structure: Templates can only create files relative to where you clicked. If I need to create files in folders of different modules at the same time, templates are powerless.
- Team synchronization: How do I share these settings? "Export settings to ZIP and import, but don't mix up the checkboxes"? This doesn't work in a team of 20 people.
- Fragility: The final blow was a WebStorm update. After another IDE update, my configured Child Templates simply disappeared.
Why Not AI?
A fair question: why write code by hand in the age of AI? Why not let GitHub Copilot or JetBrains AI create the files? I actively use AI assistants in my work, but for infrastructure tasks, they lose for 3 reasons:
- Determinism: AI is a probabilistic model. It might generate the correct file structure 9 times out of 10. But on the 10th time, it will "hallucinate" an extra import or mix up the folder. With a strict style guide, I need a tool I can trust 100%, not one I have to double-check. A plugin doesn't "think" or "guess", it follows a strict algorithm.
- Context and Speed: To make AI create a complex structure in different modules, I need to write a detailed prompt: "Create component X in the domain, then the implementation in web, use these paths...". This takes longer than right-clicking
New Feature. Plus, AI doesn't always see the full depth of the monorepo the way PSI (the IDE index) does. - Standards: It's hard to force 20 developers to use the exact same prompt. But it's easy to give them one button that guarantees the same result for everyone.
Maybe Write a Plugin?
When it became clear that standard templates wouldn't cut it, there was only one path left - to write my own tool. The idea of creating a custom IDE plugin was intimidating at first. In the frontend world, we tend to think IntelliJ development is reserved for hardcore Java engineers. Even the JetBrains documentation warns you right away that you probably don't need this, offering
Honestly, I was scared of diving into an unfamiliar stack. I'm used to TS, NPM, and Webpack, and here I saw Gradle, JVM, and a complex SDK. But the desire to automate the routine was stronger than the fear.
Quick Start: Plugin Template
My first pleasant surprise was the
You don't need to manually configure the build, write manifests, or figure out CI/CD. You just clone the repo, and you are ready to go. You have a working Hello World, configured Gradle, and GitHub Actions. This saved me days, maybe weeks.
Kotlin is Just Like TypeScript (Well, Almost)
My second fear was the language. Plugins are written in Java or Kotlin. For someone who writes modern TypeScript, the transition to Kotlin was surprisingly smooth.
The syntax is very similar:
- The same
val / varinstead ofconst / let. - Lambdas and higher-order functions work just the same.
- Strict typing, which we are used to in TS, works even more reliably here.
Basically, if you are comfortable with TypeScript, you can read and write Kotlin on the very first evening. The main difficulty was not the language.
Documentation and AI Help
The most difficult stage was studying the IntelliJ Platform SDK. The documentation at JetBrains is huge, but the learning curve is steep. To understand which class is responsible for "right-clicking on a file," you can spend hours on forums.
Here, AI agents came to the rescue. I didn't use them to write business logic, but as a smart search engine for the API. Queries like "How to show notification balloon" saved a lot of time. Instead of a digging through docs, I got a code example, and then I figured it out myself.
Implementation: From Templates to Smart Assistant
During development, I identified key tasks that would solve the team's biggest pains. The main goal was for the tool to feel native part of the IDE, and not some alien script. I won't go deep into specific APIs - what matters is what the IDE allows you to do.
1. Smart Generation
In the IntelliJ world, any action is an Action. To add an item to the right-click menu, you just need to extend the AnAction class.
But I didn't want to clutter the menu. Why do I need a "Create Component" button if I clicked on a folder with business logic or translations? Here, the flexibility of plugins shines. The action class has an update() method, which is called every time before showing the menu. I added simple logic:
- Am I in the
domainfolder? - Does the file
*.test.tsnot exist here yet?
If yes - show the menu item. If not - hide it. The developer sees only the tools that are relevant right here and right now.
The generation itself is also smarter. Standard templates can't go outside the current folder, but our architecture assumes splits code by modules and often uses injection of platform implementations of business logic.
So, I implemented a "smart" action. The developer enters the entity name once, and the plugin:
- Creates an interface file in
domainwith boilerplate for injection. - Calculates paths to
webandmobilemodules. - Creates corresponding implementation files in those folders.
- Corrects file and class names (kebab-case for files, PascalCase for classes).
Important nuance: I didn't hardcode the templates inside Kotlin classes. This would make the plugin a "black box." Instead, the plugin registers layouts in the standard IDE settings. This gives us flexibility: any team member can go into the settings, correct the code style in the template, and the plugin will immediately pick up the changes.
2. i18n Navigation
The second problem is “dead” text. We use a custom hook useLocalizedString(‘key’) and a component <LocalizedText href=’key’ />. To the IDE, this is a meaningless string
To bring them to life, I used PsiReferenceContributor. This API lets you tell the IDE: “Look, if you see a string inside this hook, treat it as a link to a JSON file”. Now, holding Ctrl/Cmd, I can click on the translation key and jump to the right localization file. No more manual searching.
Once I Started, I Couldn’t Stop
As soon as the entry barrier was gone and the basic framework was ready, I got carried away. It turned out that having access to the AST (Abstract Syntax Tree) of the code lets you do wonders:
- Auto-mocks: The plugin generates mock data for tests based on the interface.
- Wiring in tests: When creating a test file, the plugin finds the necessary mocks and adds imports automatically.
- Wrappers (HOCs): An action that wraps the selected component in an analytics HOC and passes the required props.
All these are routine actions, each of which saves dozens of seconds and helps keep focus on the main task.
Distribution
Delivering the tool to the team was simple. No sending .jar files in Slack. The plugin is published on the JetBrains Marketplace. For a new developer, onboarding now looks like this: “Install WebStorm, download our plugin — and you’re ready to go.”
Summary: Developer Experience is in Your Hands
Was it worth it? Spending time studying infrastructure, setting up the environment, and coding in a “foreign” language to save a couple of minutes a day?
Absolutely.
If you count pure time, the savings might not look huge — maybe an hour or two a month. But the real value is not in minutes, but in flow. When the tool works predictably and fast, the micro-annoyances that build up during the day disappear. I stopped thinking about which folder to put the file in or what to name it. I press a button, and the IDE does exactly what is needed.
This experience taught me two things:
-
There are no boundaries. The division into frontend and backend (or tooling) often exists only in our heads. If you understand algorithms and know how to Google (or ask AI), you can build tools for any platform. Kotlin turned out to be friendly, and the IntelliJ Platform is powerful.
-
The IDE is a constructor. We are used to putting up with inconveniences, waiting for the vendor to release an update. But WebStorm, like VS Code, is a platform. If you don’t like how your hammer works — you can rebuild it.
-
If you work on a large project and feel like you are drowning in routine — don’t be afraid to spend time building your own plugin. It’s an investment that pays off every single day when you come to work and just write code, instead of fighting with the file system.
Written by
Ready to shape the future of social discovery? Explore your dream career at SDG and join a team that’s redefining innovation - your next big opportunity is just a click away! 👉
