diff --git a/.changeset/eight-nails-act.md b/.changeset/eight-nails-act.md new file mode 100644 index 0000000000000..96dadbb8e095f --- /dev/null +++ b/.changeset/eight-nails-act.md @@ -0,0 +1,8 @@ +--- +"@medusajs/admin-bundler": patch +"@medusajs/cli": patch +"@medusajs/framework": patch +"@medusajs/medusa": patch +--- + +feat(medusa,admin-bundler,cli,framework): Integrate admin extensions into plugin build diff --git a/packages/admin/admin-bundler/package.json b/packages/admin/admin-bundler/package.json index e79b66ff6b86f..e93dc55665525 100644 --- a/packages/admin/admin-bundler/package.json +++ b/packages/admin/admin-bundler/package.json @@ -32,7 +32,7 @@ "@vitejs/plugin-react": "^4.2.1", "autoprefixer": "^10.4.16", "compression": "^1.7.4", - "glob": "^11.0.0", + "glob": "^10.3.10", "postcss": "^8.4.32", "tailwindcss": "^3.3.6", "vite": "^5.2.11" diff --git a/packages/admin/admin-bundler/src/index.ts b/packages/admin/admin-bundler/src/index.ts index 3d6f8b53b8cc3..d642941a6e058 100644 --- a/packages/admin/admin-bundler/src/index.ts +++ b/packages/admin/admin-bundler/src/index.ts @@ -1,5 +1,6 @@ export { build } from "./lib/build" export { develop } from "./lib/develop" +export { plugin } from "./lib/plugin" export { serve } from "./lib/serve" export * from "./types" diff --git a/packages/admin/admin-bundler/src/lib/plugin.ts b/packages/admin/admin-bundler/src/lib/plugin.ts index 44c0261faf750..9d947d23758c1 100644 --- a/packages/admin/admin-bundler/src/lib/plugin.ts +++ b/packages/admin/admin-bundler/src/lib/plugin.ts @@ -1,24 +1,37 @@ +import react from "@vitejs/plugin-react" import { readFileSync } from "fs" +import { rm } from "fs/promises" import { glob } from "glob" import path from "path" import { UserConfig } from "vite" -export async function plugin() { +interface PluginOptions { + root: string + outDir: string +} + +export async function plugin(options: PluginOptions) { const vite = await import("vite") - const entries = await glob("src/admin/**/*.{ts,tsx,js,jsx}") + const entries = await glob(`${options.root}/src/admin/**/*.{ts,tsx,js,jsx}`) + + /** + * If there is no entry point, we can skip the build + */ + if (entries.length === 0) { + return + } const entryPoints = entries.reduce((acc, entry) => { - // Convert src/admin/routes/brands/page.tsx -> admin/routes/brands/page const outPath = entry .replace(/^src\//, "") .replace(/\.(ts|tsx|js|jsx)$/, "") - acc[outPath] = path.resolve(process.cwd(), entry) + acc[outPath] = path.resolve(options.root, entry) return acc }, {} as Record) const pkg = JSON.parse( - readFileSync(path.resolve(process.cwd(), "package.json"), "utf-8") + readFileSync(path.resolve(options.root, "package.json"), "utf-8") ) const external = new Set([ ...Object.keys(pkg.dependencies || {}), @@ -30,14 +43,22 @@ export async function plugin() { "@medusajs/admin-sdk", ]) + /** + * We need to ensure that the NODE_ENV is set to production, + * otherwise Vite will build the dev version of React. + */ + const originalNodeEnv = process.env.NODE_ENV + process.env.NODE_ENV = "production" + const pluginConfig: UserConfig = { build: { lib: { entry: entryPoints, formats: ["es"], }, + emptyOutDir: false, minify: false, - outDir: path.resolve(process.cwd(), "dist"), + outDir: path.resolve(options.root, options.outDir), rollupOptions: { external: [...external], output: { @@ -47,11 +68,34 @@ export async function plugin() { "react/jsx-runtime": "react/jsx-runtime", }, preserveModules: true, - entryFileNames: `[name].js`, + entryFileNames: (chunkInfo) => { + return `${chunkInfo.name.replace(`${options.root}/`, "")}.js` + }, }, }, }, + plugins: [ + react(), + { + name: "clear-admin-plugin", + buildStart: async () => { + const adminDir = path.join(options.root, options.outDir, "admin") + try { + await rm(adminDir, { recursive: true, force: true }) + } catch (e) { + // Directory might not exist, ignore + } + }, + }, + ], + logLevel: "silent", + clearScreen: false, } await vite.build(pluginConfig) + + /** + * Restore the original NODE_ENV + */ + process.env.NODE_ENV = originalNodeEnv } diff --git a/packages/cli/medusa-cli/package.json b/packages/cli/medusa-cli/package.json index 275a56e6f3c05..2c8b8b8889100 100644 --- a/packages/cli/medusa-cli/package.json +++ b/packages/cli/medusa-cli/package.json @@ -56,7 +56,7 @@ "express": "^4.21.0", "fs-exists-cached": "^1.0.0", "fs-extra": "^10.0.0", - "glob": "^7.1.6", + "glob": "^10.3.10", "hosted-git-info": "^4.0.2", "inquirer": "^8.0.0", "is-valid-path": "^0.1.1", diff --git a/packages/core/framework/src/build-tools/compiler.ts b/packages/core/framework/src/build-tools/compiler.ts index d2036a28c54a4..2b336e97f7fda 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 type { AdminOptions, ConfigModule, Logger } from "@medusajs/types" import { getConfigFile } from "@medusajs/utils" import { access, constants, copyFile, rm } from "fs/promises" -import type { AdminOptions, ConfigModule, Logger } from "@medusajs/types" +import path from "path" +import type tsStatic from "typescript" /** * The compiler exposes the opinionated APIs for compiling Medusa @@ -486,4 +486,25 @@ export class Compiler { ts.createWatchProgram(host) } + + async buildPluginAdminExtensions(bundler: { + plugin: (options: { root: string; outDir: string }) => Promise + }) { + const tracker = this.#trackDuration() + this.#logger.info("Compiling plugin admin extensions...") + + try { + await bundler.plugin({ + root: this.#projectRoot, + outDir: this.#pluginsDistFolder, + }) + this.#logger.info( + `Plugin admin extensions build completed successfully (${tracker.getSeconds()}s)` + ) + return true + } catch (error) { + this.#logger.error(`Plugin admin extensions build failed`, error) + return false + } + } } diff --git a/packages/medusa/src/commands/plugin/build.ts b/packages/medusa/src/commands/plugin/build.ts index dc72625f4682e..034c55d7bf2b9 100644 --- a/packages/medusa/src/commands/plugin/build.ts +++ b/packages/medusa/src/commands/plugin/build.ts @@ -1,12 +1,10 @@ -import { logger } from "@medusajs/framework/logger" +import { plugin } from "@medusajs/admin-bundler" import { Compiler } from "@medusajs/framework/build-tools" - +import { logger } from "@medusajs/framework/logger" export default async function build({ directory, - adminOnly, }: { directory: string - adminOnly: boolean }): Promise { logger.info("Starting build...") const compiler = new Compiler(directory, logger) @@ -18,5 +16,8 @@ export default async function build({ } await compiler.buildPluginBackend(tsConfig) + await compiler.buildPluginAdminExtensions({ + plugin, + }) return true } diff --git a/yarn.lock b/yarn.lock index 4d4c79f905811..d63adad42add0 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5252,7 +5252,7 @@ __metadata: compression: ^1.7.4 copyfiles: ^2.4.1 express: ^4.21.0 - glob: ^11.0.0 + glob: ^10.3.10 postcss: ^8.4.32 tailwindcss: ^3.3.6 tsup: ^8.0.1 @@ -5486,7 +5486,7 @@ __metadata: express: ^4.21.0 fs-exists-cached: ^1.0.0 fs-extra: ^10.0.0 - glob: ^7.1.6 + glob: ^10.3.10 hosted-git-info: ^4.0.2 inquirer: ^8.0.0 is-valid-path: ^0.1.1