Feat/plugin develop (#10926)
Fixes: FRMW-2865 In this PR we add support for developing a plugin in watch mode. During the file change, we re-compile the source code (incrementally), publishes the package, and updates the installations of the plugin. We are using `yalc` under the hood and it must be installed as a dev dependency in the plugin project and the main Medusa app.
This commit is contained in:
@@ -0,0 +1,7 @@
|
|||||||
|
---
|
||||||
|
"@medusajs/medusa": patch
|
||||||
|
"@medusajs/framework": patch
|
||||||
|
"@medusajs/cli": patch
|
||||||
|
---
|
||||||
|
|
||||||
|
Feat/plugin develop
|
||||||
@@ -254,6 +254,18 @@ function buildLocalCommands(cli, isLocalProject) {
|
|||||||
})
|
})
|
||||||
),
|
),
|
||||||
})
|
})
|
||||||
|
.command({
|
||||||
|
command: "plugin:develop",
|
||||||
|
desc: "Start plugin development process in watch mode. Changes will be re-published to the local packages registry",
|
||||||
|
builder: (builder) => {},
|
||||||
|
handler: handlerP(
|
||||||
|
getCommandHandler("plugin/develop", (args, cmd) => {
|
||||||
|
process.env.NODE_ENV = process.env.NODE_ENV || `development`
|
||||||
|
cmd(args)
|
||||||
|
return new Promise(() => {})
|
||||||
|
})
|
||||||
|
),
|
||||||
|
})
|
||||||
.command({
|
.command({
|
||||||
command: `telemetry`,
|
command: `telemetry`,
|
||||||
describe: `Enable or disable collection of anonymous usage data.`,
|
describe: `Enable or disable collection of anonymous usage data.`,
|
||||||
@@ -310,7 +322,7 @@ function buildLocalCommands(cli, isLocalProject) {
|
|||||||
// Return an empty promise to prevent handlerP from exiting early.
|
// Return an empty promise to prevent handlerP from exiting early.
|
||||||
// The development server shouldn't ever exit until the user directly
|
// The development server shouldn't ever exit until the user directly
|
||||||
// kills it so this is fine.
|
// kills it so this is fine.
|
||||||
return new Promise((resolve) => {})
|
return new Promise(() => {})
|
||||||
})
|
})
|
||||||
),
|
),
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -23,15 +23,26 @@ import type { AdminOptions, ConfigModule, Logger } from "@medusajs/types"
|
|||||||
export class Compiler {
|
export class Compiler {
|
||||||
#logger: Logger
|
#logger: Logger
|
||||||
#projectRoot: string
|
#projectRoot: string
|
||||||
|
#tsConfigPath: string
|
||||||
#adminSourceFolder: string
|
#adminSourceFolder: string
|
||||||
|
#pluginsDistFolder: string
|
||||||
|
#backendIgnoreFiles: string[]
|
||||||
#adminOnlyDistFolder: string
|
#adminOnlyDistFolder: string
|
||||||
#tsCompiler?: typeof tsStatic
|
#tsCompiler?: typeof tsStatic
|
||||||
|
|
||||||
constructor(projectRoot: string, logger: Logger) {
|
constructor(projectRoot: string, logger: Logger) {
|
||||||
this.#projectRoot = projectRoot
|
this.#projectRoot = projectRoot
|
||||||
this.#logger = logger
|
this.#logger = logger
|
||||||
|
this.#tsConfigPath = path.join(this.#projectRoot, "tsconfig.json")
|
||||||
this.#adminSourceFolder = path.join(this.#projectRoot, "src/admin")
|
this.#adminSourceFolder = path.join(this.#projectRoot, "src/admin")
|
||||||
this.#adminOnlyDistFolder = path.join(this.#projectRoot, ".medusa/admin")
|
this.#adminOnlyDistFolder = path.join(this.#projectRoot, ".medusa/admin")
|
||||||
|
this.#pluginsDistFolder = path.join(this.#projectRoot, ".medusa/server")
|
||||||
|
this.#backendIgnoreFiles = [
|
||||||
|
"integration-tests",
|
||||||
|
"test",
|
||||||
|
"unit-tests",
|
||||||
|
"src/admin",
|
||||||
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -141,6 +152,20 @@ export class Compiler {
|
|||||||
return { configFilePath, configModule }
|
return { configFilePath, configModule }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Prints typescript diagnostic messages
|
||||||
|
*/
|
||||||
|
#printDiagnostics(ts: typeof tsStatic, diagnostics: tsStatic.Diagnostic[]) {
|
||||||
|
if (diagnostics.length) {
|
||||||
|
console.error(
|
||||||
|
ts.formatDiagnosticsWithColorAndContext(
|
||||||
|
diagnostics,
|
||||||
|
ts.createCompilerHost({})
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Given a tsconfig file, this method will write the compiled
|
* Given a tsconfig file, this method will write the compiled
|
||||||
* output to the specified destination
|
* output to the specified destination
|
||||||
@@ -177,14 +202,7 @@ export class Compiler {
|
|||||||
/**
|
/**
|
||||||
* Log errors (if any)
|
* Log errors (if any)
|
||||||
*/
|
*/
|
||||||
if (diagnostics.length) {
|
this.#printDiagnostics(ts, diagnostics)
|
||||||
console.error(
|
|
||||||
ts.formatDiagnosticsWithColorAndContext(
|
|
||||||
diagnostics,
|
|
||||||
ts.createCompilerHost({})
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
return { emitResult, diagnostics }
|
return { emitResult, diagnostics }
|
||||||
}
|
}
|
||||||
@@ -198,7 +216,7 @@ export class Compiler {
|
|||||||
let tsConfigErrors: tsStatic.Diagnostic[] = []
|
let tsConfigErrors: tsStatic.Diagnostic[] = []
|
||||||
|
|
||||||
const tsConfig = ts.getParsedCommandLineOfConfigFile(
|
const tsConfig = ts.getParsedCommandLineOfConfigFile(
|
||||||
path.join(this.#projectRoot, "tsconfig.json"),
|
this.#tsConfigPath,
|
||||||
{
|
{
|
||||||
inlineSourceMap: true,
|
inlineSourceMap: true,
|
||||||
excludes: [],
|
excludes: [],
|
||||||
@@ -223,18 +241,17 @@ export class Compiler {
|
|||||||
/**
|
/**
|
||||||
* Display all config errors using the diagnostics reporter
|
* Display all config errors using the diagnostics reporter
|
||||||
*/
|
*/
|
||||||
|
this.#printDiagnostics(ts, tsConfigErrors)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return undefined when there are errors in parsing the config
|
||||||
|
* file
|
||||||
|
*/
|
||||||
if (tsConfigErrors.length) {
|
if (tsConfigErrors.length) {
|
||||||
const compilerHost = ts.createCompilerHost({})
|
|
||||||
this.#logger.error(
|
|
||||||
ts.formatDiagnosticsWithColorAndContext(tsConfigErrors, compilerHost)
|
|
||||||
)
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
return tsConfig
|
||||||
* If there are no errors, the `tsConfig` object will always exist.
|
|
||||||
*/
|
|
||||||
return tsConfig!
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -262,7 +279,7 @@ export class Compiler {
|
|||||||
*/
|
*/
|
||||||
const { emitResult, diagnostics } = await this.#emitBuildOutput(
|
const { emitResult, diagnostics } = await this.#emitBuildOutput(
|
||||||
tsConfig,
|
tsConfig,
|
||||||
["integration-tests", "test", "unit-tests", "src/admin"],
|
this.#backendIgnoreFiles,
|
||||||
dist
|
dist
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -365,9 +382,61 @@ export class Compiler {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
// @todo
|
||||||
* @todo. To be implemented
|
|
||||||
*/
|
|
||||||
buildPluginBackend() {}
|
buildPluginBackend() {}
|
||||||
developPluginBacked() {}
|
|
||||||
|
/**
|
||||||
|
* Compiles the backend source code of a plugin project in watch
|
||||||
|
* mode. Type-checking is disabled to keep compilation fast.
|
||||||
|
*
|
||||||
|
* The "onFileChange" argument can be used to get notified when
|
||||||
|
* a file has changed.
|
||||||
|
*/
|
||||||
|
async developPluginBackend(onFileChange?: () => void) {
|
||||||
|
const ts = await this.#loadTSCompiler()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Format host is needed to print diagnostic messages
|
||||||
|
*/
|
||||||
|
const formatHost: tsStatic.FormatDiagnosticsHost = {
|
||||||
|
getCanonicalFileName: (path) => path,
|
||||||
|
getCurrentDirectory: ts.sys.getCurrentDirectory,
|
||||||
|
getNewLine: () => ts.sys.newLine,
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creating a watcher compiler host to watch files and recompile
|
||||||
|
* them as they are changed
|
||||||
|
*/
|
||||||
|
const host = ts.createWatchCompilerHost(
|
||||||
|
this.#tsConfigPath,
|
||||||
|
{
|
||||||
|
outDir: this.#pluginsDistFolder,
|
||||||
|
noCheck: true,
|
||||||
|
},
|
||||||
|
ts.sys,
|
||||||
|
ts.createEmitAndSemanticDiagnosticsBuilderProgram,
|
||||||
|
(diagnostic) => this.#printDiagnostics(ts, [diagnostic]),
|
||||||
|
(diagnostic) => {
|
||||||
|
if (typeof diagnostic.messageText === "string") {
|
||||||
|
this.#logger.info(diagnostic.messageText)
|
||||||
|
} else {
|
||||||
|
this.#logger.info(
|
||||||
|
ts.formatDiagnosticsWithColorAndContext([diagnostic], formatHost)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
excludeDirectories: this.#backendIgnoreFiles,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
const origPostProgramCreate = host.afterProgramCreate
|
||||||
|
host.afterProgramCreate = (program) => {
|
||||||
|
origPostProgramCreate!(program)
|
||||||
|
onFileChange?.()
|
||||||
|
}
|
||||||
|
|
||||||
|
ts.createWatchProgram(host)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -57,7 +57,8 @@
|
|||||||
"@types/multer": "^1.4.7",
|
"@types/multer": "^1.4.7",
|
||||||
"jest": "^29.7.0",
|
"jest": "^29.7.0",
|
||||||
"rimraf": "^5.0.1",
|
"rimraf": "^5.0.1",
|
||||||
"typescript": "^5.6.2"
|
"typescript": "^5.6.2",
|
||||||
|
"yalc": "1.0.0-pre.53"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@inquirer/checkbox": "^2.3.11",
|
"@inquirer/checkbox": "^2.3.11",
|
||||||
@@ -130,7 +131,13 @@
|
|||||||
"@mikro-orm/knex": "5.9.7",
|
"@mikro-orm/knex": "5.9.7",
|
||||||
"@mikro-orm/migrations": "5.9.7",
|
"@mikro-orm/migrations": "5.9.7",
|
||||||
"@mikro-orm/postgresql": "5.9.7",
|
"@mikro-orm/postgresql": "5.9.7",
|
||||||
"awilix": "^8.0.1"
|
"awilix": "^8.0.1",
|
||||||
|
"yalc": "1.0.0-pre.53"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"yalc": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"gitHead": "cd1f5afa5aa8c0b15ea957008ee19f1d695cbd2e"
|
"gitHead": "cd1f5afa5aa8c0b15ea957008ee19f1d695cbd2e"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,19 @@
|
|||||||
|
import * as yalc from "yalc"
|
||||||
|
import { logger } from "@medusajs/framework/logger"
|
||||||
|
import { Compiler } from "@medusajs/framework/build-tools"
|
||||||
|
|
||||||
|
export default async function developPlugin({
|
||||||
|
directory,
|
||||||
|
}: {
|
||||||
|
directory: string
|
||||||
|
}) {
|
||||||
|
const compiler = new Compiler(directory, logger)
|
||||||
|
await compiler.developPluginBackend(async () => {
|
||||||
|
await yalc.publishPackage({
|
||||||
|
push: true,
|
||||||
|
workingDir: directory,
|
||||||
|
changed: true,
|
||||||
|
replace: true,
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
@@ -6132,6 +6132,7 @@ __metadata:
|
|||||||
slugify: ^1.6.6
|
slugify: ^1.6.6
|
||||||
typescript: ^5.6.2
|
typescript: ^5.6.2
|
||||||
uuid: ^9.0.0
|
uuid: ^9.0.0
|
||||||
|
yalc: 1.0.0-pre.53
|
||||||
zod: 3.22.4
|
zod: 3.22.4
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
"@medusajs/framework": ^2.0.0
|
"@medusajs/framework": ^2.0.0
|
||||||
@@ -6140,6 +6141,10 @@ __metadata:
|
|||||||
"@mikro-orm/migrations": 5.9.7
|
"@mikro-orm/migrations": 5.9.7
|
||||||
"@mikro-orm/postgresql": 5.9.7
|
"@mikro-orm/postgresql": 5.9.7
|
||||||
awilix: ^8.0.1
|
awilix: ^8.0.1
|
||||||
|
yalc: 1.0.0-pre.53
|
||||||
|
peerDependenciesMeta:
|
||||||
|
yalc:
|
||||||
|
optional: true
|
||||||
languageName: unknown
|
languageName: unknown
|
||||||
linkType: soft
|
linkType: soft
|
||||||
|
|
||||||
@@ -20760,7 +20765,7 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"fs-extra@npm:8.1.0, fs-extra@npm:^8.1, fs-extra@npm:^8.1.0":
|
"fs-extra@npm:8.1.0, fs-extra@npm:^8.0.1, fs-extra@npm:^8.1, fs-extra@npm:^8.1.0":
|
||||||
version: 8.1.0
|
version: 8.1.0
|
||||||
resolution: "fs-extra@npm:8.1.0"
|
resolution: "fs-extra@npm:8.1.0"
|
||||||
dependencies:
|
dependencies:
|
||||||
@@ -21797,6 +21802,15 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"ignore-walk@npm:^3.0.3":
|
||||||
|
version: 3.0.4
|
||||||
|
resolution: "ignore-walk@npm:3.0.4"
|
||||||
|
dependencies:
|
||||||
|
minimatch: ^3.0.4
|
||||||
|
checksum: 690372b433887796fa3badd25babab7daf60a1882259dcc130ec78eea79745c2416322e10d1a96b367071204471c532647d20b11cd7ab70bd9b49879e461f956
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"ignore@npm:^4.0.6":
|
"ignore@npm:^4.0.6":
|
||||||
version: 4.0.6
|
version: 4.0.6
|
||||||
resolution: "ignore@npm:4.0.6"
|
resolution: "ignore@npm:4.0.6"
|
||||||
@@ -21804,6 +21818,13 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"ignore@npm:^5.0.4":
|
||||||
|
version: 5.3.2
|
||||||
|
resolution: "ignore@npm:5.3.2"
|
||||||
|
checksum: f9f652c957983634ded1e7f02da3b559a0d4cc210fca3792cb67f1b153623c9c42efdc1c4121af171e295444459fc4a9201101fb041b1104a3c000bccb188337
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"ignore@npm:^5.2.0, ignore@npm:^5.2.4":
|
"ignore@npm:^5.2.0, ignore@npm:^5.2.4":
|
||||||
version: 5.3.1
|
version: 5.3.1
|
||||||
resolution: "ignore@npm:5.3.1"
|
resolution: "ignore@npm:5.3.1"
|
||||||
@@ -21936,6 +21957,13 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"ini@npm:^2.0.0":
|
||||||
|
version: 2.0.0
|
||||||
|
resolution: "ini@npm:2.0.0"
|
||||||
|
checksum: 2e0c8f386369139029da87819438b20a1ff3fe58372d93fb1a86e9d9344125ace3a806b8ec4eb160a46e64cbc422fe68251869441676af49b7fc441af2389c25
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"inquirer@npm:^8.0.0":
|
"inquirer@npm:^8.0.0":
|
||||||
version: 8.2.6
|
version: 8.2.6
|
||||||
resolution: "inquirer@npm:8.2.6"
|
resolution: "inquirer@npm:8.2.6"
|
||||||
@@ -25831,6 +25859,36 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"npm-bundled@npm:^1.1.1":
|
||||||
|
version: 1.1.2
|
||||||
|
resolution: "npm-bundled@npm:1.1.2"
|
||||||
|
dependencies:
|
||||||
|
npm-normalize-package-bin: ^1.0.1
|
||||||
|
checksum: 3f2337789afc8cb608a0dd71cefe459531053d48a5497db14b07b985c4cab15afcae88600db9f92eae072c89b982eeeec8e4463e1d77bc03a7e90f5dacf29769
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
|
"npm-normalize-package-bin@npm:^1.0.1":
|
||||||
|
version: 1.0.1
|
||||||
|
resolution: "npm-normalize-package-bin@npm:1.0.1"
|
||||||
|
checksum: b0c8c05fe419a122e0ff970ccbe7874ae24b4b4b08941a24d18097fe6e1f4b93e3f6abfb5512f9c5488827a5592f2fb3ce2431c41d338802aed24b9a0c160551
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
|
"npm-packlist@npm:^2.1.5":
|
||||||
|
version: 2.2.2
|
||||||
|
resolution: "npm-packlist@npm:2.2.2"
|
||||||
|
dependencies:
|
||||||
|
glob: ^7.1.6
|
||||||
|
ignore-walk: ^3.0.3
|
||||||
|
npm-bundled: ^1.1.1
|
||||||
|
npm-normalize-package-bin: ^1.0.1
|
||||||
|
bin:
|
||||||
|
npm-packlist: bin/index.js
|
||||||
|
checksum: cf0b1350bfa2e4bdef5e283365fb54811bd095f4b6c8e5f1352a12a155f9aafbd22776b5a79fea7c5e952fab2e72c40f54cea2e139d7d705cfc6f6f955f1aa48
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"npm-run-path@npm:^2.0.0":
|
"npm-run-path@npm:^2.0.0":
|
||||||
version: 2.0.2
|
version: 2.0.2
|
||||||
resolution: "npm-run-path@npm:2.0.2"
|
resolution: "npm-run-path@npm:2.0.2"
|
||||||
@@ -33799,6 +33857,24 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"yalc@npm:1.0.0-pre.53":
|
||||||
|
version: 1.0.0-pre.53
|
||||||
|
resolution: "yalc@npm:1.0.0-pre.53"
|
||||||
|
dependencies:
|
||||||
|
chalk: ^4.1.0
|
||||||
|
detect-indent: ^6.0.0
|
||||||
|
fs-extra: ^8.0.1
|
||||||
|
glob: ^7.1.4
|
||||||
|
ignore: ^5.0.4
|
||||||
|
ini: ^2.0.0
|
||||||
|
npm-packlist: ^2.1.5
|
||||||
|
yargs: ^16.1.1
|
||||||
|
bin:
|
||||||
|
yalc: src/yalc.js
|
||||||
|
checksum: 630f65b00740da6d568d46748a40e2bf2c872cf9babe7c319642a5b6db2dcd0a5d4a34e249d20099709e3ba09bb7e9b34ff78af5cd54c690668e094e156551c9
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"yallist@npm:^2.1.2":
|
"yallist@npm:^2.1.2":
|
||||||
version: 2.1.2
|
version: 2.1.2
|
||||||
resolution: "yallist@npm:2.1.2"
|
resolution: "yallist@npm:2.1.2"
|
||||||
@@ -33916,7 +33992,7 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"yargs@npm:^16.1.0":
|
"yargs@npm:^16.1.0, yargs@npm:^16.1.1":
|
||||||
version: 16.2.0
|
version: 16.2.0
|
||||||
resolution: "yargs@npm:16.2.0"
|
resolution: "yargs@npm:16.2.0"
|
||||||
dependencies:
|
dependencies:
|
||||||
|
|||||||
Reference in New Issue
Block a user