feat(create-medusa-app): install v2 by default (#7381)

- Remove `v2` option and install V2 starter branch by default.
- Use new `exec` command to seed data
- Install v2 branch of next.js starter if the option is provided.
- Change the opened browser to `localhost:9000/app`.
- Added a bunch of todos for onboarding flows once we have that
This commit is contained in:
Shahed Nasser
2024-05-21 22:45:43 +03:00
committed by GitHub
parent 1f43290cec
commit e443a7be3f
8 changed files with 82 additions and 105 deletions

View File

@@ -8,6 +8,7 @@
"license": "MIT",
"scripts": {
"dev": "ts-node --esm src/index.ts",
"start": "node dist/index.js",
"build": "tsc",
"watch": "tsc --watch",
"prepublishOnly": "cross-env NODE_ENV=production tsc --build"

View File

@@ -34,7 +34,6 @@ const isEmail = isEmailImported.default
export type CreateOptions = {
repoUrl?: string
seed?: boolean
// commander passed --no-boilerplate as boilerplate
boilerplate?: boolean
skipDb?: boolean
dbUrl?: string
@@ -43,7 +42,6 @@ export type CreateOptions = {
directoryPath?: string
withNextjsStarter?: boolean
verbose?: boolean
v2?: boolean
}
export default async ({
@@ -57,7 +55,6 @@ export default async ({
directoryPath,
withNextjsStarter = false,
verbose = false,
v2 = false,
}: CreateOptions) => {
track("CREATE_CLI_CMA")
@@ -142,7 +139,6 @@ export default async ({
abortController,
spinner,
verbose,
v2,
})
} catch {
return
@@ -159,6 +155,7 @@ export default async ({
abortController,
factBoxOptions,
verbose,
processManager
})
: ""
@@ -195,7 +192,6 @@ export default async ({
nextjsDirectory,
client,
verbose,
v2,
})
} catch (e: any) {
if (isAbortError(e)) {
@@ -257,14 +253,10 @@ export default async ({
await waitOn({
resources: ["http://localhost:9000/health"],
}).then(async () => {
if (v2) {
return
}
open(
inviteToken
? `http://localhost:7001/invite?token=${inviteToken}&first_run=true`
: "http://localhost:7001"
? `http://localhost:9000/app/invite?token=${inviteToken}&first_run=true`
: "http://localhost:9000/app"
)
})
}
@@ -324,7 +316,7 @@ function showSuccessMessage(
message: boxen(
chalk.green(
// eslint-disable-next-line prettier/prettier
`Change to the \`${projectName}\` directory to explore your Medusa project.${EOL}${EOL}Start your Medusa app again with the following command:${EOL}${EOL}npx @medusajs/medusa-cli develop${EOL}${EOL}${inviteToken ? `After you start the Medusa app, you can set a password for your admin user with the URL ${getInviteUrl(inviteToken)}${EOL}${EOL}` : ""}${nextjsDirectory?.length ? `The Next.js Starter storefront was installed in the \`${nextjsDirectory}\` directory. Change to that directory and start it with the following command:${EOL}${EOL}npm run dev${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`
`Change to the \`${projectName}\` directory to explore your Medusa project.${EOL}${EOL}Start your Medusa app again with the following command:${EOL}${EOL}yarn dev${EOL}${EOL}${inviteToken ? `After you start the Medusa app, you can set a password for your admin user with the URL ${getInviteUrl(inviteToken)}${EOL}${EOL}` : ""}${nextjsDirectory?.length ? `The Next.js Starter storefront was installed in the \`${nextjsDirectory}\` directory. Change to that directory and start it with the following command:${EOL}${EOL}npm run dev${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`
),
{
titleAlignment: "center",

View File

@@ -43,11 +43,6 @@ program
"Show all logs of underlying commands. Useful for debugging.",
false
)
.option(
"--v2",
"Install Medusa with the V2 feature flag enabled. WARNING: Medusa V2 is still in development and shouldn't be used in production.",
false
)
.parse()
void create(program.opts())

View File

@@ -10,7 +10,6 @@ type CloneRepoOptions = {
repoUrl?: string
abortController?: AbortController
verbose?: boolean
v2?: boolean
}
const DEFAULT_REPO = "https://github.com/medusajs/medusa-starter-default"
@@ -21,13 +20,10 @@ export default async function cloneRepo({
repoUrl,
abortController,
verbose = false,
v2 = false,
}: CloneRepoOptions) {
await execute(
[
`git clone ${repoUrl || DEFAULT_REPO}${
v2 ? ` -b ${V2_BRANCH}` : ""
} ${directoryName}`,
`git clone ${repoUrl || DEFAULT_REPO} -b ${V2_BRANCH} ${directoryName}`,
{
signal: abortController?.signal,
},
@@ -42,14 +38,12 @@ export async function runCloneRepo({
abortController,
spinner,
verbose = false,
v2 = false,
}: {
projectName: string
repoUrl: string
abortController: AbortController
spinner: Ora
verbose?: boolean
v2?: boolean
}) {
try {
await cloneRepo({
@@ -57,7 +51,6 @@ export async function runCloneRepo({
repoUrl,
abortController,
verbose,
v2,
})
deleteGitDirectory(projectName)

View File

@@ -14,7 +14,6 @@ export type FactBoxOptions = {
}
const facts = [
"Plugins allow you to integrate third-party services for payment, fulfillment, notifications, and more.",
"You can specify a product's availability in one or more sales channels.",
"Payment and shipping options and providers can be configured per region.",
"Tax-inclusive pricing allows you to set prices for products, shipping options, and more without having to worry about calculating taxes.",
@@ -24,13 +23,16 @@ const facts = [
"Publishable-API Keys allow you to send requests to the backend within a scoped resource.",
"You can create custom endpoints by creating a TypeScript file under the src/api directory.",
"You can listen to events to perform asynchronous actions using Subscribers.",
"An entity represents a table in the database. You can create a table by creating a custom entity and migration.",
"A data model represents a table in the database. You can create a table by creating a custom data model and migration in a module.",
"Medusa's store endpoint paths are prefixed by /store. The admin endpoints are prefixed by /admin.",
"Medusa provides a JavaScript client and a React library that you can use to build a storefront or a custom admin.",
"Services are classes with methods related to an entity or functionality. You can create a custom service in a TypeScript file under src/services.",
"Modules hold your custom features and data models. You create them under the src/modules directory. Each module must have a service.",
"A service is a class with methods related to a functionality or a data model. You create a service in a module.",
"Modules allow you to replace an entire functionality with your custom logic.",
"The event bus module is responsible for triggering events and relaying them to subscribers.",
"The cache module is responsible for caching data that requires heavy computation.",
"A workflow is a series of steps that are defined once and executed anywhere. Workflows are created under the src/workflows directory.",
"A workflow's steps can be retried or rolled back in case of an error."
]
export const getFact = () => {

View File

@@ -7,6 +7,7 @@ import path from "path"
import { customAlphabet } from "nanoid"
import { isAbortError } from "./create-abort-controller.js"
import logMessage from "./log-message.js"
import ProcessManager from "./process-manager.js"
const NEXTJS_REPO = "https://github.com/medusajs/nextjs-starter-medusa"
@@ -28,6 +29,7 @@ type InstallOptions = {
abortController?: AbortController
factBoxOptions: FactBoxOptions
verbose?: boolean
processManager: ProcessManager
}
export async function installNextjsStarter({
@@ -35,6 +37,7 @@ export async function installNextjsStarter({
abortController,
factBoxOptions,
verbose = false,
processManager
}: InstallOptions): Promise<string> {
factBoxOptions.interval = displayFactBox({
...factBoxOptions,
@@ -56,19 +59,35 @@ export async function installNextjsStarter({
}
try {
// TODO change back to use create-next-app once Next.js v2 changes land on the main branch
await execute(
[
`npx create-next-app -e ${NEXTJS_REPO} ${nextjsDirectory}`,
`git clone ${NEXTJS_REPO} -b v2 ${nextjsDirectory}`,
{
signal: abortController?.signal,
env: {
...process.env,
npm_config_yes: "yes",
},
env: process.env,
},
],
{ verbose }
)
const execOptions = {
signal: abortController?.signal,
cwd: nextjsDirectory
}
await processManager.runProcess({
process: async () => {
try {
await execute([`yarn`, execOptions], { verbose })
} catch (e) {
// yarn isn't available
// use npm
await execute([`npm install`, execOptions], {
verbose,
})
}
},
ignoreERESOLVE: true,
})
} catch (e) {
if (isAbortError(e)) {
process.exit()
@@ -80,6 +99,11 @@ export async function installNextjsStarter({
})
}
fs.rmSync(path.join(nextjsDirectory, ".git"), {
recursive: true,
force: true,
})
fs.renameSync(
path.join(nextjsDirectory, ".env.template"),
path.join(nextjsDirectory, ".env.local")

View File

@@ -26,7 +26,6 @@ type PrepareOptions = {
nextjsDirectory?: string
client: Client | null
verbose?: boolean
v2?: boolean
}
export default async ({
@@ -44,7 +43,6 @@ export default async ({
nextjsDirectory = "",
client,
verbose = false,
v2 = false,
}: PrepareOptions) => {
// initialize execution options
const execOptions = {
@@ -73,10 +71,7 @@ export default async ({
let inviteToken: string | undefined = undefined
if (!skipDb) {
let env = `DATABASE_TYPE=postgres${EOL}DATABASE_URL=${dbConnectionString}${EOL}MEDUSA_ADMIN_ONBOARDING_TYPE=${onboardingType}${EOL}STORE_CORS=http://localhost:8000,http://localhost:7001`
if (v2) {
env += `${EOL}POSTGRES_URL=${dbConnectionString}`
}
let env = `DATABASE_TYPE=postgres${EOL}DATABASE_URL=${dbConnectionString}${EOL}MEDUSA_ADMIN_ONBOARDING_TYPE=${onboardingType}${EOL}STORE_CORS=http://localhost:8000,http://localhost:7001${EOL}POSTGRES_URL=${dbConnectionString}`
if (nextjsDirectory) {
env += `${EOL}MEDUSA_ADMIN_ONBOARDING_NEXTJS_DIRECTORY=${nextjsDirectory}`
}
@@ -154,7 +149,7 @@ export default async ({
await processManager.runProcess({
process: async () => {
const proc = await execute(
["npx @medusajs/medusa-cli@latest migrations run", npxOptions],
["npx medusa migrations run", npxOptions],
{ verbose, needOutput: true }
)
@@ -164,7 +159,7 @@ export default async ({
let errorOccurred = false
try {
const migrations = await client.query(
`SELECT * FROM "${v2 ? "mikro_orm_migrations" : "migrations"}"`
`SELECT * FROM "mikro_orm_migrations"`
)
errorOccurred = migrations.rowCount == 0
} catch (e) {
@@ -191,7 +186,7 @@ export default async ({
})
}
if (admin && !skipDb && migrations && !v2) {
if (admin && !skipDb && migrations) {
// create admin user
factBoxOptions.interval = displayFactBox({
...factBoxOptions,
@@ -202,7 +197,7 @@ export default async ({
process: async () => {
const proc = await execute(
[
`npx @medusajs/medusa-cli@latest user -e ${admin.email} --invite`,
`npx medusa user -e ${admin.email} --invite`,
npxOptions,
],
{ verbose, needOutput: true }
@@ -223,70 +218,47 @@ export default async ({
}
if (!skipDb && migrations) {
if (seed || !boilerplate) {
factBoxOptions.interval = displayFactBox({
...factBoxOptions,
title: "Seeding database...",
})
// TODO for now we just seed the default data
// we should add onboarding seeding again if it makes
// since once we re-introduce the onboarding flow.
factBoxOptions.interval = displayFactBox({
...factBoxOptions,
title: "Seeding database...",
})
// check if a seed file exists in the project
if (!fs.existsSync(path.join(directory, "data", "seed.json"))) {
spinner
?.warn(
chalk.yellow(
"Seed file was not found in the project. Skipping seeding..."
)
const seedScriptPath = path.join("dist", "helpers", "seed.js")
// check if a seed file exists in the project
if (!fs.existsSync(path.join(directory, seedScriptPath))) {
spinner
?.warn(
chalk.yellow(
"Seed file was not found in the project. Skipping seeding..."
)
.start()
return inviteToken
}
await processManager.runProcess({
process: async () => {
await execute(
[
`npx @medusajs/medusa-cli@latest seed --seed-file=${path.join(
"data",
"seed.json"
)}`,
npxOptions,
],
{ verbose }
)
},
})
displayFactBox({
...factBoxOptions,
message: "Seeded database with demo data",
})
} else if (
fs.existsSync(path.join(directory, "data", "seed-onboarding.json"))
) {
// seed the database with onboarding seed
factBoxOptions.interval = displayFactBox({
...factBoxOptions,
title: "Finish preparation...",
})
await processManager.runProcess({
process: async () => {
await execute(
[
`npx @medusajs/medusa-cli@latest seed --seed-file=${path.join(
"data",
"seed-onboarding.json"
)}`,
npxOptions,
],
{ verbose }
)
},
})
)
.start()
return inviteToken
}
displayFactBox({ ...factBoxOptions, message: "Finished Preparation" })
await processManager.runProcess({
process: async () => {
await execute(
[
`npx medusa exec ${seedScriptPath}`,
npxOptions,
],
{ verbose }
)
},
})
displayFactBox({
...factBoxOptions,
message: "Seeded database with demo data",
})
}
displayFactBox({ ...factBoxOptions, message: "Finished Preparation" })
return inviteToken
}

View File

@@ -6,13 +6,11 @@ type StartOptions = {
}
export default ({ directory, abortController }: StartOptions) => {
const childProcess = exec(`npx @medusajs/medusa-cli@latest develop`, {
const childProcess = exec(`npm run dev`, {
cwd: directory,
signal: abortController?.signal,
env: {
...process.env,
OPEN_BROWSER: "false",
npm_config_yes: "yes",
},
})