From fe5c602e7a7f06f3280d9f2a21b6be4ec96d8e25 Mon Sep 17 00:00:00 2001 From: Harminder Virk Date: Fri, 10 Jan 2025 13:24:04 +0530 Subject: [PATCH 1/5] chore: move build utilities to Compiler class --- packages/core/framework/package.json | 1 + .../framework/src/build-tools/compiler.ts | 366 ++++++++++++++++++ .../core/framework/src/build-tools/index.ts | 1 + packages/medusa/src/commands/build.ts | 280 +------------- 4 files changed, 375 insertions(+), 273 deletions(-) create mode 100644 packages/core/framework/src/build-tools/compiler.ts create mode 100644 packages/core/framework/src/build-tools/index.ts diff --git a/packages/core/framework/package.json b/packages/core/framework/package.json index bed2a01df1d9e..fc42cc1835625 100644 --- a/packages/core/framework/package.json +++ b/packages/core/framework/package.json @@ -27,6 +27,7 @@ "./feature-flags": "./dist/feature-flags/index.js", "./utils": "./dist/utils/index.js", "./types": "./dist/types/index.js", + "./build-tools": "./dist/build-tools/index.js", "./orchestration": "./dist/orchestration/index.js", "./workflows-sdk": "./dist/workflows-sdk/index.js", "./workflows-sdk/composer": "./dist/workflows-sdk/composer.js", diff --git a/packages/core/framework/src/build-tools/compiler.ts b/packages/core/framework/src/build-tools/compiler.ts new file mode 100644 index 0000000000000..2f9d283869bfd --- /dev/null +++ b/packages/core/framework/src/build-tools/compiler.ts @@ -0,0 +1,366 @@ +import path from "path" +import type tsStatic from "typescript" +import { getConfigFile } from "@medusajs/utils" +import type { ConfigModule, Logger } from "@medusajs/types" +import { access, constants, copyFile, rm } from "fs/promises" + +/** + * The compiler exposes the opinionated APIs for compiling Medusa + * applications and plugins. You can perform the following + * actions. + * + * - loadTSConfigFile: Load and parse the TypeScript config file. All errors + * will be reported using the logger. + * + * - buildAppBackend: Compile the Medusa application backend source code to the + * ".medusa/server" directory. The admin source and integration-tests are + * skipped. + * + * - buildAppFrontend: Compile the admin extensions using the "@medusjs/admin-bundler" + * package. Admin can be compiled for self hosting (aka adminOnly), or can be compiled + * to be bundled with the backend output. + */ +export class Compiler { + #logger: Logger + #projectRoot: string + #appDistFolder: string + #adminSourceFolder: string + #adminOnlyDistFolder: string + #adminBundledDistFolder: string + #tsCompiler?: typeof tsStatic + + constructor(projectRoot: string, logger: Logger) { + this.#projectRoot = projectRoot + this.#logger = logger + this.#appDistFolder = path.join(this.#projectRoot, ".medusa/server") + this.#adminSourceFolder = path.join(this.#projectRoot, "src/admin") + this.#adminOnlyDistFolder = path.join(this.#projectRoot, ".medusa/admin") + this.#adminBundledDistFolder = path.join( + this.#projectRoot, + ".medusa/server/public/admin" + ) + } + + /** + * Util to track duration using hrtime + */ + #trackDuration() { + const startTime = process.hrtime() + return { + getSeconds() { + const duration = process.hrtime(startTime) + return (duration[0] + duration[1] / 1e9).toFixed(2) + }, + } + } + + /** + * Imports and stores a reference to the TypeScript compiler. + * We dynamically import "typescript", since its is a dev + * only dependency + */ + async #loadTSCompiler() { + if (!this.#tsCompiler) { + this.#tsCompiler = await import("typescript") + } + return this.#tsCompiler + } + + /** + * Copies the file to the destination without throwing any + * errors if the source file is missing + */ + async #copy(source: string, destination: string) { + let sourceExists = false + try { + await access(source, constants.F_OK) + sourceExists = true + } catch (error) { + if (error.code !== "ENOENT") { + throw error + } + } + + if (sourceExists) { + await copyFile(path.join(source), path.join(destination)) + } + } + + /** + * Copies package manager files from the project root + * to the specified dist folder + */ + async #copyPkgManagerFiles(dist: string) { + /** + * Copying package manager files + */ + await this.#copy( + path.join(this.#projectRoot, "package.json"), + path.join(dist, "package.json") + ) + await this.#copy( + path.join(this.#projectRoot, "yarn.lock"), + path.join(dist, "yarn.lock") + ) + await this.#copy( + path.join(this.#projectRoot, "pnpm.lock"), + path.join(dist, "pnpm.lock") + ) + await this.#copy( + path.join(this.#projectRoot, "package-lock.json"), + path.join(dist, "package-lock.json") + ) + } + + /** + * Removes the directory and its children recursively and + * ignores any errors + */ + async #clean(path: string) { + await rm(path, { recursive: true }).catch(() => {}) + } + + /** + * Loads the medusa config file and prints the error to + * the console (in case of any errors). Otherwise, the + * file path and the parsed config is returned + */ + async #loadMedusaConfig() { + const { configModule, configFilePath, error } = + await getConfigFile(this.#projectRoot, "medusa-config") + if (error) { + this.#logger.error(`Failed to load medusa-config.(js|ts) file`) + this.#logger.error(error) + return + } + + return { configFilePath, configModule } + } + + /** + * Given a tsconfig file, this method will write the compiled + * output to the specified destination + */ + async #emitBuildOutput( + tsConfig: tsStatic.ParsedCommandLine, + chunksToIgnore: string[], + dist: string + ): Promise<{ + emitResult: tsStatic.EmitResult + diagnostics: tsStatic.Diagnostic[] + }> { + const ts = await this.#loadTSCompiler() + const filesToCompile = tsConfig.fileNames.filter((fileName) => { + return chunksToIgnore.some((chunk) => !fileName.includes(chunk)) + }) + + /** + * Create emit program to compile and emit output + */ + const program = ts.createProgram(filesToCompile, { + ...tsConfig.options, + ...{ + outDir: dist, + inlineSourceMap: !tsConfig.options.sourceMap, + }, + }) + + const emitResult = program.emit() + const diagnostics = ts + .getPreEmitDiagnostics(program) + .concat(emitResult.diagnostics) + + /** + * Log errors (if any) + */ + if (diagnostics.length) { + console.error( + ts.formatDiagnosticsWithColorAndContext( + diagnostics, + ts.createCompilerHost({}) + ) + ) + } + + return { emitResult, diagnostics } + } + + /** + * Loads and parses the TypeScript config file. In case of an error, the errors + * will be logged using the logger and undefined it returned + */ + async loadTSConfigFile(): Promise { + const ts = await this.#loadTSCompiler() + let tsConfigErrors: tsStatic.Diagnostic[] = [] + + const tsConfig = ts.getParsedCommandLineOfConfigFile( + path.join(this.#projectRoot, "tsconfig.json"), + { + inlineSourceMap: true, + excludes: [], + }, + { + ...ts.sys, + useCaseSensitiveFileNames: true, + getCurrentDirectory: () => this.#projectRoot, + onUnRecoverableConfigFileDiagnostic: (error) => + (tsConfigErrors = [error]), + } + ) + + /** + * Push errors from the tsConfig parsed output to the + * tsConfigErrors array. + */ + if (tsConfig?.errors.length) { + tsConfigErrors.push(...tsConfig.errors) + } + + /** + * Display all config errors using the diagnostics reporter + */ + if (tsConfigErrors.length) { + const compilerHost = ts.createCompilerHost({}) + this.#logger.error( + ts.formatDiagnosticsWithColorAndContext(tsConfigErrors, compilerHost) + ) + return + } + + /** + * If there are no errors, the `tsConfig` object will always exist. + */ + return tsConfig! + } + + /** + * Builds the application backend source code using + * TypeScript's official compiler. Also performs + * type-checking + */ + async buildAppBackend( + tsConfig: tsStatic.ParsedCommandLine + ): Promise { + const tracker = this.#trackDuration() + this.#logger.info("Compiling backend source...") + + /** + * Step 1: Cleanup existing build output + */ + this.#logger.info( + `Removing existing "${path.relative( + this.#projectRoot, + this.#appDistFolder + )}" folder` + ) + await this.#clean(this.#appDistFolder) + + /** + * Step 2: Compile TypeScript source code + */ + const { emitResult, diagnostics } = await this.#emitBuildOutput( + tsConfig, + ["integration-tests", "test", "unit-tests", "src/admin"], + this.#appDistFolder + ) + + /** + * Exit early if no output is written to the disk + */ + if (emitResult.emitSkipped) { + this.#logger.warn("Backend build completed without emitting any output") + return false + } + + /** + * Step 3: Copy package manager files to the output folder + */ + await this.#copyPkgManagerFiles(this.#appDistFolder) + + /** + * Notify about the state of build + */ + if (diagnostics.length) { + this.#logger.warn( + `Backend build completed with errors (${tracker.getSeconds()}s)` + ) + } else { + this.#logger.info( + `Backend build completed successfully (${tracker.getSeconds()}s)` + ) + } + + return true + } + + /** + * Builds the frontend source code of a Medusa application + * using the "@medusajs/admin-bundler" package. + */ + async buildAppFrontend( + adminOnly: boolean, + tsConfig: tsStatic.ParsedCommandLine + ): Promise { + const tracker = this.#trackDuration() + + /** + * Step 1: Load the medusa config file to read + * admin options + */ + const configFile = await this.#loadMedusaConfig() + if (!configFile) { + return false + } + + /** + * Return early when admin is disabled and we are trying to + * create a bundled build for the admin. + */ + if (configFile.configModule.admin.disable && !adminOnly) { + this.#logger.info( + "Skipping admin build, since its disabled inside the medusa-config file" + ) + return false + } + + /** + * Warn when we are creating an admin only build, but forgot to disable + * the admin inside the config file + */ + if (!configFile.configModule.admin.disable && adminOnly) { + this.#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 { + this.#logger.info("Compiling frontend source...") + const { build: buildProductionBuild } = await import( + "@medusajs/admin-bundler" + ) + await buildProductionBuild({ + disable: false, + sources: [this.#adminSourceFolder], + ...configFile.configModule.admin, + outDir: adminOnly + ? this.#adminOnlyDistFolder + : this.#adminBundledDistFolder, + }) + + this.#logger.info( + `Frontend build completed successfully (${tracker.getSeconds()}s)` + ) + return true + } catch (error) { + this.#logger.error("Unable to compile frontend source") + console.error(error) + return false + } + } + + /** + * @todo. To be implemented + */ + buildPluginBackend() {} + developPluginBacked() {} +} diff --git a/packages/core/framework/src/build-tools/index.ts b/packages/core/framework/src/build-tools/index.ts new file mode 100644 index 0000000000000..1dae1fbc9c809 --- /dev/null +++ b/packages/core/framework/src/build-tools/index.ts @@ -0,0 +1 @@ +export * from "./compiler" diff --git a/packages/medusa/src/commands/build.ts b/packages/medusa/src/commands/build.ts index 7c95d962f8bb9..13fd38fba5233 100644 --- a/packages/medusa/src/commands/build.ts +++ b/packages/medusa/src/commands/build.ts @@ -1,273 +1,7 @@ -import path from "path" -import { access, constants, copyFile, rm } from "node:fs/promises" -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" +import { Compiler } from "@medusajs/framework/build-tools" -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 - */ -async function copy(source: string, destination: string) { - let sourceExists = false - try { - await access(source, constants.F_OK) - sourceExists = true - } catch (error) { - if (error.code !== "ENOENT") { - throw error - } - } - - if (sourceExists) { - await copyFile(path.join(source), path.join(destination)) - } -} - -/** - * Removes the directory and its children recursively and - * ignores any errors - */ -async function clean(path: string) { - await rm(path, { recursive: true }).catch(() => {}) -} - -/** - * Loads the medusa config file or exits with an error - */ -async function loadMedusaConfig(directory: string) { - /** - * Parsing the medusa config file to ensure it is error - * free - */ - const { configModule, configFilePath, error } = - await getConfigFile(directory, "medusa-config") - if (error) { - console.error(`Failed to load medusa-config.js`) - console.error(error) - return - } - - return { configFilePath, configModule } -} - -/** - * Parses the tsconfig file or exits with an error in case - * the file is invalid - */ -function parseTSConfig(projectRoot: string, ts: typeof tsStatic) { - let tsConfigErrors: null | tsStatic.Diagnostic = null - - const tsConfig = ts.getParsedCommandLineOfConfigFile( - path.join(projectRoot, "tsconfig.json"), - { - inlineSourceMap: true, - excludes: [], - }, - { - ...ts.sys, - useCaseSensitiveFileNames: true, - getCurrentDirectory: () => projectRoot, - onUnRecoverableConfigFileDiagnostic: (error) => (tsConfigErrors = error), - } - ) - - if (tsConfigErrors) { - const compilerHost = ts.createCompilerHost({}) - console.error( - ts.formatDiagnosticsWithColorAndContext([tsConfigErrors], compilerHost) - ) - return - } - - if (tsConfig!.errors.length) { - const compilerHost = ts.createCompilerHost({}) - console.error( - ts.formatDiagnosticsWithColorAndContext(tsConfig!.errors, compilerHost) - ) - return - } - - return tsConfig! -} - -/** - * Builds the backend project using TSC - */ -async function buildBackend( - projectRoot: string, - tsConfig: tsStatic.ParsedCommandLine -): Promise { - const startTime = process.hrtime() - logger.info("Compiling backend source...") - - const dist = computeDist(projectRoot, tsConfig) - - logger.info(`Removing existing "${path.relative(projectRoot, dist)}" folder`) - await clean(dist) - - /** - * Ignoring admin and integration tests from the compiled - * files - */ - const filesToCompile = tsConfig.fileNames.filter((fileName) => { - return ( - !fileName.includes(`${ADMIN_SOURCE_DIR}/`) && - !fileName.includes(`${INTEGRATION_TESTS_FOLDER}/`) - ) - }) - - const ts = await import("typescript") - const program = ts.createProgram(filesToCompile, { - ...tsConfig.options, - ...{ - outDir: dist, - - /** - * Disable inline source maps when the user has enabled - * source maps within the config file - */ - inlineSourceMap: !tsConfig.options.sourceMap, - }, - }) - - const emitResult = program.emit() - const diagnostics = ts - .getPreEmitDiagnostics(program) - .concat(emitResult.diagnostics) - - /** - * Log errors (if any) - */ - if (diagnostics.length) { - console.error( - ts.formatDiagnosticsWithColorAndContext( - diagnostics, - ts.createCompilerHost({}) - ) - ) - } - - /** - * Exit early if no output is written to the disk - */ - if (emitResult.emitSkipped) { - logger.warn("Backend build completed without emitting any output") - return false - } - - /** - * Copying package manager files - */ - await copy( - path.join(projectRoot, "package.json"), - path.join(dist, "package.json") - ) - await copy(path.join(projectRoot, "yarn.lock"), path.join(dist, "yarn.lock")) - await copy(path.join(projectRoot, "pnpm.lock"), path.join(dist, "pnpm.lock")) - await copy( - path.join(projectRoot, "package-lock.json"), - path.join(dist, "package-lock.json") - ) - - const duration = process.hrtime(startTime) - const seconds = (duration[0] + duration[1] / 1e9).toFixed(2) - - if (diagnostics.length) { - logger.warn(`Backend build completed with errors (${seconds}s)`) - } else { - logger.info(`Backend build completed successfully (${seconds}s)`) - } - - return true -} - -/** - * Builds the frontend project using the "@medusajs/admin-bundler" - */ -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 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 && !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( - "@medusajs/admin-bundler" - ) - await buildProductionBuild(adminOptions) - const duration = process.hrtime(startTime) - const seconds = (duration[0] + duration[1] / 1e9).toFixed(2) - - logger.info(`Frontend build completed successfully (${seconds}s)`) - return true - } catch (error) { - logger.error("Unable to compile frontend source") - console.error(error) - return false - } -} - -export default async function ({ +export default async function build({ directory, adminOnly, }: { @@ -275,20 +9,20 @@ export default async function ({ adminOnly: boolean }): Promise { logger.info("Starting build...") + const compiler = new Compiler(directory, logger) - const tsConfig = await loadTsConfig(directory) + const tsConfig = await compiler.loadTSConfigFile() if (!tsConfig) { + logger.error("Unable to compile application") return false } const promises: Promise[] = [] - if (!adminOnly) { - promises.push(buildBackend(directory, tsConfig)) + promises.push(compiler.buildAppBackend(tsConfig)) } - promises.push(buildFrontend(directory, adminOnly, tsConfig)) - + promises.push(compiler.buildAppFrontend(adminOnly, tsConfig)) await Promise.all(promises) return true } From 99ab2fa2b87d90b741ad7c34e032b1c3acb3213f Mon Sep 17 00:00:00 2001 From: Harminder Virk Date: Fri, 10 Jan 2025 15:06:26 +0530 Subject: [PATCH 2/5] refactor: remove import of admin-bundler and accept it as an argument --- .../core/framework/src/build-tools/compiler.ts | 16 ++++++++++------ packages/medusa/src/commands/build.ts | 3 ++- 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/packages/core/framework/src/build-tools/compiler.ts b/packages/core/framework/src/build-tools/compiler.ts index 2f9d283869bfd..7247c326b91a6 100644 --- a/packages/core/framework/src/build-tools/compiler.ts +++ b/packages/core/framework/src/build-tools/compiler.ts @@ -1,8 +1,8 @@ import path from "path" import type tsStatic from "typescript" import { getConfigFile } from "@medusajs/utils" -import type { ConfigModule, Logger } from "@medusajs/types" import { access, constants, copyFile, rm } from "fs/promises" +import type { AdminOptions, ConfigModule, Logger } from "@medusajs/types" /** * The compiler exposes the opinionated APIs for compiling Medusa @@ -299,7 +299,14 @@ export class Compiler { */ async buildAppFrontend( adminOnly: boolean, - tsConfig: tsStatic.ParsedCommandLine + adminBundler: { + build: ( + options: AdminOptions & { + sources: string[] + outDir: string + } + ) => Promise + } ): Promise { const tracker = this.#trackDuration() @@ -335,10 +342,7 @@ export class Compiler { try { this.#logger.info("Compiling frontend source...") - const { build: buildProductionBuild } = await import( - "@medusajs/admin-bundler" - ) - await buildProductionBuild({ + await adminBundler.build({ disable: false, sources: [this.#adminSourceFolder], ...configFile.configModule.admin, diff --git a/packages/medusa/src/commands/build.ts b/packages/medusa/src/commands/build.ts index 13fd38fba5233..7348d6ef01e48 100644 --- a/packages/medusa/src/commands/build.ts +++ b/packages/medusa/src/commands/build.ts @@ -22,7 +22,8 @@ export default async function build({ promises.push(compiler.buildAppBackend(tsConfig)) } - promises.push(compiler.buildAppFrontend(adminOnly, tsConfig)) + const bundler = await import("@medusajs/admin-bundler") + promises.push(compiler.buildAppFrontend(adminOnly, bundler)) await Promise.all(promises) return true } From b8e97ddd347fa7cfa605c03d776b27ecdbd95489 Mon Sep 17 00:00:00 2001 From: Harminder Virk Date: Fri, 10 Jan 2025 15:29:17 +0530 Subject: [PATCH 3/5] refactor: use logger.error over console.error --- packages/core/framework/src/build-tools/compiler.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/core/framework/src/build-tools/compiler.ts b/packages/core/framework/src/build-tools/compiler.ts index 7247c326b91a6..618a76aa948ec 100644 --- a/packages/core/framework/src/build-tools/compiler.ts +++ b/packages/core/framework/src/build-tools/compiler.ts @@ -357,7 +357,7 @@ export class Compiler { return true } catch (error) { this.#logger.error("Unable to compile frontend source") - console.error(error) + this.#logger.error(error) return false } } From 7af3e4cc2d8ca4ae818b31fe7e3de8868ad7f3a7 Mon Sep 17 00:00:00 2001 From: Harminder Virk Date: Fri, 10 Jan 2025 16:41:09 +0530 Subject: [PATCH 4/5] chore: read outDir for apps from the tsconfig file --- .../framework/src/build-tools/compiler.ts | 35 ++++++++++--------- packages/medusa/src/commands/build.ts | 2 +- 2 files changed, 20 insertions(+), 17 deletions(-) diff --git a/packages/core/framework/src/build-tools/compiler.ts b/packages/core/framework/src/build-tools/compiler.ts index 618a76aa948ec..2eb383555d513 100644 --- a/packages/core/framework/src/build-tools/compiler.ts +++ b/packages/core/framework/src/build-tools/compiler.ts @@ -23,22 +23,15 @@ import type { AdminOptions, ConfigModule, Logger } from "@medusajs/types" export class Compiler { #logger: Logger #projectRoot: string - #appDistFolder: string #adminSourceFolder: string #adminOnlyDistFolder: string - #adminBundledDistFolder: string #tsCompiler?: typeof tsStatic constructor(projectRoot: string, logger: Logger) { this.#projectRoot = projectRoot this.#logger = logger - this.#appDistFolder = path.join(this.#projectRoot, ".medusa/server") this.#adminSourceFolder = path.join(this.#projectRoot, "src/admin") this.#adminOnlyDistFolder = path.join(this.#projectRoot, ".medusa/admin") - this.#adminBundledDistFolder = path.join( - this.#projectRoot, - ".medusa/server/public/admin" - ) } /** @@ -54,6 +47,17 @@ export class Compiler { } } + /** + * Returns the dist folder from the tsconfig.outDir property + * or uses the ".medusa/server" folder + */ + #computeDist(tsConfig: { options: { outDir?: string } }): string { + const distFolder = tsConfig.options.outDir ?? ".medusa/server" + return path.isAbsolute(distFolder) + ? distFolder + : path.join(this.#projectRoot, distFolder) + } + /** * Imports and stores a reference to the TypeScript compiler. * We dynamically import "typescript", since its is a dev @@ -151,7 +155,7 @@ export class Compiler { }> { const ts = await this.#loadTSCompiler() const filesToCompile = tsConfig.fileNames.filter((fileName) => { - return chunksToIgnore.some((chunk) => !fileName.includes(chunk)) + return !chunksToIgnore.some((chunk) => fileName.includes(`${chunk}/`)) }) /** @@ -242,18 +246,16 @@ export class Compiler { tsConfig: tsStatic.ParsedCommandLine ): Promise { const tracker = this.#trackDuration() + const dist = this.#computeDist(tsConfig) this.#logger.info("Compiling backend source...") /** * Step 1: Cleanup existing build output */ this.#logger.info( - `Removing existing "${path.relative( - this.#projectRoot, - this.#appDistFolder - )}" folder` + `Removing existing "${path.relative(this.#projectRoot, dist)}" folder` ) - await this.#clean(this.#appDistFolder) + await this.#clean(dist) /** * Step 2: Compile TypeScript source code @@ -261,7 +263,7 @@ export class Compiler { const { emitResult, diagnostics } = await this.#emitBuildOutput( tsConfig, ["integration-tests", "test", "unit-tests", "src/admin"], - this.#appDistFolder + dist ) /** @@ -275,7 +277,7 @@ export class Compiler { /** * Step 3: Copy package manager files to the output folder */ - await this.#copyPkgManagerFiles(this.#appDistFolder) + await this.#copyPkgManagerFiles(dist) /** * Notify about the state of build @@ -299,6 +301,7 @@ export class Compiler { */ async buildAppFrontend( adminOnly: boolean, + tsConfig: tsStatic.ParsedCommandLine, adminBundler: { build: ( options: AdminOptions & { @@ -348,7 +351,7 @@ export class Compiler { ...configFile.configModule.admin, outDir: adminOnly ? this.#adminOnlyDistFolder - : this.#adminBundledDistFolder, + : path.join(this.#computeDist(tsConfig), "./public/admin"), }) this.#logger.info( diff --git a/packages/medusa/src/commands/build.ts b/packages/medusa/src/commands/build.ts index 7348d6ef01e48..e321e7bf827fd 100644 --- a/packages/medusa/src/commands/build.ts +++ b/packages/medusa/src/commands/build.ts @@ -23,7 +23,7 @@ export default async function build({ } const bundler = await import("@medusajs/admin-bundler") - promises.push(compiler.buildAppFrontend(adminOnly, bundler)) + promises.push(compiler.buildAppFrontend(adminOnly, tsConfig, bundler)) await Promise.all(promises) return true } From 9258f10bc830b90c850322cb45266485c34d7987 Mon Sep 17 00:00:00 2001 From: Harminder Virk Date: Fri, 10 Jan 2025 16:42:26 +0530 Subject: [PATCH 5/5] Create wild-parrots-lie.md --- .changeset/wild-parrots-lie.md | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 .changeset/wild-parrots-lie.md diff --git a/.changeset/wild-parrots-lie.md b/.changeset/wild-parrots-lie.md new file mode 100644 index 0000000000000..96c00bd044873 --- /dev/null +++ b/.changeset/wild-parrots-lie.md @@ -0,0 +1,6 @@ +--- +"@medusajs/medusa": patch +"@medusajs/framework": patch +--- + +chore: move build utilities to Compiler class