fix(create-medusa-app): ensure the same package manager is used consistently (#12714)
* fix(create-medusa-app): ensure the same package manager is used consistently * fix verbose not working as expected * improvements * remove legacy peer deps * format
This commit is contained in:
5
.changeset/shy-nails-enjoy.md
Normal file
5
.changeset/shy-nails-enjoy.md
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
---
|
||||||
|
"create-medusa-app": patch
|
||||||
|
---
|
||||||
|
|
||||||
|
fix(create-medusa-app): ensure the same package manager is used consistently
|
||||||
@@ -32,13 +32,15 @@ const execute = async (
|
|||||||
const childProcess = spawnSync(commandStr, {
|
const childProcess = spawnSync(commandStr, {
|
||||||
...options,
|
...options,
|
||||||
shell: true,
|
shell: true,
|
||||||
stdio: needOutput
|
stdio: needOutput ?
|
||||||
? "pipe"
|
"pipe" :
|
||||||
: [process.stdin, process.stdout, process.stderr],
|
[process.stdin, process.stdout, process.stderr],
|
||||||
})
|
})
|
||||||
|
|
||||||
if (childProcess.error) {
|
if (childProcess.error || childProcess.status !== 0) {
|
||||||
throw childProcess.error
|
throw childProcess.error ||
|
||||||
|
childProcess.stderr?.toString() ||
|
||||||
|
`${commandStr} failed with status ${childProcess.status}`
|
||||||
}
|
}
|
||||||
|
|
||||||
if (
|
if (
|
||||||
|
|||||||
87
packages/cli/create-medusa-app/src/utils/package-manager.ts
Normal file
87
packages/cli/create-medusa-app/src/utils/package-manager.ts
Normal file
@@ -0,0 +1,87 @@
|
|||||||
|
import execute from "./execute.js"
|
||||||
|
import ProcessManager from "./process-manager.js"
|
||||||
|
|
||||||
|
export default class PackageManager {
|
||||||
|
protected packageManager?: "npm" | "yarn"
|
||||||
|
protected processManager: ProcessManager
|
||||||
|
protected verbose
|
||||||
|
|
||||||
|
constructor(processManager: ProcessManager, verbose = false) {
|
||||||
|
this.processManager = processManager
|
||||||
|
this.verbose = verbose
|
||||||
|
}
|
||||||
|
|
||||||
|
async setPackageManager(execOptions: Record<string, unknown>): Promise<void> {
|
||||||
|
if (this.packageManager) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// check whether yarn is available
|
||||||
|
await this.processManager.runProcess({
|
||||||
|
process: async () => {
|
||||||
|
try {
|
||||||
|
await execute([`yarn -v`, execOptions], { verbose: this.verbose })
|
||||||
|
// yarn is available
|
||||||
|
this.packageManager = "yarn"
|
||||||
|
} catch (e) {
|
||||||
|
// yarn isn't available
|
||||||
|
// use npm
|
||||||
|
this.packageManager = "npm"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
ignoreERESOLVE: true,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
async installDependencies(
|
||||||
|
execOptions: Record<string, unknown>,
|
||||||
|
) {
|
||||||
|
if (!this.packageManager) {
|
||||||
|
await this.setPackageManager(execOptions)
|
||||||
|
}
|
||||||
|
|
||||||
|
const command = this.packageManager === "yarn" ?
|
||||||
|
`yarn` : `npm install`
|
||||||
|
|
||||||
|
await this.processManager.runProcess({
|
||||||
|
process: async () => {
|
||||||
|
await execute([command, execOptions], {
|
||||||
|
verbose: this.verbose
|
||||||
|
})
|
||||||
|
},
|
||||||
|
ignoreERESOLVE: true,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
async runCommand(
|
||||||
|
command: string,
|
||||||
|
execOptions: Record<string, unknown>,
|
||||||
|
) {
|
||||||
|
if (!this.packageManager) {
|
||||||
|
await this.setPackageManager(execOptions)
|
||||||
|
}
|
||||||
|
|
||||||
|
const commandStr = this.getCommandStr(command)
|
||||||
|
|
||||||
|
await this.processManager.runProcess({
|
||||||
|
process: async () => {
|
||||||
|
await execute([commandStr, execOptions], {
|
||||||
|
verbose: this.verbose
|
||||||
|
})
|
||||||
|
},
|
||||||
|
ignoreERESOLVE: true,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
getCommandStr(
|
||||||
|
command: string,
|
||||||
|
): string {
|
||||||
|
if (!this.packageManager) {
|
||||||
|
throw new Error("Package manager not set")
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.packageManager === "yarn"
|
||||||
|
? `yarn ${command}`
|
||||||
|
: `npm run ${command}`
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -6,6 +6,7 @@ import { EOL } from "os"
|
|||||||
import { displayFactBox, FactBoxOptions } from "./facts.js"
|
import { displayFactBox, FactBoxOptions } from "./facts.js"
|
||||||
import ProcessManager from "./process-manager.js"
|
import ProcessManager from "./process-manager.js"
|
||||||
import type { Client } from "pg"
|
import type { Client } from "pg"
|
||||||
|
import PackageManager from "./package-manager.js"
|
||||||
|
|
||||||
const ADMIN_EMAIL = "admin@medusa-test.com"
|
const ADMIN_EMAIL = "admin@medusa-test.com"
|
||||||
let STORE_CORS = "http://localhost:8000"
|
let STORE_CORS = "http://localhost:8000"
|
||||||
@@ -24,6 +25,7 @@ type PreparePluginOptions = {
|
|||||||
processManager: ProcessManager
|
processManager: ProcessManager
|
||||||
abortController?: AbortController
|
abortController?: AbortController
|
||||||
verbose?: boolean
|
verbose?: boolean
|
||||||
|
packageManager: PackageManager
|
||||||
}
|
}
|
||||||
|
|
||||||
type PrepareProjectOptions = {
|
type PrepareProjectOptions = {
|
||||||
@@ -42,6 +44,7 @@ type PrepareProjectOptions = {
|
|||||||
nextjsDirectory?: string
|
nextjsDirectory?: string
|
||||||
client: Client | null
|
client: Client | null
|
||||||
verbose?: boolean
|
verbose?: boolean
|
||||||
|
packageManager: PackageManager
|
||||||
}
|
}
|
||||||
|
|
||||||
type PrepareOptions = PreparePluginOptions | PrepareProjectOptions
|
type PrepareOptions = PreparePluginOptions | PrepareProjectOptions
|
||||||
@@ -66,6 +69,7 @@ async function preparePlugin({
|
|||||||
processManager,
|
processManager,
|
||||||
abortController,
|
abortController,
|
||||||
verbose = false,
|
verbose = false,
|
||||||
|
packageManager,
|
||||||
}: PreparePluginOptions) {
|
}: PreparePluginOptions) {
|
||||||
// initialize execution options
|
// initialize execution options
|
||||||
const execOptions = {
|
const execOptions = {
|
||||||
@@ -98,20 +102,7 @@ async function preparePlugin({
|
|||||||
processManager,
|
processManager,
|
||||||
})
|
})
|
||||||
|
|
||||||
await processManager.runProcess({
|
await packageManager.installDependencies(execOptions)
|
||||||
process: async () => {
|
|
||||||
try {
|
|
||||||
await execute([`yarn`, execOptions], { verbose })
|
|
||||||
} catch (e) {
|
|
||||||
// yarn isn't available
|
|
||||||
// use npm
|
|
||||||
await execute([`npm install --legacy-peer-deps`, execOptions], {
|
|
||||||
verbose,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
},
|
|
||||||
ignoreERESOLVE: true,
|
|
||||||
})
|
|
||||||
|
|
||||||
factBoxOptions.interval = displayFactBox({
|
factBoxOptions.interval = displayFactBox({
|
||||||
...factBoxOptions,
|
...factBoxOptions,
|
||||||
@@ -136,6 +127,7 @@ async function prepareProject({
|
|||||||
nextjsDirectory = "",
|
nextjsDirectory = "",
|
||||||
client,
|
client,
|
||||||
verbose = false,
|
verbose = false,
|
||||||
|
packageManager,
|
||||||
}: PrepareProjectOptions) {
|
}: PrepareProjectOptions) {
|
||||||
// initialize execution options
|
// initialize execution options
|
||||||
const execOptions = {
|
const execOptions = {
|
||||||
@@ -196,20 +188,7 @@ async function prepareProject({
|
|||||||
processManager,
|
processManager,
|
||||||
})
|
})
|
||||||
|
|
||||||
await processManager.runProcess({
|
await packageManager.installDependencies(execOptions)
|
||||||
process: async () => {
|
|
||||||
try {
|
|
||||||
await execute([`yarn`, execOptions], { verbose })
|
|
||||||
} catch (e) {
|
|
||||||
// yarn isn't available
|
|
||||||
// use npm
|
|
||||||
await execute([`npm install --legacy-peer-deps`, execOptions], {
|
|
||||||
verbose,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
},
|
|
||||||
ignoreERESOLVE: true,
|
|
||||||
})
|
|
||||||
|
|
||||||
factBoxOptions.interval = displayFactBox({
|
factBoxOptions.interval = displayFactBox({
|
||||||
...factBoxOptions,
|
...factBoxOptions,
|
||||||
@@ -285,18 +264,7 @@ async function prepareProject({
|
|||||||
title: "Seeding database...",
|
title: "Seeding database...",
|
||||||
})
|
})
|
||||||
|
|
||||||
await processManager.runProcess({
|
await packageManager.runCommand("seed", execOptions)
|
||||||
process: async () => {
|
|
||||||
try {
|
|
||||||
await execute([`yarn seed`, execOptions], { verbose })
|
|
||||||
} catch (e) {
|
|
||||||
// yarn isn't available
|
|
||||||
// use npm
|
|
||||||
await execute([`npm run seed`, execOptions], { verbose })
|
|
||||||
}
|
|
||||||
},
|
|
||||||
ignoreERESOLVE: true,
|
|
||||||
})
|
|
||||||
|
|
||||||
displayFactBox({
|
displayFactBox({
|
||||||
...factBoxOptions,
|
...factBoxOptions,
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import path from "path"
|
|||||||
import createAbortController from "../create-abort-controller.js"
|
import createAbortController from "../create-abort-controller.js"
|
||||||
import { FactBoxOptions } from "../facts.js"
|
import { FactBoxOptions } from "../facts.js"
|
||||||
import ProcessManager from "../process-manager.js"
|
import ProcessManager from "../process-manager.js"
|
||||||
|
import PackageManager from "../package-manager.js"
|
||||||
|
|
||||||
export interface ProjectOptions {
|
export interface ProjectOptions {
|
||||||
repoUrl?: string
|
repoUrl?: string
|
||||||
@@ -25,6 +26,7 @@ export interface ProjectCreator {
|
|||||||
export abstract class BaseProjectCreator {
|
export abstract class BaseProjectCreator {
|
||||||
protected spinner: Ora
|
protected spinner: Ora
|
||||||
protected processManager: ProcessManager
|
protected processManager: ProcessManager
|
||||||
|
protected packageManager: PackageManager
|
||||||
protected abortController: AbortController
|
protected abortController: AbortController
|
||||||
protected factBoxOptions: FactBoxOptions
|
protected factBoxOptions: FactBoxOptions
|
||||||
protected projectName: string
|
protected projectName: string
|
||||||
@@ -39,6 +41,7 @@ export abstract class BaseProjectCreator {
|
|||||||
) {
|
) {
|
||||||
this.spinner = ora()
|
this.spinner = ora()
|
||||||
this.processManager = new ProcessManager()
|
this.processManager = new ProcessManager()
|
||||||
|
this.packageManager = new PackageManager(this.processManager)
|
||||||
this.abortController = createAbortController(this.processManager)
|
this.abortController = createAbortController(this.processManager)
|
||||||
this.projectName = projectName
|
this.projectName = projectName
|
||||||
const basePath =
|
const basePath =
|
||||||
|
|||||||
@@ -72,6 +72,7 @@ export class PluginProjectCreator
|
|||||||
processManager: this.processManager,
|
processManager: this.processManager,
|
||||||
abortController: this.abortController,
|
abortController: this.abortController,
|
||||||
verbose: this.options.verbose,
|
verbose: this.options.verbose,
|
||||||
|
packageManager: this.packageManager,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -153,6 +153,7 @@ export class MedusaProjectCreator
|
|||||||
nextjsDirectory: this.nextjsDirectory,
|
nextjsDirectory: this.nextjsDirectory,
|
||||||
client: this.client,
|
client: this.client,
|
||||||
verbose: this.options.verbose,
|
verbose: this.options.verbose,
|
||||||
|
packageManager: this.packageManager,
|
||||||
})
|
})
|
||||||
} finally {
|
} finally {
|
||||||
await this.client?.end()
|
await this.client?.end()
|
||||||
@@ -214,18 +215,19 @@ export class MedusaProjectCreator
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected showSuccessMessage(): void {
|
protected showSuccessMessage(): void {
|
||||||
|
const commandStr = this.packageManager.getCommandStr(`dev`)
|
||||||
logMessage({
|
logMessage({
|
||||||
message: boxen(
|
message: boxen(
|
||||||
chalk.green(
|
chalk.green(
|
||||||
`Change to the \`${
|
`Change to the \`${
|
||||||
this.projectName
|
this.projectName
|
||||||
}\` directory to explore your Medusa project.${EOL}${EOL}Start your Medusa application again with the following command:${EOL}${EOL}yarn dev${EOL}${EOL}${
|
}\` directory to explore your Medusa project.${EOL}${EOL}Start your Medusa application again with the following command:${EOL}${EOL}${commandStr}${EOL}${EOL}${
|
||||||
this.inviteToken
|
this.inviteToken
|
||||||
? `After you start the Medusa application, you can create an admin user with the URL http://localhost:9000/app/invite?token=${this.inviteToken}&first_run=true${EOL}${EOL}`
|
? `After you start the Medusa application, you can create an admin user with the URL http://localhost:9000/app/invite?token=${this.inviteToken}&first_run=true${EOL}${EOL}`
|
||||||
: ""
|
: ""
|
||||||
}${
|
}${
|
||||||
this.nextjsDirectory?.length
|
this.nextjsDirectory?.length
|
||||||
? `The Next.js Starter Storefront was installed in the \`${this.nextjsDirectory}\` directory. Change to that directory and start it with the following command:${EOL}${EOL}npm run dev${EOL}${EOL}`
|
? `The Next.js Starter Storefront was installed in the \`${this.nextjsDirectory}\` directory. Change to that directory and start it with the following command:${EOL}${EOL}${commandStr}${EOL}${EOL}`
|
||||||
: ""
|
: ""
|
||||||
}Check out the Medusa documentation to start your development:${EOL}${EOL}https://docs.medusajs.com/${EOL}${EOL}Star us on GitHub if you like what we're building:${EOL}${EOL}https://github.com/medusajs/medusa/stargazers`
|
}Check out the Medusa documentation to start your development:${EOL}${EOL}https://docs.medusajs.com/${EOL}${EOL}Star us on GitHub if you like what we're building:${EOL}${EOL}https://github.com/medusajs/medusa/stargazers`
|
||||||
),
|
),
|
||||||
|
|||||||
Reference in New Issue
Block a user