chore: reorganize docs apps (#7228)

* reorganize docs apps

* add README

* fix directory

* add condition for old docs
This commit is contained in:
Shahed Nasser authored and GitHub committed 2024-05-03 17:36:38 +03:00
1 parent 224ebb2154
commit 4fe28f5a95
6187 files changed
+601447 -598226

No files matched your search

@@ -0,0 +1,85 @@
export const metadata = {
title: `${pageNumber} Create a Plugin`,
}
# {metadata.title}
In this chapter, you’ll learn how to create a plugin.
## Plugin Development Process
A plugin consists of Medusa application customizations. So, start with a new Medusa application and build your plugin’s resources.
Once you’re done developing and testing your customizations, you can package them in a plugin to be installed in other Medusa applications.
![Diagram visualizing the plugin development process.](https://res.cloudinary.com/dza7lstvk/image/upload/v1708506149/Medusa%20Book/plugin-development-process_hls7bh.jpg)
This chapter explains the steps to create the plugin that packages those customizations. The next chapter explains how to publish the plugin to NPM.
---
## Changes to package.json
### Add Prepare Script
Your plugin’s customizations must be built for production use. So, add a new `prepare` script to your scripts in `package.json`:
```json title="package.json"
"scripts": {
// other scripts...
"prepare": "cross-env NODE_ENV=production npm run build:server && medusa-admin bundle"
}
```
This builds your application resources, such as services and API routes, and creates a production build of your admin customizations. If your plugin doesn’t have any admin customizations, remove the `medusa-admin bundle` part of the script.
<Note>
`cross-env` is already a dependency in your Medusa application. If not, make sure to install it.
</Note>
### Change Dependencies
Your Medusa application requires dependencies that are not relevant to a plugin. For example, you can remove other plugins like `@medusajs/file-local` or modules like `@medusajs/cache-inmemory`.
<Note title="Tip">
Make sure to remove those plugins/modules from `medusa-config.js`.
</Note>
In addition, move `@medusajs/medusa` to be a peer dependency:
```json title="package.json"
"peerDependencies": {
"@medusajs/medusa": "YOUR_MEDUSA_VERSION",
// other peer dependencies...
}
```
If your plugin includes admin customizations, add `react` and `react-router-dom` (if you’re using it) to the `peerDependencies` as well:
```json title="package.json"
"peerDependencies": {
// other dependencies...
"react": "^18.2.0",
"react-router-dom": "^6.13.0"
}
```
---
## File Changes
Your Medusa application has files that aren’t relevant to your plugin. For example, files like `src/model/onboarding.ts` used for the onboarding process.
Go through all files under the `src` directory and remove those that aren’t relevant to your plugin.
---
## Plugin Structure
A published plugin must have its customizations built into the `dist` directory or to the root of the package. This is handled by the `prepare` command you added earlier.
Once your plugin is created, you’re ready to publish and use it in Medusa applications.
@@ -0,0 +1,102 @@
export const metadata = {
title: `${pageNumber} Integration Services`,
}
# {metadata.title}
In this chapter, you’ll learn about special service types used when integrating third-party services.
## Notification Service
A notification service is used to send notifications, such as email, in your Medusa application.
For example, the SendGrid plugin contains a notification service. When the plugin is installed, the Medusa application resolves its notification service to send emails using SendGrid.
A notification service must extend the `AbstractNotificationService` class from the `@medusajs/medusa` package.
Refer to [this reference](!resources!/notification-service) to learn more about creating a notification service.
---
## File Service
A file service is used to upload and download files in your Medusa application.
For example, the S3 plugin contains a file service. When the plugin is installed, the Medusa application resolves its file service to upload and download files, such as product images.
A file service must extend the `AbstractFileService` class from the `@medusajs/medusa` package.
Refer to [this reference](!resources!/file-service) to learn more about creating a file service.
---
## Search Service
A search service is used to search data in your store, such as products.
For example, the MeiliSearch plugin contains a search service. When the plugin is installed, the Medusa application resolves its search service when searching for products.
A search service must extend the `AbstractSearchService` class from the `@medusajs/utils` package.
Refer to [this reference](!resources!/search-service) to learn more about creating a search service.
---
## Other Integration Types
If you’re integrating other types of services, such as a CMS or an ERP system, you can create a standard service that extends the `TransactionBaseService` class and implements the necessary methods for your integration.
Then, you can use that service in other resources, such as an API route or a subscriber.
---
## Integration Services Tips
### Client Initialization
Part of the integration is interacting with the third-party service using a client.
Some third-party services provide a Node.js SDK that you can use. In those cases, you can install the SDK and initialize the client in the constructor.
In other cases, you can install [axios](https://www.npmjs.com/package/axios) and use it to create a client in the constructor.
For example:
```tsx
import { TransactionBaseService } from "@medusajs/medusa"
import { Axios } from "axios"
type Options = {
erp_url: string
token: string
}
class ErpService extends TransactionBaseService {
protected client: Axios
constructor({}, options: Options) {
super(arguments[0], options)
this.client = new Axios({
baseURL: options.erp_url,
headers: {
Authorization: `Bearer ${options.token}`,
},
})
}
async retrieveProductErpDetails(productId: string) {
const { data } = await this.client.get(
`/product/${productId}`
)
return data
}
}
export default ErpService
```
In the above example, you create a client with `axios`. You use the plugin’s options to set the client’s options, such as the base URL and the authorization token.
Then, you can use the client in other methods to send requests to the third-party service.
+127
View File
@@ -0,0 +1,127 @@
import { Table } from "docs-ui"
import { Check, XMark } from "@medusajs/icons"
export const metadata = {
title: `${pageNumber} Plugin Development`,
}
# {metadata.title}
In the next chapters, you’ll learn about plugins, their use in your application, and how to create and publish plugins.
## What is a Plugin?
A plugin is an NPM package that consists of Medusa customizations. It adds new functionalities or integrates third-party services, such as a CMS or MeiliSearch.
Plugins can be added or removed from your Medusa application without causing side effects.
<Note title="Use plugins when" type="success">
- You're integrating a third-party service into your Medusa application.
- You're creating reusable Medusa application customizations.
- You're providing features that are specific to a Medusa application, such as a migration tool from another platform to Medusa.
</Note>
---
## Plugins vs Modules
Both plugins and modules are NPM packages that can be installed on your Medusa application without affecting the overall system.
However, there are key differences between plugins and modules:
<Table>
<Table.Header>
<Table.Row>
<Table.HeaderCell className="w-1/3">Criteria</Table.HeaderCell>
<Table.HeaderCell className="!text-center">Plugins</Table.HeaderCell>
<Table.HeaderCell className="!text-center">Modules</Table.HeaderCell>
</Table.Row>
</Table.Header>
<Table.Body>
<Table.Row>
<Table.Cell>Run in isolation of a Medusa application.</Table.Cell>
<Table.Cell><XMark className="mx-auto" /></Table.Cell>
<Table.Cell><Check className="mx-auto" /></Table.Cell>
</Table.Row>
<Table.Row>
<Table.Cell>Can consist of Medusa application customizations, such as API routes or admin widgets.</Table.Cell>
<Table.Cell><Check className="mx-auto" /></Table.Cell>
<Table.Cell><XMark className="mx-auto" /></Table.Cell>
</Table.Row>
<Table.Row>
<Table.Cell>Link custom data models to those of Medusa's commerce modules.</Table.Cell>
<Table.Cell><XMark className="mx-auto" /></Table.Cell>
<Table.Cell><Check className="mx-auto" /></Table.Cell>
</Table.Row>
<Table.Row>
<Table.Cell>Make architectural changes, such as change the pub/sub service used to emit events.</Table.Cell>
<Table.Cell><XMark className="mx-auto" /></Table.Cell>
<Table.Cell><Check className="mx-auto" /></Table.Cell>
</Table.Row>
</Table.Body>
</Table>
## Official and Community Plugins
Medusa provides official plugins that integrate third-party services like Algolia, SendGrid, S3, and more.
You can also check out the [Plugins Library](https://medusajs.com/plugins/) for a full list of plugins created by the community.
---
## How are Plugins Installed?
Plugins are installed through NPM. Then, you must add them to the `plugins` array exported as part of the configurations in `medusa-config.js`.
If you check the `plugins` array in your `medusa-config.js`, you'll find a few plugins already installed:
```js title="medusa-config.js"
const plugins = [
`medusa-fulfillment-manual`,
`medusa-payment-manual`,
{
resolve: `@medusajs/file-local`,
options: {
upload_dir: "uploads",
},
},
{
resolve: "@medusajs/admin",
/** @type {import('@medusajs/admin').PluginOptions} */
options: {
autoRebuild: true,
develop: {
open: false,
},
},
},
]
```
The items in the `plugins` array can either be:
- A string which is the plugin's name. In this case, the plugin doesn't require any options;
- Or an object having the following properties:
- `resolve`: the plugin's name.
- `options`: An object of options to pass to the plugin.
### Configure Admin Customizations
If a plugin provides customizations to the admin dashboard, you can pass a special option `enableUI` whose value is a boolean indicating whether the admin customizations should be enabled. By default, its value is `false`.
For example:
```js title="medusa-config.js"
const plugins = [
// ...
{
resolve: `medusa-plugin-custom`,
options: {
// other options...
enableUI: true,
},
},
]
```
@@ -0,0 +1,144 @@
import { CodeTabs, CodeTab } from "docs-ui"
export const metadata = {
title: `${pageNumber} Plugin Options`,
}
# {metadata.title}
In this chapter, you’ll learn how to access a plugin’s options in different resources.
## Services
In a plugin, a service’s constructor accepts a second parameter: an object holding the plugin’s options.
For example:
```ts title="src/services/erp.ts" highlights={[["6", "", "The plugin's options are passed as a parameter."], ["9", "", "Set the plugin's options in a class property."]]}
import { TransactionBaseService } from "@medusajs/medusa"
class ErpService extends TransactionBaseService {
protected options_: Record<string, unknown>
constructor(container, options) {
super(container, options)
this.options_ = options
}
}
export default ErpService
```
This adds an `options_` property to the `ErpService` and sets its value using the second parameter of the constructor. You can now use the options in other methods.
---
## API Routes
To access a plugin’s options in an API route, it’s recommended to expose a getter method in the service for the `options_` property that the API route can use.
For example:
<CodeTabs group="resource-types">
<CodeTab label="Service" value="service">
```ts title="src/services/erp.ts" highlights={[["11"], ["12"], ["13"], ["14"], ["15"], ["16"]]}
import { TransactionBaseService } from "@medusajs/medusa"
class ErpService extends TransactionBaseService {
protected options_: Record<string, unknown>
// ...
get options(): Record<string, unknown> {
return this.options_
}
}
export default ErpService
```
</CodeTab>
<CodeTab label="API Route" value="api-route">
```ts title="src/subscribers/customer-created.ts"
import { MedusaRequest, MedusaResponse } from "@medusajs/medusa"
import ErpService from "../../services/erp"
export async function GET(
req: MedusaRequest,
res: MedusaResponse
): Promise<void> {
const erpService: ErpService = req.scope.resolve("erpService")
const pluginOptions = erpService.options
// use plugin options...
}
```
</CodeTab>
</CodeTabs>
---
## Subscribers
The object parameter that a subscriber handler function accepts has a `pluginOptions` property. When a subscriber is created in a plugin, this property holds the plugin’s options.
For example:
```ts title="src/subscribers/product-updated.ts" highlights={[["7", "", "The plugin's options are passed in the object parameter."]]}
import {
// other imports...
SubscriberArgs,
} from "@medusajs/medusa"
export default async function productUpdateHandler({
pluginOptions,
}: SubscriberArgs) {
console.log(`Plugin options: ${pluginOptions}`)
}
// ...
```
---
## Scheduled Job
The object parameter that a scheduled job function accepts has a `pluginOptions` property. When a scheduled job is created in a plugin, this property holds the plugin’s options.
For example:
```ts title="src/jobs/once-a-day.ts" highlights={[["6", "", "The plugin's options are passed in the object parameter."]]}
import {
// ...
ScheduledJobArgs,
} from "@medusajs/medusa"
export default function ({ pluginOptions }: ScheduledJobArgs) {
console.log(`Plugin options: ${pluginOptions}`)
}
// ...
```
---
## Loaders
In a plugin, a loader function accepts a second parameter: an object holding the plugin’s options.
For example:
```ts title="src/loaders/on-start.ts" highlights={[["5", "", "The plugin's options are passed as a second parameter to the loader."]]}
import { MedusaContainer } from "@medusajs/medusa"
export default function (
container: MedusaContainer,
options: Record<string, unknown>
) {
console.log(`Plugin options: ${options}`)
}
```
@@ -0,0 +1,184 @@
import { Table } from "docs-ui"
export const metadata = {
title: `${pageNumber} Publish a Plugin`,
}
# {metadata.title}
In this chapter, you’ll learn how to publish a plugin. After you publish your plugin, it will also be available in [Medusa’s Plugins Library](https://medusajs.com/plugins/).
## package.json Checklist
Update the following meta information in your plugin’s package.json:
- `name`: The name of your plugin. By convention, all plugin names start with `medusa` followed by a descriptive name of what the plugin does. For example, `medusa-payment-stripe`.
- `description`: A short description of what the plugin does.
- `author`: Your name or your company's name.
- `repository`: Details about the repository that holds the source code of the plugin. It's an object that holds the following properties:
- `type`: Should be `git`.
- `url`: The URL to the repository (for example, the GitHub repository holding the code of your plugin).
### Package Keywords
It's required for all Medusa plugins to use the keywords `medusa-plugin`.
The following table mentions other keywords that you can use based on your plugin's functionalities.
<Table>
<Table.Header>
<Table.Row>
<Table.HeaderCell>Keyword</Table.HeaderCell>
<Table.HeaderCell>Description</Table.HeaderCell>
</Table.Row>
</Table.Header>
<Table.Body>
<Table.Row>
<Table.Cell>`medusa-plugin-analytics`</Table.Cell>
<Table.Cell>Analytics functionalities or integrations.</Table.Cell>
</Table.Row>
<Table.Row>
<Table.Cell>`medusa-plugin-cms`</Table.Cell>
<Table.Cell>CMS functionalities or integrations.</Table.Cell>
</Table.Row>
<Table.Row>
<Table.Cell>`medusa-plugin-notification`</Table.Cell>
<Table.Cell>Notification functionalities or integrations.</Table.Cell>
</Table.Row>
<Table.Row>
<Table.Cell>`medusa-plugin-payment`</Table.Cell>
<Table.Cell>Payment functionalities or integrations.</Table.Cell>
</Table.Row>
<Table.Row>
<Table.Cell>`medusa-plugin-search`</Table.Cell>
<Table.Cell>Search functionalities or integrations.</Table.Cell>
</Table.Row>
<Table.Row>
<Table.Cell>`medusa-plugin-shipping`</Table.Cell>
<Table.Cell>Shipping functionalities or integrations.</Table.Cell>
</Table.Row>
<Table.Row>
<Table.Cell>`medusa-plugin-storage`</Table.Cell>
<Table.Cell>File service or storage integrations.</Table.Cell>
</Table.Row>
<Table.Row>
<Table.Cell>`medusa-plugin-source`</Table.Cell>
<Table.Cell>Migrate or import data into Medusa from another platform.</Table.Cell>
</Table.Row>
<Table.Row>
<Table.Cell>`medusa-plugin-admin`</Table.Cell>
<Table.Cell>Plugins that include only admin customizations.</Table.Cell>
</Table.Row>
<Table.Row>
<Table.Cell>`medusa-plugin-other`</Table.Cell>
<Table.Cell>Any other type of plugin.</Table.Cell>
</Table.Row>
</Table.Body>
</Table>
---
## Add NPMIgnore File
Not all files in your Medusa application are relevant to the published plugin.
Add the following `.npmignore` file in the root of the plugin's directory to ignore unnecessary files from the published plugin:
```bash title=".npmignore"
# directories
.cache
.DS_store
.github
.vscode
.yarn
build
data
node_modules
src
uploads
# files
.babelrc
.env*
.gitignore
.eslintrc
.prettierrc
.yarnrc.yml
index.js
medusa-config.js
yarn.lock
```
---
## Publish Plugin
<Note type="check">
To publish a plugin, you need an [NPM account](https://www.npmjs.com/signup).
</Note>
To publish the plugin:
1. Run the `prepare` command:
```bash npm2yarn
npm run prepare
```
2. Publish the NPM package:
```bash
npm publish
```
If you haven’t logged in before with NPM, you’ll be asked to log in first.
Your package is then published to NPM.
---
## Install Plugin in Medusa Applications
To install your published plugin in a Medusa application, run the following command:
```bash npm2yarn
npm install medusa-plugin-custom
```
Where `medusa-plugin-custom` is your plugin’s name.
Then, add the plugin to `medusa-config.js`:
```js title="medusa-config.js"
const plugins = [
// ...
{
resolve: `medusa-plugin-custom`,
options: {
// plugin options...
},
},
]
```
---
## Update Plugin
To publish plugin changes, first, run the following command in the plugin’s directory to change the NPM version:
```bash
npm version <type>
```
Where `<type>` indicates the type of version update you’re publishing. For example, `major`. 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
```
You can then update the plugin in the Medusa applications that use it.