487 lines
14 KiB
Markdown
487 lines
14 KiB
Markdown
# Create a Plugin
|
||
|
||
In this document, you’ll learn how to create a plugin and publish it. If you’re interested to learn more about what plugins are and where to find available official and community plugins, check out the [overview document](overview.md).
|
||
|
||
## Prerequisites
|
||
|
||
This guide uses the Medusa CLI throughout different steps. If you don’t have the Medusa CLI installed you can install it with the following command:
|
||
|
||
```bash npm2yarn
|
||
npm install @medusajs/medusa-cli -g
|
||
```
|
||
|
||
:::note
|
||
|
||
If you run into any errors while installing the CLI tool, check out the [troubleshooting guide](../../../troubleshooting/cli-installation-errors.mdx).
|
||
|
||
:::
|
||
|
||
---
|
||
|
||
## Initialize Project
|
||
|
||
The recommended way to create a plugin is using the Medusa CLI. Run the following command to create a new Medusa project:
|
||
|
||
```bash
|
||
medusa new medusa-plugin-custom
|
||
```
|
||
|
||
Where `medusa-plugin-custom` is the name of the plugin you’re creating. In Medusa, plugins are named based on their functionalities.
|
||
|
||
By convention, all plugin names start with `medusa` followed by a descriptive name of what the plugin does. For example, the Stripe plugin is named `medusa-payment-stripe`.
|
||
|
||
---
|
||
|
||
## Changes to package.json
|
||
|
||
### Rename Project Name
|
||
|
||
Update the `name` field in the `package.json` file to the name of your plugin. This should be the same name that you chose when running the `medusa new` command.
|
||
|
||
### Change Dependencies
|
||
|
||
A basic Medusa server installed with the `medusa new` command has dependencies similar to this:
|
||
|
||
```json title=package.json
|
||
"dependencies": {
|
||
"@medusajs/medusa": "^1.3.1",
|
||
"@medusajs/medusa-cli": "^1.3.0",
|
||
"medusa-fulfillment-manual": "^1.1.31",
|
||
"medusa-interfaces": "^1.3.0",
|
||
"medusa-payment-manual": "^1.0.16",
|
||
"medusa-payment-stripe": "^1.1.38",
|
||
"typeorm": "^0.2.36"
|
||
},
|
||
"devDependencies": {
|
||
"@babel/cli": "^7.14.3",
|
||
"@babel/core": "^7.14.3",
|
||
"@babel/preset-typescript": "^7.14.5",
|
||
"babel-preset-medusa-package": "^1.1.19"
|
||
}
|
||
```
|
||
|
||
For a plugin, a lot of these dependencies are not necessary or should be labeled as [peer dependencies](https://docs.npmjs.com/cli/v8/configuring-npm/package-json#peerdependencies). Therefore, it’s important to make changes to the dependencies of your plugin.
|
||
|
||
The recommended change is the following:
|
||
|
||
```json title=package.json
|
||
"peerDependencies": {
|
||
"@medusajs/medusa": "^1.3.1",
|
||
"medusa-interfaces": "^1.3.0",
|
||
"typeorm": "^0.2.36"
|
||
},
|
||
"devDependencies": {
|
||
"@babel/cli": "^7.14.3",
|
||
"@babel/core": "^7.14.3",
|
||
"@babel/preset-typescript": "^7.14.5",
|
||
"babel-preset-medusa-package": "^1.1.19",
|
||
}
|
||
```
|
||
|
||
The packages `@medusajs/medusa` and `medusa-interfaces` act as peer dependencies. They’ll be installed while you develop your package, and they are required when your plugin is installed in another NPM project.
|
||
|
||
You remove the packages `medusa-fulfillment-manual`, `medusa-payment-manual`, and `medusa-payment-stripe` as they are fulfillment and payment plugins necessary for a Medusa server, but not for a plugin.
|
||
|
||
Additionally, you remove `@medusajs/medusa-cli` as you don’t need to use the Medusa CLI while developing a plugin.
|
||
|
||
Once you’re done making these changes, re-run the install command to update your `node_modules` directory:
|
||
|
||
```bash npm2yarn
|
||
npm install
|
||
```
|
||
|
||
This section includes recommended changes to your `package.json`. You can skip any of these changes if you don’t find them necessary to your plugin.
|
||
|
||
### Recommended: Change scripts
|
||
|
||
:::caution
|
||
|
||
If you don't make changes to the `build` and `watch` commands, please be aware of the [expected plugin structure](#plugin-structure).
|
||
|
||
:::
|
||
|
||
A basic Medusa installation comes with the following scripts:
|
||
|
||
```json title=package.json
|
||
"scripts": {
|
||
"seed": "medusa seed -f ./data/seed.json",
|
||
"build": "babel src --out-dir . --ignore **/__tests__ --extensions \".ts,.js\"",
|
||
"start": "medusa develop"
|
||
}
|
||
```
|
||
|
||
The `seed` and `start` scripts aren't necessary for plugin development so you can remove them.
|
||
|
||
It’s also recommended to add the `watch` script that automatically compiles your files if they are changed:
|
||
|
||
```json title=package.json
|
||
"watch": "babel -w src --out-dir . --ignore **/__tests__ --extensions \".ts,.js\""
|
||
```
|
||
|
||
This is helpful when testing the plugin.
|
||
|
||
:::note
|
||
|
||
Testing the plugin is covered in a [later section](#test-your-plugin).
|
||
|
||
:::
|
||
|
||
Another recommended script is the `prepare` script that builds your files under a “production” environment:
|
||
|
||
```json title=package.json
|
||
"prepare": "cross-env NODE_ENV=production npm run build"
|
||
```
|
||
|
||
You would typically run this script before publishing your plugin.
|
||
|
||
This script requires installing the package `cross-env` as a development dependency:
|
||
|
||
```bash npm2yarn
|
||
npm install --save-dev cross-env
|
||
```
|
||
|
||
### Recommended: Change Basic Info
|
||
|
||
`package.json` holds information that further describes the package or the author that created the package. It is recommended to make the following changes:
|
||
|
||
- `description`: Change this to a sentence that describes what your plugin does.
|
||
- `author`: Your name and email.
|
||
- `repository`: The repository that holds your plugin’s codebase.
|
||
- `keywords`: This should hold the keywords that are related to your plugin. It’s recommended that all plugins use the keywords `medusa-plugin` or `medusa`.
|
||
|
||
---
|
||
|
||
## Develop your Plugin
|
||
|
||
Now, You can start developing your plugin. This can include adding services, endpoints, entities, or anything that's relevant to your plugin.
|
||
|
||
### Plugin Structure
|
||
|
||
While developing your plugin, you can create your TypeScript or JavaScript files under the `src` directory. This includes creating services, endpoints, migrations, etc...
|
||
|
||
However, before you test the changes on a Medusa server or publish your plugin, you must transpile your files, which moves them into the root of your plugin directory.
|
||
|
||
For example, if you have an endpoint in `src/api/index.js`, after running the `build` or `watch` commands [as defined earlier](#change-scripts), the file should be transpiled into `api/index.js` in your plugin's root.
|
||
|
||
If files and directories aren't placed in the root of your plugin, the Medusa server won't detect or load them.
|
||
|
||
An example of a plugin's directory before testing or publishing:
|
||
|
||
```bash noReport
|
||
medusa-plugin-custom
|
||
|
|
||
|_ _ _ api
|
||
| |
|
||
| |_ _ _ index.js
|
||
|
|
||
|_ _ _ migrations
|
||
| |
|
||
| |_ _ _ <TIMESTAMP>_UserChanged.js
|
||
|
|
||
|_ _ _ src
|
||
| |
|
||
| |_ _ _ api
|
||
| | |
|
||
| | |_ _ _ index.ts
|
||
| |
|
||
| |_ _ _ migrations
|
||
| |
|
||
| |_ _ _ <TIMESTAMP>_UserChanged.ts
|
||
|
|
||
|_ _ _ package.json
|
||
//... other files
|
||
```
|
||
|
||
### Development Resources
|
||
|
||
This guide doesn't cover how to create different files and components. If you’re interested in learning how to do that, you can check out these guides:
|
||
|
||
- How to [create endpoints](../endpoints/add.md)
|
||
- How to [create a service](../services/create-service.md)
|
||
- How to [create a subscriber](../subscribers/create-subscriber.md)
|
||
- How to [create an entity](./../entities/index.md)
|
||
- How to [create a migration](../migrations/index.md)
|
||
|
||
---
|
||
|
||
## Add Plugin Configuration
|
||
|
||
Plugins often allow developers that will later use them to enter their own configuration. For example, you can allow developers to specify the API key of a service you’re integrating.
|
||
|
||
To pass a plugin its configurations on a Medusa server, you have to add it to the `plugins` array in `medusa-config.js`:
|
||
|
||
```jsx title=medusa-config.js
|
||
const plugins = [
|
||
//...
|
||
{
|
||
resolve: `medusa-plugin-custom`,
|
||
options: {
|
||
name: "My Store",
|
||
},
|
||
},
|
||
]
|
||
```
|
||
|
||
Then, you can have access to your plugin configuration in the constructor of services in your plugin:
|
||
|
||
```jsx title=src/service/test.ts
|
||
//In a service in your plugin
|
||
constructor({}, options) {
|
||
//options contains plugin configurations
|
||
this.name = options.name
|
||
}
|
||
```
|
||
|
||
You can also have access to the configurations in endpoints in your plugin:
|
||
|
||
```jsx title=src/api/index.ts
|
||
//in an endpoint in your plugin
|
||
export default (rootDirectory, options) => {
|
||
//options contain the plugin configurations
|
||
const router = Router()
|
||
|
||
router.get("/hello-world", (req, res) => {
|
||
res.json({
|
||
message: `Welcome to ${options.name ? options.name : "Medusa"}!`,
|
||
})
|
||
})
|
||
|
||
return router
|
||
}
|
||
```
|
||
|
||
:::tip
|
||
|
||
Make sure to include in the README of your plugin the configurations that can be passed to a plugin.
|
||
|
||
:::
|
||
|
||
---
|
||
|
||
## Test Your Plugin
|
||
|
||
While you develop your plugin, you’ll need to test it on an actual Medusa server. This can be done by using the [npm link](https://docs.npmjs.com/cli/v8/commands/npm-link) command.
|
||
|
||
In the root of your plugin directory, run the following command:
|
||
|
||
```bash npm2yarn
|
||
npm link
|
||
```
|
||
|
||
Then, change to the directory of the Medusa server you want to test the plugin on and run the following command:
|
||
|
||
```bash npm2yarn
|
||
npm link medusa-plugin-custom
|
||
```
|
||
|
||
Where `medusa-plugin-custom` is the package name of your plugin.
|
||
|
||
After linking to your plugin in a local Medusa server, either run the `build` or `watch` commands in your plugin directory:
|
||
|
||
```bash npm2yarn
|
||
# in the directory of the plugin
|
||
npm run watch
|
||
```
|
||
|
||
:::tip
|
||
|
||
If you’re running the `watch` command, you don’t need to run the `build` command every time you make a change to your plugin.
|
||
|
||
:::
|
||
|
||
Then, add your plugin into the array of plugins in `medusa-config.js`:
|
||
|
||
```jsx title=medusa-config.js
|
||
const plugins = [
|
||
//...
|
||
{
|
||
resolve: `medusa-plugin-custom`,
|
||
//if your plugin has configurations
|
||
options: {
|
||
name: "My Store",
|
||
},
|
||
},
|
||
]
|
||
```
|
||
|
||
:::note
|
||
|
||
If your plugin has migrations, you must run them before you start the server. Check out the [Migrations guide](../migrations/overview.md#migrate-command) for more details.
|
||
|
||
:::
|
||
|
||
Finally, start your server and test your plugin’s functionalities:
|
||
|
||
```bash npm2yarn
|
||
npm run start
|
||
```
|
||
|
||
### Troubleshoot Errors
|
||
|
||
#### Error: The class must be a valid service implementation
|
||
|
||
Please make sure that your plugin is following the correct structure. If the error persists then please try the following fix:
|
||
|
||
```bash npm2yarn
|
||
cd <SERVER_PATH>/node_modules/medusa-interfaces
|
||
npm link
|
||
cd <SERVER_PATH>/node_modules/@medusajs/medusa
|
||
npm link
|
||
cd <PLUGIN_PATH>
|
||
rm -rf node_modules/medusa-interfaces
|
||
rm -rf node_modules/@medusajs/medusa
|
||
npm link medusa-interfaces
|
||
npm link @medusajs/medusa
|
||
npm link
|
||
cd <SERVER_PATH>
|
||
npm link your-plugin
|
||
```
|
||
|
||
Where `<SERVER_PATH>` is the path to your Medusa server and `<PLUGIN_PATH>` is the path to your plugin.
|
||
|
||
This links the `medusa-interfaces` and `@medusajs/medusa` packages from your `medusa-backend` to your plugin directory and then links your plugin to your `medusa-backend`.
|
||
|
||
#### APIs not loading
|
||
|
||
If the APIs you added to your Medussa server are not loading then please try the following steps:
|
||
|
||
```bash npm2yarn
|
||
cd <PLUGIN_PATH>
|
||
rm -rf node_modules
|
||
cd <SERVER_PATH>/node_modules/<PLUGIN_NAME>
|
||
npm install
|
||
cd <PLUGIN_PATH>
|
||
npm run build
|
||
cd <SERVER_PATH>
|
||
npm run start
|
||
```
|
||
|
||
Where `<SERVER_PATH>` is the path to your Medusa server, `<PLUGIN_PATH>` is the path to your plugin and `<PLUGIN_NAME>` is the name of your plugin as it is in your plugin `package.json` file.
|
||
|
||
:::note
|
||
|
||
It is safe to ignore any `cross-env: command not found` error you may receive.
|
||
|
||
:::
|
||
|
||
---
|
||
|
||
## NPM Ignore File
|
||
|
||
Not all files that you use while developing your plugin are necessary to be published.
|
||
|
||
For example, the files you add in the `src` directory are compiled to the root of the plugin directory before publishing. Then, when a developer installs your plugin, they’ll just be using the files in the root.
|
||
|
||
So, you can ignore files and directories like `src` from the final published NPM package.
|
||
|
||
To do that, create the file `.npmignore` with the following content:
|
||
|
||
```bash title=.npmignore
|
||
/lib
|
||
node_modules
|
||
.DS_store
|
||
.env*
|
||
/*.js
|
||
!index.js
|
||
yarn.lock
|
||
src
|
||
.gitignore
|
||
.eslintrc
|
||
.babelrc
|
||
.prettierrc
|
||
|
||
#These are files that are included in a
|
||
#Medusa project and can be removed from a
|
||
#plugin project
|
||
medusa-config.js
|
||
Dockerfile
|
||
medusa-db.sql
|
||
develop.sh
|
||
```
|
||
|
||
---
|
||
|
||
## Publish Plugin
|
||
|
||
Once you’re done developing your plugin you can publish the package on NPM’s registry so that other developers can benefit from it and use it.
|
||
|
||
Before you publish a plugin, you must [create an account on NPM](https://www.npmjs.com/signup).
|
||
|
||
### Prepare Plugin
|
||
|
||
Before you publish or update your plugin, make sure to run the `prepare` command [defined earlier](#recommended-change-scripts):
|
||
|
||
```bash npm2yarn
|
||
npm run prepare
|
||
```
|
||
|
||
### Login
|
||
|
||
In your terminal, log in with your NPM account:
|
||
|
||
```bash
|
||
npm login
|
||
```
|
||
|
||
You’ll be asked to enter your NPM email and password.
|
||
|
||
### Publish Plugin Package
|
||
|
||
Once you’re logged in, you can publish your package with the following command:
|
||
|
||
```bash
|
||
npm publish
|
||
```
|
||
|
||
Your package is then published on NPM and everyone can use it and install it.
|
||
|
||
### Update Plugin
|
||
|
||
To update your plugin at a later point, you can run the following command to change the NPM version:
|
||
|
||
```bash
|
||
npm version <type>
|
||
```
|
||
|
||
Where `<type>` indicates the type of version update you’re publishing. For example, it can be `major` or `minor`.
|
||
|
||
You can see the [full list of types in NPM’s documentation](https://docs.npmjs.com/cli/v8/commands/npm-version).
|
||
|
||
Then, publish the new update:
|
||
|
||
```bash
|
||
npm publish
|
||
```
|
||
|
||
---
|
||
|
||
## Add Plugin to Medusa’s Repository
|
||
|
||
All officially-supported plugins are available in the [`packages` directory of the Medusa GitHub repository](https://github.com/medusajs/medusa/tree/master/packages).
|
||
|
||
If you’re interested in adding your plugin, you need to create a new pull request (PR) where you add your plugin inside the `packages` directory. Our team will then review your plugin, and if it’s approved the PR will be merged and your plugin will be available on Medusa’s repository.
|
||
|
||
:::note
|
||
|
||
Before contributing to the Medusa repository, please check out the [contribution guidelines](https://github.com/medusajs/medusa/blob/master/CONTRIBUTING.md).
|
||
|
||
:::
|
||
|
||
---
|
||
|
||
## Install a Plugin
|
||
|
||
To install any published plugin, you can run the following command on any Medusa server project:
|
||
|
||
```bash npm2yarn
|
||
npm install medusa-plugin-custom
|
||
```
|
||
|
||
---
|
||
|
||
## See Also
|
||
|
||
- [Available official plugins](https://github.com/medusajs/medusa/tree/master/packages)
|
||
- [Services reference](references/services/../../../../../references/services/classes/AuthService.md)
|
||
- [Events reference](../subscribers/events-list.md)
|