# \[Beta\] Easier workflow for making plugins

**URL:** <https://discourse.joplinapp.org/t/beta-easier-workflow-for-making-plugins/17472>\
**Category:** Plugins\
**Created:** [19 May 2021 23:04 UTC](https://discourse.joplinapp.org/t/beta-easier-workflow-for-making-plugins/17472 "2021-05-19T23:04:19Z")\
**Posts on this page:** 13\
**Page:** 1

<div class="post-metadata">

**Author:** ![thejohnfreeman](https://yyz2.discourse-cdn.com/flex028/user_avatar/discourse.joplinapp.org/thejohnfreeman/32/7547_2.png) [@thejohnfreeman](https://discourse.joplinapp.org/u/thejohnfreeman)\
**Post date:** [19 May 2021 23:04 UTC](https://discourse.joplinapp.org/t/beta-easier-workflow-for-making-plugins/17472/1 "2021-05-19T23:04:20Z")

</div>

Right now when you write a Joplin plugin, the recommendation is to use a Yeoman generator that spits out a bunch of boilerplate, including a directory of type declarations. I've written a package that you can depend on instead, which exports both those type declarations and two binaries that can build (the `dist` directory) and pack (the `publish` directory) your plugin.

> **[@thejohnfreeman/joplin-plugin](https://www.npmjs.com/package/@thejohnfreeman/joplin-plugin)**
>
> Types and tools for Joplin plugins

This is the _first_ time I'm announcing this. I've tested it on 3 plugins: the [table of contents plugin](https://github.com/laurent22/joplin/tree/dev/packages/app-cli/tests/support/plugins/toc/) from the tutorial, the [backlinks plugin](https://discourse.joplinapp.org/t/automatic-backlinks-with-manual-insert-option/13632) posted on these forums, and the [go-to-item plugin](https://discourse.joplinapp.org/t/go-to-tag-notebook-or-notes-via-links-and-by-highlighting-text-in-editor/12731) also by @ambrt. That means I cannot _promise_ this package will work out-of-the-box for you, but I believe there's a good chance it will, and if it doesn't, I'll be happy to help make it do so.

I plan to publish new versions of this package for each new release of Joplin. I've published both versions 1.8.5 and 2.0.1 for now. They have the same contents, but you can choose which major version you want to depend on.

I'm hoping that this will eventually be _the_ way to write Joplin plugins, because I find it much more conventional in the JavaScript ecosystem. I won't need Yeoman to scaffold a plugin, the repositories will have far less boilerplate cluttering them, and updating is just a simple dependency change.

---

<div class="post-metadata">

**Author:** ![laurent](https://avatars.discourse-cdn.com/v4/letter/l/ce7236/32.png) [@laurent](https://discourse.joplinapp.org/u/laurent)\
**Post date:** [20 May 2021 08:26 UTC](https://discourse.joplinapp.org/t/beta-easier-workflow-for-making-plugins/17472/2 "2021-05-20T08:26:44Z")

</div>

That's very good, thanks for sharing. How do you handle manifest.json at the moment? Is that a file that the user needs to manually create and add to the /src directory?

I think your approach is good but on the other hand there's still boiler plate that needs to be created - folders to create, scripts to add to package.json, etc. Perhaps a mixed approach with Yeoman to create the required files and directories, and your package to handle the Joplin API and building scripts might be better.

---

<div class="post-metadata">

**Author:** ![rxliuli](https://yyz2.discourse-cdn.com/flex028/user_avatar/discourse.joplinapp.org/rxliuli/32/4083_2.png) [@rxliuli](https://discourse.joplinapp.org/u/rxliuli)\
**Post date:** [20 May 2021 08:30 UTC](https://discourse.joplinapp.org/t/beta-easier-workflow-for-making-plugins/17472/3 "2021-05-20T08:30:14Z")

</div>

It looks good. The way to improve efficiency is constantly changing. Boilerplate files are something from the "last century". Vue 2 is still doing this. Vue 3 and cra have already encapsulated it into high-level commands.

Development stage: Manually copy the template =\> CLI that automatically generates template files =\> Eliminate template files by packaging and customizing the CLI

---

<div class="post-metadata">

**Author:** ![laurent](https://avatars.discourse-cdn.com/v4/letter/l/ce7236/32.png) [@laurent](https://discourse.joplinapp.org/u/laurent)\
**Post date:** [20 May 2021 09:26 UTC](https://discourse.joplinapp.org/t/beta-easier-workflow-for-making-plugins/17472/4 "2021-05-20T09:26:41Z")

</div>

I've considered creating a custom CLI tool, but the advantage of Yeoman is that you don't need to. It already handles all the basic operations you might need to create files from template, create directories, etc.

---

<div class="post-metadata">

**Author:** ![rxliuli](https://yyz2.discourse-cdn.com/flex028/user_avatar/discourse.joplinapp.org/rxliuli/32/4083_2.png) [@rxliuli](https://discourse.joplinapp.org/u/rxliuli)\
**Post date:** [20 May 2021 09:44 UTC](https://discourse.joplinapp.org/t/beta-easier-workflow-for-making-plugins/17472/5 "2021-05-20T09:44:17Z")

</div>

But it can only generate, and cannot be responsible for packaging, testing, and publishing operations. Even if you say that these commands can be included in npm scripts, it is very bad that complex tools such as webpack are exposed to users (people who develop plug-ins) (Also including the upgrade mentioned by @thejohnfreeman above will be very complicated). In contrast, vite is currently the best cli, achieving a suitable balance between packaging and customization.

---

<div class="post-metadata">

**Author:** ![thejohnfreeman](https://yyz2.discourse-cdn.com/flex028/user_avatar/discourse.joplinapp.org/thejohnfreeman/32/7547_2.png) [@thejohnfreeman](https://discourse.joplinapp.org/u/thejohnfreeman)\
**Post date:** [20 May 2021 13:41 UTC](https://discourse.joplinapp.org/t/beta-easier-workflow-for-making-plugins/17472/6 "2021-05-20T13:41:32Z")

</div>

Sure. I think there's room for a `joplin-plugin-new` command in my dependency to spit out the boilerplate, but aside from the manifest, it is no more than is required for any other TypeScript/JavaScript package, unlike the current approach.

There's only one folder to create (`src`), and the user doesn't _have_ to add any scripts. I just provide some tools that make those scripts easy should they choose to add them.

---

<div class="post-metadata">

**Author:** ![roman\_r\_m](https://yyz2.discourse-cdn.com/flex028/user_avatar/discourse.joplinapp.org/roman_r_m/32/3297_2.png) [@roman\_r\_m](https://discourse.joplinapp.org/u/roman_r_m)\
**Post date:** [20 May 2021 13:44 UTC](https://discourse.joplinapp.org/t/beta-easier-workflow-for-making-plugins/17472/7 "2021-05-20T13:44:23Z")

</div>

Looks neat! Haven't checked it in detail yet but one feature I think would be nice is somehow forcing versions in package.json and manifest.json to always be in sync.

---

<div class="post-metadata">

**Author:** ![thejohnfreeman](https://yyz2.discourse-cdn.com/flex028/user_avatar/discourse.joplinapp.org/thejohnfreeman/32/7547_2.png) [@thejohnfreeman](https://discourse.joplinapp.org/u/thejohnfreeman)\
**Post date:** [20 May 2021 13:49 UTC](https://discourse.joplinapp.org/t/beta-easier-workflow-for-making-plugins/17472/8 "2021-05-20T13:49:15Z")

</div>

How about generating the `manifest.json` from the contents of `package.json`?

- `manifest_version`: Must always be `1`.
- `name`: Take the `name` field from `package.json`.
- `version`: Take the `version` field.
- `app_min_version`: Take the version of the `joplin-plugin` dependency.
- `description`: Take the `description` field.
- `author`: Take the `author` field.
- `keywords`: Take the `keywords` field.
- `homepage_url`: Take the `homepage` field.
- `repository_url`: Take the `repository` field.

I like this approach because it completely eliminates the extra boilerplate, so I'm going to use it. I'll make it so these are the default values, and they can be overridden by values in `src/manifest.json`.

---

<div class="post-metadata">

**Author:** ![roman\_r\_m](https://yyz2.discourse-cdn.com/flex028/user_avatar/discourse.joplinapp.org/roman_r_m/32/3297_2.png) [@roman\_r\_m](https://discourse.joplinapp.org/u/roman_r_m)\
**Post date:** [20 May 2021 13:56 UTC](https://discourse.joplinapp.org/t/beta-easier-workflow-for-making-plugins/17472/9 "2021-05-20T13:56:00Z")

</div>

Yes, sounds great.

Another suggestion: I had issues before where I would run npm publish while having local uncommitted changes. And then when someone reported an issue with the plugin it took me a while to figure out how come the user saw the behaviour that was absolutely impossible based on what was in git repo.  
So would be great if it could check for uncommitted changes before publishing to npm.

---

<div class="post-metadata">

**Author:** ![thejohnfreeman](https://yyz2.discourse-cdn.com/flex028/user_avatar/discourse.joplinapp.org/thejohnfreeman/32/7547_2.png) [@thejohnfreeman](https://discourse.joplinapp.org/u/thejohnfreeman)\
**Post date:** [20 May 2021 14:00 UTC](https://discourse.joplinapp.org/t/beta-easier-workflow-for-making-plugins/17472/10 "2021-05-20T14:00:58Z")

</div>

That might be outside the scope of this package. You might be interested in a tool like [`publish-please`](https://yarnpkg.com/package/publish-please).

---

<div class="post-metadata">

**Author:** ![laurent](https://avatars.discourse-cdn.com/v4/letter/l/ce7236/32.png) [@laurent](https://discourse.joplinapp.org/u/laurent)\
**Post date:** [20 May 2021 15:33 UTC](https://discourse.joplinapp.org/t/beta-easier-workflow-for-making-plugins/17472/11 "2021-05-20T15:33:14Z")

</div>

You'd miss the plugin ID and the name for package.json and for manifest.json have different purpose - the first one is for computers, the second is a user-friendly string.

At this point I won't depend on an npm package that tries to do everything like this. I prefer the mix approach with Yeoman for scaffolding, and possibly an npm package to get rid of the /api directory. Yeoman is also good to provide instructions when creating the plugin structure.

---

<div class="post-metadata">

**Author:** ![thejohnfreeman](https://yyz2.discourse-cdn.com/flex028/user_avatar/discourse.joplinapp.org/thejohnfreeman/32/7547_2.png) [@thejohnfreeman](https://discourse.joplinapp.org/u/thejohnfreeman)\
**Post date:** [20 May 2021 16:19 UTC](https://discourse.joplinapp.org/t/beta-easier-workflow-for-making-plugins/17472/12 "2021-05-20T16:19:12Z")

</div>

Good point about the ID. Could you add it to the documentation [here](https://joplinapp.org/api/references/plugin_manifest/)? Its absence is the reason I missed it in my comment.

I'm sad to hear you don't like it, but that's ok. I'll try to make it so good you can't ignore it. In the meantime, you can use the parts that you want, e.g. as "an npm package to get rid of the /api directory".

---

<div class="post-metadata">

**Author:** ![laurent](https://avatars.discourse-cdn.com/v4/letter/l/ce7236/32.png) [@laurent](https://discourse.joplinapp.org/u/laurent)\
**Post date:** [20 May 2021 16:57 UTC](https://discourse.joplinapp.org/t/beta-easier-workflow-for-making-plugins/17472/13 "2021-05-20T16:57:52Z")

</div>

> Good point about the ID. Could you add it to the documentation [here](https://joplinapp.org/api/references/plugin_manifest/)? Its absence is the reason I missed it in my comment.

Right, it wasn't required originally which is why it's missing.

> I'm sad to hear you don't like it, but that's ok. I'll try to make it so good you can't ignore it. In the meantime, you can use the parts that you want, e.g. as "an npm package to get rid of the /api directory".

Let's see how it goes but I prefer not to move too fast, and like everything in software I expect your package might solve some issues but also create new ones. I'll definitely keep an eye on your package though and see what can be integrated.
