docs: docs for next release (#13621)
* docs: docs for next release * changes to opentelemetry dependencies * document plugin env variables * document admin changes * fix vale error * add version notes * document campaign budget updates * document campaign changes in user guide * document chages in cluster mode cli * documented once promotion allocation * document multiple API keys support
This commit is contained in:
@@ -0,0 +1,21 @@
|
||||
import { ChildDocs } from "docs-ui"
|
||||
|
||||
export const metadata = {
|
||||
title: `${pageNumber} Medusa Codemods`,
|
||||
}
|
||||
|
||||
# {metadata.title}
|
||||
|
||||
In this chapter, you'll learn about Medusa codemods and the list of available codemods.
|
||||
|
||||
## What are Codemods?
|
||||
|
||||
Codemods are scripts that help you automate codebase changes. They are especially useful when updating to a new version that requires large changes to your codebase.
|
||||
|
||||
Medusa provides codemods to help you update your codebase. Use these codemods when updating to their respective versions.
|
||||
|
||||
---
|
||||
|
||||
## List of Medusa Codemods
|
||||
|
||||
<ChildDocs type="item" />
|
||||
@@ -0,0 +1,279 @@
|
||||
export const metadata = {
|
||||
title: `${pageNumber} Replace Imports Codemod (v2.11.0+)`,
|
||||
}
|
||||
|
||||
# {metadata.title}
|
||||
|
||||
In this chapter, you'll learn about the codemod that helps you replace imports in your codebase when upgrading to Medusa v2.11.0.
|
||||
|
||||
## What is the Replace Imports Codemod?
|
||||
|
||||
[Medusa v2.11.0](https://github.com/medusajs/medusa/releases/tag/v2.11.0) optimized the package structure by consolidating several external packages into the `@medusajs/framework` package.
|
||||
|
||||
Previously, you had to install and manage packages related to MikroORM, Awilix, OpenTelemetry, and the `pg` package separately in your Medusa application. Starting with v2.11.0, these packages are included in the `@medusajs/framework` package.
|
||||
|
||||
For example, instead of importing `@mikro-orm/core`, you now import it from `@medusajs/framework/mikro-orm/core`. This applies to all of the following packages:
|
||||
|
||||
- `@mikro-orm/*` packages (for example, `@mikro-orm/core`, `@mikro-orm/migrations`, etc.) -> `@medusajs/framework/mikro-orm/{subpath}`
|
||||
- `awilix` -> `@medusajs/framework/awilix`
|
||||
- `pg` -> `@medusajs/framework/pg`
|
||||
- `@opentelemetry/instrumentation-pg` -> `@medusajs/framework/opentelemetry/instrumentation-pg`
|
||||
- `@opentelemetry/resources` -> `@medusajs/framework/opentelemetry/resources`
|
||||
- `@opentelemetry/sdk-node` -> `@medusajs/framework/opentelemetry/sdk-node`
|
||||
- `@opentelemetry/sdk-trace-node` -> `@medusajs/framework/opentelemetry/sdk-trace-node`
|
||||
|
||||
To help you update your codebase to reflect these changes, Medusa provides a codemod that automatically replaces imports of these packages throughout your codebase.
|
||||
|
||||
---
|
||||
|
||||
## Using the Replace Imports Codemod
|
||||
|
||||
To use the replace imports codemod, create the file `replace-imports.js` in the root of your Medusa application with the following content:
|
||||
|
||||
```js
|
||||
#!/usr/bin/env node
|
||||
|
||||
const fs = require("fs")
|
||||
const path = require("path")
|
||||
const { execSync } = require("child_process")
|
||||
|
||||
/**
|
||||
* Script to replace imports and require statements from mikro-orm/{subpath}, awilix, and pg
|
||||
* to their @medusajs/framework equivalents
|
||||
*/
|
||||
|
||||
// Define the replacement mappings
|
||||
const replacements = [
|
||||
// MikroORM imports - replace mikro-orm/{subpath} with @medusajs/framework/mikro-orm/{subpath}
|
||||
{
|
||||
pattern: /from\s+['"]@?mikro-orm\/([^'"]+)['"]/g,
|
||||
// eslint-disable-next-line quotes
|
||||
replacement: 'from "@medusajs/framework/mikro-orm/$1"',
|
||||
},
|
||||
// Awilix imports - replace awilix with @medusajs/framework/awilix
|
||||
{
|
||||
pattern: /from\s+['"]awilix['"]/g,
|
||||
// eslint-disable-next-line quotes
|
||||
replacement: 'from "@medusajs/framework/awilix"',
|
||||
},
|
||||
// PG imports - replace pg with @medusajs/framework/pg
|
||||
{
|
||||
pattern: /from\s+['"]pg['"]/g,
|
||||
// eslint-disable-next-line quotes
|
||||
replacement: 'from "@medusajs/framework/pg"',
|
||||
},
|
||||
// OpenTelemetry imports - replace @opentelemetry/instrumentation-pg, @opentelemetry/resources,
|
||||
// @opentelemetry/sdk-node, and @opentelemetry/sdk-trace-node with @medusajs/framework/opentelemetry/{subpath}
|
||||
{
|
||||
pattern: /from\s+['"]@?opentelemetry\/(instrumentation-pg|resources|sdk-node|sdk-trace-node)['"]/g,
|
||||
// eslint-disable-next-line quotes
|
||||
replacement: 'from "@medusajs/framework/opentelemetry/$1"',
|
||||
},
|
||||
// MikroORM require statements - replace require('@?mikro-orm/{subpath}') with require('@medusajs/framework/mikro-orm/{subpath}')
|
||||
{
|
||||
pattern: /require\s*\(\s*['"]@?mikro-orm\/([^'"]+)['"]\s*\)/g,
|
||||
// eslint-disable-next-line quotes
|
||||
replacement: 'require("@medusajs/framework/mikro-orm/$1")',
|
||||
},
|
||||
// Awilix require statements - replace require('awilix') with require('@medusajs/framework/awilix')
|
||||
{
|
||||
pattern: /require\s*\(\s*['"]awilix['"]\s*\)/g,
|
||||
// eslint-disable-next-line quotes
|
||||
replacement: 'require("@medusajs/framework/awilix")',
|
||||
},
|
||||
// PG require statements - replace require('pg') with require('@medusajs/framework/pg')
|
||||
{
|
||||
pattern: /require\s*\(\s*['"]pg['"]\s*\)/g,
|
||||
// eslint-disable-next-line quotes
|
||||
replacement: 'require("@medusajs/framework/pg")',
|
||||
},
|
||||
// OpenTelemetry require statements - replace require('@opentelemetry/instrumentation-pg'),
|
||||
// require('@opentelemetry/resources'), require('@opentelemetry/sdk-node'), and
|
||||
// require('@opentelemetry/sdk-trace-node') with require('@medusajs/framework/opentelemetry/{subpath}')
|
||||
{
|
||||
pattern: /require\s*\(\s*['"]@?opentelemetry\/(instrumentation-pg|resources|sdk-node|sdk-trace-node)['"]\s*\)/g,
|
||||
// eslint-disable-next-line quotes
|
||||
replacement: 'require("@medusajs/framework/opentelemetry/$1")',
|
||||
},
|
||||
]
|
||||
|
||||
function processFile(filePath) {
|
||||
try {
|
||||
const content = fs.readFileSync(filePath, "utf8")
|
||||
let modifiedContent = content
|
||||
let wasModified = false
|
||||
|
||||
replacements.forEach(({ pattern, replacement }) => {
|
||||
const newContent = modifiedContent.replace(pattern, replacement)
|
||||
if (newContent !== modifiedContent) {
|
||||
wasModified = true
|
||||
modifiedContent = newContent
|
||||
}
|
||||
})
|
||||
|
||||
if (wasModified) {
|
||||
fs.writeFileSync(filePath, modifiedContent)
|
||||
console.log(`✓ Updated: ${filePath}`)
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
} catch (error) {
|
||||
console.error(`✗ Error processing ${filePath}:`, error.message)
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
function getTargetFiles() {
|
||||
try {
|
||||
// Get the current script's filename to exclude it from processing
|
||||
const currentScript = path.basename(__filename)
|
||||
|
||||
// Find TypeScript/JavaScript files, excluding common directories that typically don't contain target imports
|
||||
const findCommand = `find . -name node_modules -prune -o -name .git -prune -o -name dist -prune -o -name build -prune -o -name coverage -prune -o -name "*.ts" -print -o -name "*.js" -print -o -name "*.tsx" -print -o -name "*.jsx" -print`
|
||||
const files = execSync(findCommand, {
|
||||
encoding: "utf8",
|
||||
maxBuffer: 50 * 1024 * 1024, // 50MB buffer
|
||||
})
|
||||
.split("\n")
|
||||
.filter((line) => line.trim())
|
||||
|
||||
console.log(files)
|
||||
|
||||
const targetFiles = []
|
||||
let processedCount = 0
|
||||
|
||||
console.log(`📄 Scanning ${files.length} files for target imports and require statements...`)
|
||||
|
||||
for (const file of files) {
|
||||
try {
|
||||
// Skip the current script file
|
||||
const fileName = path.basename(file)
|
||||
if (fileName === currentScript) {
|
||||
processedCount++
|
||||
continue
|
||||
}
|
||||
const content = fs.readFileSync(file, "utf8")
|
||||
if (
|
||||
/from\s+['"]@?mikro-orm\//.test(content) ||
|
||||
/from\s+['"]awilix['"]/.test(content) ||
|
||||
/from\s+['"]pg['"]/.test(content) ||
|
||||
/require\s*\(\s*['"]@?mikro-orm\//.test(content) ||
|
||||
/require\s*\(\s*['"]awilix['"]/.test(content) ||
|
||||
/require\s*\(\s*['"]pg['"]/.test(content)
|
||||
) {
|
||||
targetFiles.push(file.startsWith("./") ? file.slice(2) : file)
|
||||
}
|
||||
processedCount++
|
||||
if (processedCount % 100 === 0) {
|
||||
process.stdout.write(
|
||||
`\r📄 Processed ${processedCount}/${files.length} files...`
|
||||
)
|
||||
}
|
||||
} catch (fileError) {
|
||||
// Skip files that can't be read
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
if (processedCount > 0) {
|
||||
console.log(`\r📄 Processed ${processedCount} files. `)
|
||||
}
|
||||
|
||||
return targetFiles
|
||||
} catch (error) {
|
||||
console.error("Error finding target files:", error.message)
|
||||
return []
|
||||
}
|
||||
}
|
||||
|
||||
function main() {
|
||||
console.log("🔄 Finding files with target imports and require statements...")
|
||||
|
||||
const targetFiles = getTargetFiles()
|
||||
|
||||
if (targetFiles.length === 0) {
|
||||
console.log("ℹ️ No files found with target imports or require statements.")
|
||||
return
|
||||
}
|
||||
|
||||
console.log(`📁 Found ${targetFiles.length} files to process`)
|
||||
|
||||
let modifiedCount = 0
|
||||
let errorCount = 0
|
||||
|
||||
targetFiles.forEach((filePath) => {
|
||||
const fullPath = path.resolve(filePath)
|
||||
if (fs.existsSync(fullPath)) {
|
||||
if (processFile(fullPath)) {
|
||||
modifiedCount++
|
||||
}
|
||||
} else {
|
||||
console.warn(`⚠️ File not found: ${filePath}`)
|
||||
errorCount++
|
||||
}
|
||||
})
|
||||
|
||||
console.log("\n📊 Summary:")
|
||||
console.log(` Files processed: ${targetFiles.length}`)
|
||||
console.log(` Files modified: ${modifiedCount}`)
|
||||
console.log(` Errors: ${errorCount}`)
|
||||
|
||||
if (modifiedCount > 0) {
|
||||
console.log("\n✅ Import replacement completed successfully!")
|
||||
console.log("\n💡 Next steps:")
|
||||
console.log(" 1. Review the changes with: git diff")
|
||||
console.log(" 2. Run your tests to ensure everything works correctly")
|
||||
console.log(" 3. Commit the changes if you're satisfied")
|
||||
} else {
|
||||
console.log(
|
||||
"\n✅ No modifications needed - all imports are already correct!"
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// Run if called directly
|
||||
if (require.main === module) {
|
||||
main()
|
||||
}
|
||||
|
||||
module.exports = { processFile, getTargetFiles, main }
|
||||
```
|
||||
|
||||
This script scans your project for files that import from `mikro-orm/{subpath}`, `awilix`, or `pg`, and replaces those imports with their new equivalents from `@medusajs/framework`. It handles both ES module `import` statements and CommonJS `require` statements in JavaScript and TypeScript files.
|
||||
|
||||
Next, run the following command in your terminal to make the script executable:
|
||||
|
||||
<Note title="Windows Users">
|
||||
|
||||
You can run the script using `node` without changing permissions.
|
||||
|
||||
</Note>
|
||||
|
||||
```bash
|
||||
chmod +x replace-imports.js
|
||||
```
|
||||
|
||||
Finally, execute the script with the following command:
|
||||
|
||||
```bash
|
||||
node replace-imports.js
|
||||
```
|
||||
|
||||
This will scan your project files, apply the necessary import replacements, and provide a summary of the changes made.
|
||||
|
||||
---
|
||||
|
||||
## Next Steps
|
||||
|
||||
After running the codemod, review the changes made to your codebase. You can use `git diff` to see the modifications. Additionally, run your tests to ensure everything works as expected.
|
||||
|
||||
If everything is working correctly, you can remove the `replace-imports.js` file from your project. You can also remove the following packages from your `package.json`, as they're now included in the `@medusajs/framework` package:
|
||||
|
||||
- `@mikro-orm/*` packages (for example, `@mikro-orm/core`, `@mikro-orm/migrations`, etc.)
|
||||
- `awilix`
|
||||
- `pg`
|
||||
- `@opentelemetry/instrumentation-pg`
|
||||
- `@opentelemetry/resources`
|
||||
- `@opentelemetry/sdk-node`
|
||||
- `@opentelemetry/sdk-trace-node`
|
||||
@@ -40,13 +40,13 @@ Medusa uses [OpenTelemetry](https://opentelemetry.io/) for instrumentation and r
|
||||
|
||||
### Install Dependencies
|
||||
|
||||
Start by installing the following OpenTelemetry dependencies in your Medusa project:
|
||||
<Note>
|
||||
|
||||
```bash npm2yarn
|
||||
npm install @opentelemetry/sdk-node @opentelemetry/resources @opentelemetry/sdk-trace-node @opentelemetry/instrumentation-pg
|
||||
```
|
||||
As of [Medusa v2.11.0](https://github.com/medusajs/medusa/releases/tag/v2.11.0), OpenTelemetry dependencies are installed by default in new Medusa projects. If you're using an older version of Medusa, you need to install the `@opentelemetry/sdk-node`, `@opentelemetry/resources`, `@opentelemetry/sdk-trace-node`, and `@opentelemetry/instrumentation-pg` dependencies.
|
||||
|
||||
Also, install the dependencies relevant for the exporter you use. If you're using Zipkin, install the following dependencies:
|
||||
</Note>
|
||||
|
||||
Before you start, you must install the dependencies relevant for the exporter you use. If you're using Zipkin, install the following dependencies:
|
||||
|
||||
```bash npm2yarn
|
||||
npm install @opentelemetry/exporter-zipkin
|
||||
|
||||
@@ -63,8 +63,14 @@ if (process.env.TEST_TYPE === "integration:http") {
|
||||
|
||||
Next, create the `integration-tests/setup.js` file with the following content:
|
||||
|
||||
<Note>
|
||||
|
||||
As of [Medusa v2.11.0](https://github.com/medusajs/medusa/releases/tag/v2.11.0), MikroORM dependencies are included in the `@medusajs/framework` package. If you're using an older version of Medusa, change the require statement to `@mikro-orm/core`.
|
||||
|
||||
</Note>
|
||||
|
||||
```js title="integration-tests/setup.js"
|
||||
const { MetadataStorage } = require("@mikro-orm/core")
|
||||
const { MetadataStorage } = require("@medusajs/framework/@mikro-orm/core")
|
||||
|
||||
MetadataStorage.clear()
|
||||
```
|
||||
|
||||
@@ -98,9 +98,48 @@ For example, the `VITE_MY_API_KEY` environment variable in the example above wil
|
||||
|
||||
## Environment Variables in Plugins
|
||||
|
||||
As explained in the [previous section](#environment-variables-in-production), environment variables are inlined into the build. This presents a limitation for plugins, where you can't use environment variables.
|
||||
<Note>
|
||||
|
||||
Instead, only the following global variable is available in plugins:
|
||||
Environment variable support in plugins is available starting [Medusa v2.11.0](https://github.com/medusajs/medusa/releases/tag/v2.11.0). Refer to the [Medusa versions prior to v2.11.0](#for-medusa-versions-prior-to-v2110) section for more details if you're using an earlier version.
|
||||
|
||||
</Note>
|
||||
|
||||
For plugins, you can use environment variables without a prefix. Then, Medusa applications that use the plugin can set the environment variable with the `PLUGIN_` prefix.
|
||||
|
||||
For example, you can create a widget in your plugin that uses the `MY_API_KEY` environment variable:
|
||||
|
||||
```tsx highlights={[["8"]]}
|
||||
import { defineWidgetConfig } from "@medusajs/admin-sdk"
|
||||
import { Container, Heading } from "@medusajs/ui"
|
||||
|
||||
const ProductWidget = () => {
|
||||
return (
|
||||
<Container className="divide-y p-0">
|
||||
<div className="flex items-center justify-between px-6 py-4">
|
||||
<Heading level="h2">API Key: {import.meta.env.MY_API_KEY}</Heading>
|
||||
</div>
|
||||
</Container>
|
||||
)
|
||||
}
|
||||
|
||||
export const config = defineWidgetConfig({
|
||||
zone: "product.details.before",
|
||||
})
|
||||
|
||||
export default ProductWidget
|
||||
```
|
||||
|
||||
Then, in the Medusa application that uses the plugin, set the environment variable with the `PLUGIN_` prefix:
|
||||
|
||||
```bash
|
||||
PLUGIN_MY_API_KEY=sk_123
|
||||
```
|
||||
|
||||
The `MY_API_KEY` environment variable in the plugin will be replaced with the value of `PLUGIN_MY_API_KEY` during the build process of the Medusa application.
|
||||
|
||||
### Global Variables in Plugins
|
||||
|
||||
Plugins also have the following global variables available:
|
||||
|
||||
- `__BACKEND_URL__`: The URL of the Medusa backend, as set in the [Medusa configurations](../../../configurations/medusa-config/page.mdx#backendurl).
|
||||
- `__BASE__`: The base path of the Medusa Admin. (For example, `/app`).
|
||||
@@ -137,4 +176,14 @@ To fix possible type errors, create the file `src/admin/vite-env.d.ts` and add t
|
||||
declare const __BACKEND_URL__: string
|
||||
declare const __BASE__: string
|
||||
declare const __STOREFRONT_URL__: string
|
||||
```
|
||||
```
|
||||
|
||||
### For Medusa versions prior to v2.11.0
|
||||
|
||||
<Details summaryContent="Instructions for Medusa versions prior to v2.11.0">
|
||||
|
||||
As explained in the [Environment Variables in Production section](#environment-variables-in-production), environment variables are inlined into the build. This presents a limitation for plugins, where you can't use environment variables.
|
||||
|
||||
Instead, you can use the [Plugin Global Variables](#global-variables-in-plugins) described above to access the backend URL, base path, and storefront URL.
|
||||
|
||||
</Details>
|
||||
@@ -63,8 +63,14 @@ npx medusa db:generate blog
|
||||
|
||||
The `db:generate` command of the Medusa CLI accepts one or more module names to generate the migration for. It will create a migration file for the Blog Module in the directory `src/modules/blog/migrations` similar to the following:
|
||||
|
||||
<Note>
|
||||
|
||||
As of [Medusa v2.11.0](https://github.com/medusajs/medusa/releases/tag/v2.11.0), MikroORM dependencies are included in the `@medusajs/framework` package. If you're using an older version of Medusa, change the import statement to `@mikro-orm/migrations`.
|
||||
|
||||
</Note>
|
||||
|
||||
```ts
|
||||
import { Migration } from "@mikro-orm/migrations"
|
||||
import { Migration } from "@medusajs/framework/@mikro-orm/migrations"
|
||||
|
||||
export class Migration20241121103722 extends Migration {
|
||||
|
||||
|
||||
@@ -37,8 +37,14 @@ You can also write migrations manually. To do that, create a file in the `migrat
|
||||
|
||||
For example:
|
||||
|
||||
<Note>
|
||||
|
||||
As of [Medusa v2.11.0](https://github.com/medusajs/medusa/releases/tag/v2.11.0), MikroORM dependencies are included in the `@medusajs/framework` package. If you're using an older version of Medusa, change the import statement to `@mikro-orm/migrations`.
|
||||
|
||||
</Note>
|
||||
|
||||
```ts title="src/modules/blog/migrations/Migration202507021059_create_author.ts"
|
||||
import { Migration } from "@mikro-orm/migrations"
|
||||
import { Migration } from "@medusajs/framework/@mikro-orm/migrations"
|
||||
|
||||
export class Migration202507021059 extends Migration {
|
||||
|
||||
@@ -53,7 +59,7 @@ export class Migration202507021059 extends Migration {
|
||||
}
|
||||
```
|
||||
|
||||
The migration class in the file extends the `Migration` class imported from `@mikro-orm/migrations`. In the `up` and `down` method of the migration class, you use the `addSql` method provided by MikroORM's `Migration` class to run PostgreSQL syntax.
|
||||
The migration class in the file extends the `Migration` class imported from `@medusajs/framework/@mikro-orm/migrations`. In the `up` and `down` method of the migration class, you use the `addSql` method provided by MikroORM's `Migration` class to run PostgreSQL syntax.
|
||||
|
||||
In the example above, the `up` method creates the table `author`, and the `down` method drops the table if the migration is reverted.
|
||||
|
||||
|
||||
@@ -27,6 +27,12 @@ So, to run database queries in a service:
|
||||
|
||||
For example, in your service, add the following methods:
|
||||
|
||||
<Note>
|
||||
|
||||
As of [Medusa v2.11.0](https://github.com/medusajs/medusa/releases/tag/v2.11.0), MikroORM dependencies are included in the `@medusajs/framework` package. If you're using an older version of Medusa, change the import statement to `@mikro-orm/knex`.
|
||||
|
||||
</Note>
|
||||
|
||||
export const methodsHighlight = [
|
||||
["13", "getCount", "Retrieves the number of records in `my_custom` using the `count` method."],
|
||||
["20", "getCountSql", "Retrieves the number of records in `my_custom` using the `execute` method."]
|
||||
@@ -39,7 +45,7 @@ import {
|
||||
MedusaContext,
|
||||
} from "@medusajs/framework/utils"
|
||||
import { Context } from "@medusajs/framework/types"
|
||||
import { EntityManager } from "@mikro-orm/knex"
|
||||
import { EntityManager } from "@medusajs/framework/@mikro-orm/knex"
|
||||
|
||||
class BlogModuleService {
|
||||
// ...
|
||||
@@ -66,7 +72,7 @@ class BlogModuleService {
|
||||
|
||||
You add two methods `getCount` and `getCountSql` that have the `InjectManager` decorator. Each of the methods also accept the `sharedContext` parameter which has the `MedusaContext` decorator.
|
||||
|
||||
The entity manager is injected to the `sharedContext.manager` property, which is an instance of [EntityManager from the @mikro-orm/knex package](https://mikro-orm.io/api/knex/class/EntityManager).
|
||||
The entity manager is injected to the `sharedContext.manager` property, which is an instance of [EntityManager from the `@medusajs/framework/@mikro-orm/knex` package](https://mikro-orm.io/api/knex/class/EntityManager).
|
||||
|
||||
You use the manager in the `getCount` method to retrieve the number of records in a table, and in the `getCountSql` to run a PostgreSQL query that retrieves the count.
|
||||
|
||||
@@ -113,7 +119,7 @@ import {
|
||||
MedusaContext,
|
||||
} from "@medusajs/framework/utils"
|
||||
import { Context } from "@medusajs/framework/types"
|
||||
import { EntityManager } from "@mikro-orm/knex"
|
||||
import { EntityManager } from "@medusajs/framework/@mikro-orm/knex"
|
||||
|
||||
class BlogModuleService {
|
||||
// ...
|
||||
@@ -174,7 +180,7 @@ import {
|
||||
MedusaContext,
|
||||
} from "@medusajs/framework/utils"
|
||||
import { Context } from "@medusajs/framework/types"
|
||||
import { EntityManager } from "@mikro-orm/knex"
|
||||
import { EntityManager } from "@medusajs/framework/@mikro-orm/knex"
|
||||
|
||||
class BlogModuleService {
|
||||
// ...
|
||||
@@ -221,7 +227,7 @@ import {
|
||||
MedusaContext,
|
||||
} from "@medusajs/framework/utils"
|
||||
import { Context } from "@medusajs/framework/types"
|
||||
import { EntityManager } from "@mikro-orm/knex"
|
||||
import { EntityManager } from "@medusajs/framework/@mikro-orm/knex"
|
||||
|
||||
class BlogModuleService {
|
||||
// ...
|
||||
@@ -380,7 +386,7 @@ import {
|
||||
MedusaContext,
|
||||
} from "@medusajs/framework/utils"
|
||||
import { Context } from "@medusajs/framework/types"
|
||||
import { EntityManager } from "@mikro-orm/knex"
|
||||
import { EntityManager } from "@medusajs/framework/@mikro-orm/knex"
|
||||
|
||||
class BlogModuleService {
|
||||
// ...
|
||||
@@ -512,7 +518,7 @@ import {
|
||||
MedusaContext,
|
||||
} from "@medusajs/framework/utils"
|
||||
import { Context } from "@medusajs/framework/types"
|
||||
import { EntityManager } from "@mikro-orm/knex"
|
||||
import { EntityManager } from "@medusajs/framework/@mikro-orm/knex"
|
||||
|
||||
class BlogModuleService {
|
||||
// ...
|
||||
@@ -582,7 +588,7 @@ The second parameter of the `baseRepository_.transaction` method is an object of
|
||||
|
||||
```ts highlights={[["24"]]}
|
||||
// other imports...
|
||||
import { EntityManager } from "@mikro-orm/knex"
|
||||
import { EntityManager } from "@medusajs/framework/@mikro-orm/knex"
|
||||
import {
|
||||
InjectTransactionManager,
|
||||
MedusaContext,
|
||||
@@ -625,8 +631,8 @@ import {
|
||||
MedusaContext,
|
||||
} from "@medusajs/framework/utils"
|
||||
import { Context } from "@medusajs/framework/types"
|
||||
import { EntityManager } from "@mikro-orm/knex"
|
||||
import { IsolationLevel } from "@mikro-orm/core"
|
||||
import { EntityManager } from "@medusajs/framework/@mikro-orm/knex"
|
||||
import { IsolationLevel } from "@medusajs/framework/@mikro-orm/core"
|
||||
|
||||
class BlogModuleService {
|
||||
// ...
|
||||
@@ -660,7 +666,7 @@ import {
|
||||
MedusaContext,
|
||||
} from "@medusajs/framework/utils"
|
||||
import { Context } from "@medusajs/framework/types"
|
||||
import { EntityManager } from "@mikro-orm/knex"
|
||||
import { EntityManager } from "@medusajs/framework/@mikro-orm/knex"
|
||||
|
||||
class BlogModuleService {
|
||||
// ...
|
||||
|
||||
@@ -152,6 +152,12 @@ Consider your have a MongoDB module that allows you to perform operations on a M
|
||||
|
||||
To connect to the database, you create the following loader in your module:
|
||||
|
||||
<Note>
|
||||
|
||||
As of [Medusa v2.11.0](https://github.com/medusajs/medusa/releases/tag/v2.11.0), Awilix dependencies are included in the `@medusajs/framework` package. If you're using an older version of Medusa, change the import statement to `awilix`.
|
||||
|
||||
</Note>
|
||||
|
||||
export const loaderHighlights = [
|
||||
["5", "ModuleOptions", "Define a type for expected options."],
|
||||
["13", "ModuleOptions", "Pass the option type as a type argument to `LoaderOptions`."],
|
||||
@@ -163,7 +169,7 @@ export const loaderHighlights = [
|
||||
|
||||
```ts title="src/modules/mongo/loaders/connection.ts" highlights={loaderHighlights}
|
||||
import { LoaderOptions } from "@medusajs/framework/types"
|
||||
import { asValue } from "awilix"
|
||||
import { asValue } from "@medusajs/framework/awilix"
|
||||
import { MongoClient } from "mongodb"
|
||||
|
||||
type ModuleOptions = {
|
||||
@@ -233,7 +239,7 @@ In the loader, you check first that these options are set before proceeding. The
|
||||
After creating the client, you register it in the module's container using the container's `register` method. The method accepts two parameters:
|
||||
|
||||
1. The key to register the resource under, which in this case is `mongoClient`. You'll use this name later to resolve the client.
|
||||
2. The resource to register in the container, which is the MongoDB client you created. However, you don't pass the resource as-is. Instead, you need to use an `asValue` function imported from the [awilix package](https://github.com/jeffijoe/awilix), which is the package used to implement the container functionality in Medusa.
|
||||
2. The resource to register in the container, which is the MongoDB client you created. However, you don't pass the resource as-is. Instead, you need to use an `asValue` function imported from the [`@medusajs/framework/awilix` package](https://github.com/jeffijoe/awilix), which is the package used to implement the container functionality in Medusa.
|
||||
|
||||
### Use Custom Registered Resource in Module's Service
|
||||
|
||||
|
||||
@@ -195,8 +195,14 @@ npx medusa db:generate blog
|
||||
|
||||
The `db:generate` command of the Medusa CLI accepts one or more module names to generate the migration for. It will create a migration file for the Blog Module in the directory `src/modules/blog/migrations` similar to the following:
|
||||
|
||||
<Note>
|
||||
|
||||
As of [Medusa v2.11.0](https://github.com/medusajs/medusa/releases/tag/v2.11.0), MikroORM dependencies are included in the `@medusajs/framework` package. If you're using an older version of Medusa, change the import statement to `@mikro-orm/migrations`.
|
||||
|
||||
</Note>
|
||||
|
||||
```ts
|
||||
import { Migration } from "@mikro-orm/migrations"
|
||||
import { Migration } from "@medusajs/framework/@mikro-orm/migrations"
|
||||
|
||||
export class Migration20241121103722 extends Migration {
|
||||
|
||||
|
||||
@@ -70,17 +70,10 @@ A basic v2 project has the following dependencies in `package.json`:
|
||||
"@medusajs/admin-sdk": "2.8.2",
|
||||
"@medusajs/cli": "2.8.2",
|
||||
"@medusajs/framework": "2.8.2",
|
||||
"@medusajs/medusa": "2.8.2",
|
||||
"@mikro-orm/core": "6.4.3",
|
||||
"@mikro-orm/knex": "6.4.3",
|
||||
"@mikro-orm/migrations": "6.4.3",
|
||||
"@mikro-orm/postgresql": "6.4.3",
|
||||
"awilix": "^8.0.1",
|
||||
"pg": "^8.13.0"
|
||||
"@medusajs/medusa": "2.8.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@medusajs/test-utils": "2.8.2",
|
||||
"@mikro-orm/cli": "6.4.3",
|
||||
"@swc/core": "1.5.7",
|
||||
"@swc/jest": "^0.2.36",
|
||||
"@types/jest": "^29.5.13",
|
||||
@@ -107,25 +100,15 @@ The main changes are:
|
||||
- `@medusajs/framework`
|
||||
- `@medusajs/medusa`
|
||||
- `@medusajs/test-utils` (as a dev dependency)
|
||||
- You need to install the following extra packages:
|
||||
- Database packages:
|
||||
- `@mikro-orm/core@6.4.3`
|
||||
- `@mikro-orm/knex@6.4.3`
|
||||
- `@mikro-orm/migrations@6.4.3`
|
||||
- `@mikro-orm/postgresql@6.4.3`
|
||||
- `@mikro-orm/cli@6.4.3` (as a dev dependency)
|
||||
- `pg^8.13.0`
|
||||
- Framework packages:
|
||||
- `awilix@^8.0.1`
|
||||
- Development and Testing packages:
|
||||
- `@swc/core@1.5.7`
|
||||
- `@swc/jest@^0.2.36`
|
||||
- `@types/node@^20.0.0`
|
||||
- `jest@^29.7.0`
|
||||
- `ts-node@^10.9.2`
|
||||
- `typescript@^5.6.2`
|
||||
- `vite@^5.2.11`
|
||||
- `yalc@^1.0.0-pre.53`
|
||||
- You need to install the following extra packages for development and testing:
|
||||
- `@swc/core@1.5.7`
|
||||
- `@swc/jest@^0.2.36`
|
||||
- `@types/node@^20.0.0`
|
||||
- `jest@^29.7.0`
|
||||
- `ts-node@^10.9.2`
|
||||
- `typescript@^5.6.2`
|
||||
- `vite@^5.2.11`
|
||||
- `yalc@^1.0.0-pre.53`
|
||||
- Other packages, such as `@types/react` and `@types/react-dom`, are necessary for admin development and TypeScript support.
|
||||
|
||||
<Note>
|
||||
|
||||
@@ -10,7 +10,14 @@ In this chapter, you'll learn about the different modes of running a Medusa inst
|
||||
|
||||
## What is Worker Mode?
|
||||
|
||||
By default, the Medusa application runs both the server, which handles all incoming requests, and the worker, which processes background tasks, in a single process. While this setup is suitable for development, it is not optimal for production environments where background tasks can be long-running or resource-intensive.
|
||||
By default, the Medusa application runs in `shared` mode, which runs:
|
||||
|
||||
- `server`: the application server that handles incoming requests to the application's API routes.
|
||||
- `worker`: the worker that processes background tasks. This includes scheduled jobs and subscribers.
|
||||
|
||||
While this setup is suitable for development, it is not optimal for production environments where background tasks can be long-running or resource-intensive.
|
||||
|
||||
### Worker Mode in Production
|
||||
|
||||
In a production environment, you should deploy two separate instances of your Medusa application:
|
||||
|
||||
@@ -104,3 +111,27 @@ ADMIN_DISABLED=true
|
||||
|
||||
</CodeTab>
|
||||
</CodeTabs>
|
||||
|
||||
---
|
||||
|
||||
## Dividing Resources in Cluster Mode
|
||||
|
||||
<Note>
|
||||
|
||||
The `--servers` and `--workers` options were introduced in [Medusa v2.11.0](https://github.com/medusajs/medusa/releases/tag/v2.11.0).
|
||||
|
||||
</Note>
|
||||
|
||||
When running Medusa in [cluster mode](!resources!/medusa-cli/commands/start#starting-medusa-in-cluster-mode), you can specify the number or percentage of instances that are servers or workers by passing the `--servers` and `--workers` options:
|
||||
|
||||
```bash
|
||||
npx medusa start --cluster 4 --servers 25% --workers 75% # Use 4 CPU cores, with 25% as servers and 75% as workers
|
||||
npx medusa start --cluster 4 --servers 1 --workers 3 # Use 4 CPU cores, with 1 as server and 3 as workers
|
||||
npx medusa start --cluster 4 --servers 1 --workers 1 # Use 4 CPU cores, with 1 as server and 1 as worker (the remaining 2 will run in shared mode)
|
||||
```
|
||||
|
||||
In the above snippet you can see the following examples:
|
||||
|
||||
- In the first example, 25% of the instances (1 out of 4) will run as servers, and 75% (3 out of 4) will run as workers.
|
||||
- In the second example, 1 instance will run as a server, and 3 instances will run as workers.
|
||||
- In the third example, 1 instance will run as a server, and 1 instance will run as a worker. The remaining 2 instances will run in shared mode
|
||||
Reference in New Issue
Block a user