From 84fa6ccde543fcc1bbf89f2605d87742d03ba7bc Mon Sep 17 00:00:00 2001 From: Adrien de Peretti Date: Tue, 15 Oct 2024 17:59:47 +0200 Subject: [PATCH] chore: Update admin build/serve configuration (#9584) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit **Breaking changes** The `outDir` has been deprecated and wont be used anymore, instead all the path are computed internally following these rules - if admin is not `disabled` and the `build` command is run without the `--admin-only` flag, then the admin output dir will be `.medusa/server/public/admin` and it will be served from that same location from the medusa instance. - if admin is not `disabled` and the `build` command is run with the `--admin-only` flag, then the admin output dir will be `.medusa/admin` with the purpose of deploying the admin separately. ⚠️ (expect to receive a warning log) - if the admin is `disabled` and the `build` command is run with the `--admin-only` flag, then fallback to rule number 2 | admin enabled | medusa build --admin-only | output dir | |---|---|---| | true | true | `.medusa/admin` ⚠️ (expect to receive a warning log) | | true | false | `.medusa/server/public/admin` | | false | true | `.medusa/admin` | | false | false | none | ```diff // medusa-config.ts { // ... admin: { - outDir: 'some/path' } } ``` cc @kasperkristensen @sradevski @olivermrbl --- packages/admin/admin-bundler/src/types.ts | 3 +- packages/cli/medusa-cli/src/create-cli.ts | 12 ++- .../core/types/src/common/config-module.ts | 15 --- .../common/__tests__/define-config.spec.ts | 6 -- .../core/utils/src/common/define-config.ts | 1 - packages/medusa/src/commands/build.ts | 95 +++++++++++++++---- packages/medusa/src/loaders/admin.ts | 7 +- packages/medusa/src/utils/admin-consts.ts | 3 + packages/medusa/src/utils/index.ts | 1 + 9 files changed, 95 insertions(+), 48 deletions(-) create mode 100644 packages/medusa/src/utils/admin-consts.ts diff --git a/packages/admin/admin-bundler/src/types.ts b/packages/admin/admin-bundler/src/types.ts index ca56df216f..491307037e 100644 --- a/packages/admin/admin-bundler/src/types.ts +++ b/packages/admin/admin-bundler/src/types.ts @@ -1,6 +1,7 @@ import { AdminOptions } from "@medusajs/types" -export type BundlerOptions = Required> & +export type BundlerOptions = Required> & Pick & { + outDir: string sources?: string[] } diff --git a/packages/cli/medusa-cli/src/create-cli.ts b/packages/cli/medusa-cli/src/create-cli.ts index 653474caa8..f817e618c7 100644 --- a/packages/cli/medusa-cli/src/create-cli.ts +++ b/packages/cli/medusa-cli/src/create-cli.ts @@ -354,9 +354,15 @@ function buildLocalCommands(cli, isLocalProject) { ), }) .command({ - command: `build`, - desc: `Build your project.`, - builder: (_) => _, + command: "build", + desc: "Build your project.", + builder: (_) => + _.option("admin-only", { + default: false, + type: "boolean", + describe: + "Only build the admin to serve it separately (outDir .medusa/admin)", + }), handler: handlerP( getCommandHandler(`build`, (args, cmd) => { process.env.NODE_ENV = process.env.NODE_ENV || `development` diff --git a/packages/core/types/src/common/config-module.ts b/packages/core/types/src/common/config-module.ts index e351ac678e..fcfc03a01c 100644 --- a/packages/core/types/src/common/config-module.ts +++ b/packages/core/types/src/common/config-module.ts @@ -49,21 +49,6 @@ export interface AdminOptions { * ``` */ path: `/${string}` - /** - * The directory where the admin build is outputted when you run the `build` command. - * The default value is `./build`. - * - * @example - * ```js title="medusa-config.js" - * module.exports = defineConfig({ - * admin: { - * outDir: process.env.ADMIN_BUILD_DIR || `./build`, - * }, - * // ... - * }) - * ``` - */ - outDir: string /** * The URL of your Medusa application. This is useful to set when you deploy the Medusa application. * diff --git a/packages/core/utils/src/common/__tests__/define-config.spec.ts b/packages/core/utils/src/common/__tests__/define-config.spec.ts index efb414002d..929b432859 100644 --- a/packages/core/utils/src/common/__tests__/define-config.spec.ts +++ b/packages/core/utils/src/common/__tests__/define-config.spec.ts @@ -7,7 +7,6 @@ describe("defineConfig", function () { { "admin": { "backendUrl": "http://localhost:9000", - "outDir": ".medusa/admin", "path": "/app", }, "featureFlags": {}, @@ -154,7 +153,6 @@ describe("defineConfig", function () { { "admin": { "backendUrl": "http://localhost:9000", - "outDir": ".medusa/admin", "path": "/app", }, "featureFlags": {}, @@ -307,7 +305,6 @@ describe("defineConfig", function () { { "admin": { "backendUrl": "http://localhost:9000", - "outDir": ".medusa/admin", "path": "/app", }, "featureFlags": {}, @@ -466,7 +463,6 @@ describe("defineConfig", function () { { "admin": { "backendUrl": "http://localhost:9000", - "outDir": ".medusa/admin", "path": "/app", }, "featureFlags": {}, @@ -621,7 +617,6 @@ describe("defineConfig", function () { { "admin": { "backendUrl": "http://localhost:9000", - "outDir": ".medusa/admin", "path": "/app", }, "featureFlags": {}, @@ -771,7 +766,6 @@ describe("defineConfig", function () { { "admin": { "backendUrl": "http://localhost:9000", - "outDir": ".medusa/admin", "path": "/app", }, "featureFlags": {}, diff --git a/packages/core/utils/src/common/define-config.ts b/packages/core/utils/src/common/define-config.ts index 9f83dbdf35..ae962cc674 100644 --- a/packages/core/utils/src/common/define-config.ts +++ b/packages/core/utils/src/common/define-config.ts @@ -90,7 +90,6 @@ export function defineConfig(config: Config = {}): ConfigModule { */ const admin: ConfigModule["admin"] = { backendUrl: process.env.MEDUSA_BACKEND_URL || DEFAULT_ADMIN_URL, - outDir: ".medusa/admin", path: "/app", ...config.admin, } diff --git a/packages/medusa/src/commands/build.ts b/packages/medusa/src/commands/build.ts index 53839e19a4..7c95d962f8 100644 --- a/packages/medusa/src/commands/build.ts +++ b/packages/medusa/src/commands/build.ts @@ -4,10 +4,35 @@ import type tsStatic from "typescript" import { logger } from "@medusajs/framework/logger" import { ConfigModule } from "@medusajs/framework/types" import { getConfigFile } from "@medusajs/framework/utils" +import { + ADMIN_ONLY_OUTPUT_DIR, + ADMIN_RELATIVE_OUTPUT_DIR, + ADMIN_SOURCE_DIR, +} from "../utils" -const ADMIN_FOLDER = "src/admin" const INTEGRATION_TESTS_FOLDER = "integration-tests" +function computeDist( + projectRoot: string, + tsConfig: { options: { outDir?: string } } +): string { + const distFolder = tsConfig.options.outDir ?? ".medusa/server" + return path.isAbsolute(distFolder) + ? distFolder + : path.join(projectRoot, distFolder) +} + +async function loadTsConfig(projectRoot: string) { + const ts = await import("typescript") + const tsConfig = parseTSConfig(projectRoot, ts) + if (!tsConfig) { + logger.error("Unable to compile backend source") + return false + } + + return tsConfig! +} + /** * Copies the file to the destination without throwing any * errors if the source file is missing @@ -98,21 +123,14 @@ function parseTSConfig(projectRoot: string, ts: typeof tsStatic) { /** * Builds the backend project using TSC */ -async function buildBackend(projectRoot: string): Promise { +async function buildBackend( + projectRoot: string, + tsConfig: tsStatic.ParsedCommandLine +): Promise { const startTime = process.hrtime() logger.info("Compiling backend source...") - const ts = await import("typescript") - const tsConfig = parseTSConfig(projectRoot, ts) - if (!tsConfig) { - logger.error("Unable to compile backend source") - return false - } - - const distFolder = tsConfig.options.outDir ?? ".medusa/server" - const dist = path.isAbsolute(distFolder) - ? distFolder - : path.join(projectRoot, distFolder) + const dist = computeDist(projectRoot, tsConfig) logger.info(`Removing existing "${path.relative(projectRoot, dist)}" folder`) await clean(dist) @@ -123,11 +141,12 @@ async function buildBackend(projectRoot: string): Promise { */ const filesToCompile = tsConfig.fileNames.filter((fileName) => { return ( - !fileName.includes(`${ADMIN_FOLDER}/`) && + !fileName.includes(`${ADMIN_SOURCE_DIR}/`) && !fileName.includes(`${INTEGRATION_TESTS_FOLDER}/`) ) }) + const ts = await import("typescript") const program = ts.createProgram(filesToCompile, { ...tsConfig.options, ...{ @@ -195,24 +214,41 @@ async function buildBackend(projectRoot: string): Promise { /** * Builds the frontend project using the "@medusajs/admin-bundler" */ -async function buildFrontend(projectRoot: string): Promise { +async function buildFrontend( + projectRoot: string, + adminOnly: boolean, + tsConfig: tsStatic.ParsedCommandLine +): Promise { const startTime = process.hrtime() const configFile = await loadMedusaConfig(projectRoot) if (!configFile) { return false } - const adminSource = path.join(projectRoot, ADMIN_FOLDER) + const dist = computeDist(projectRoot, tsConfig) + + const adminOutputPath = adminOnly + ? path.join(projectRoot, ADMIN_ONLY_OUTPUT_DIR) + : path.join(dist, ADMIN_RELATIVE_OUTPUT_DIR) + + const adminSource = path.join(projectRoot, ADMIN_SOURCE_DIR) const adminOptions = { disable: false, sources: [adminSource], ...configFile.configModule.admin, + outDir: adminOutputPath, } - if (adminOptions.disable) { + if (adminOptions.disable && !adminOnly) { return false } + if (!adminOptions.disable && adminOnly) { + logger.warn( + `You are building using the flag --admin-only but the admin is enabled in your medusa-config, If you intend to host the dashboard separately you should disable the admin in your medusa config` + ) + } + try { logger.info("Compiling frontend source...") const { build: buildProductionBuild } = await import( @@ -231,7 +267,28 @@ async function buildFrontend(projectRoot: string): Promise { } } -export default async function ({ directory }: { directory: string }) { +export default async function ({ + directory, + adminOnly, +}: { + directory: string + adminOnly: boolean +}): Promise { logger.info("Starting build...") - await Promise.all([buildBackend(directory), buildFrontend(directory)]) + + const tsConfig = await loadTsConfig(directory) + if (!tsConfig) { + return false + } + + const promises: Promise[] = [] + + if (!adminOnly) { + promises.push(buildBackend(directory, tsConfig)) + } + + promises.push(buildFrontend(directory, adminOnly, tsConfig)) + + await Promise.all(promises) + return true } diff --git a/packages/medusa/src/loaders/admin.ts b/packages/medusa/src/loaders/admin.ts index 0d2ce30bff..fa126ae03b 100644 --- a/packages/medusa/src/loaders/admin.ts +++ b/packages/medusa/src/loaders/admin.ts @@ -3,6 +3,7 @@ import { AdminOptions, ConfigModule } from "@medusajs/framework/types" import { Express } from "express" import fs from "fs" import path from "path" +import { ADMIN_RELATIVE_OUTPUT_DIR } from "../utils" type Options = { app: Express @@ -10,10 +11,9 @@ type Options = { rootDirectory: string } -type IntializedOptions = Required< - Pick -> & +type IntializedOptions = Required> & AdminOptions & { + outDir: string sources?: string[] } @@ -39,6 +39,7 @@ export default async function adminLoader({ disable: false, sources, ...admin, + outDir: path.join(rootDirectory, ADMIN_RELATIVE_OUTPUT_DIR), } if (adminOptions?.disable) { diff --git a/packages/medusa/src/utils/admin-consts.ts b/packages/medusa/src/utils/admin-consts.ts new file mode 100644 index 0000000000..54a58297e3 --- /dev/null +++ b/packages/medusa/src/utils/admin-consts.ts @@ -0,0 +1,3 @@ +export const ADMIN_SOURCE_DIR = "src/admin" +export const ADMIN_RELATIVE_OUTPUT_DIR = "./public/admin" +export const ADMIN_ONLY_OUTPUT_DIR = ".medusa/admin" diff --git a/packages/medusa/src/utils/index.ts b/packages/medusa/src/utils/index.ts index 35b8ff48d5..c6f93f8a02 100644 --- a/packages/medusa/src/utils/index.ts +++ b/packages/medusa/src/utils/index.ts @@ -2,3 +2,4 @@ export * from "./clean-response-data" export * from "./exception-formatter" export * from "./middlewares" export * from "./define-middlewares" +export * from "./admin-consts"