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:
@@ -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"
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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())
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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 = () => {
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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",
|
||||
},
|
||||
})
|
||||
|
||||
|
||||
Reference in New Issue
Block a user