[Bug]: `medusa plugin:build` does not resolve TypeScript path aliases in admin extensions
Package.json file
{
"name": "@vicacha-devs/medusa-plugin-b2b",
"version": "0.0.1",
"description": "B2B commerce capabilities for Medusa v2: companies, employees, quotes, approvals, spending limits, and B2B cart workflows.",
"author": "Vicacha Devs",
"license": "MIT",
"files": [
".medusa/server",
"src",
"README.md",
"LICENSE",
"tsconfig.json"
],
"exports": {
"./package.json": "./package.json",
"./workflows": "./.medusa/server/src/workflows/index.js",
"./.medusa/server/src/modules/*": "./.medusa/server/src/modules/*/index.js",
"./modules/*": "./.medusa/server/src/modules/*/index.js",
"./providers/*": "./.medusa/server/src/providers/*/index.js",
"./*": "./.medusa/server/src/*.js",
"./admin": {
"import": "./.medusa/server/src/admin/index.mjs",
"require": "./.medusa/server/src/admin/index.js",
"default": "./.medusa/server/src/admin/index.js"
}
},
"keywords": [
"medusa",
"plugin",
"medusa-plugin-b2b",
"medusa-plugin",
"medusa-plugin-other",
"medusa-v2"
],
"scripts": {
"build": "medusa plugin:build && tsc-alias -p tsconfig.json",
"publish:local": "medusa plugin:publish",
"dev": "medusa plugin:develop",
"lint": "medusa lint",
"prepublishOnly": "medusa plugin:build",
"test": "pnpm test:unit && pnpm test:integration:modules && pnpm test:integration:http",
"test:integration:http": "TEST_TYPE=integration:http NODE_OPTIONS=--experimental-vm-modules jest --silent=false --runInBand --forceExit",
"test:integration:modules": "TEST_TYPE=integration:modules NODE_OPTIONS=--experimental-vm-modules jest --silent --runInBand --forceExit",
"test:unit": "TEST_TYPE=unit NODE_OPTIONS=--experimental-vm-modules jest --silent --runInBand --forceExit",
"clean": "rm -rf .medusa node_modules"
},
"devDependencies": {
"@hookform/resolvers": "5.7.1",
"@medusajs/admin-sdk": "2.18.0",
"@medusajs/admin-shared": "2.18.0",
"@medusajs/cli": "2.18.0",
"@medusajs/core-flows": "2.18.0",
"@medusajs/framework": "2.18.0",
"@medusajs/icons": "2.18.0",
"@medusajs/js-sdk": "2.18.0",
"@medusajs/medusa": "2.18.0",
"@medusajs/test-utils": "2.18.0",
"@medusajs/types": "2.18.0",
"@medusajs/ui": "4.2.0",
"@radix-ui/react-popover": "1.1.23",
"@radix-ui/react-radio-group": "1.4.7",
"@radix-ui/react-slot": "1.3.3",
"@swc/core": "1.7.28",
"@tanstack/react-table": "8.20.5",
"@types/node": "20.0.0",
"@types/react": "18.3.2",
"@types/react-dom": "18.2.25",
"cmdk": "1.1.1",
"date-fns": "4.4.0",
"jiti": "2.0.0",
"lodash": "4.18.1",
"prop-types": "15.8.1",
"react": "18.2.0",
"react-dom": "18.2.0",
"ts-node": "10.9.2",
"tsc-alias": "^1.9.2",
"typescript": "5.6.2",
"vite": "5.2.11"
},
"peerDependencies": {
"@medusajs/admin-sdk": "2.18.0",
"@medusajs/admin-shared": "2.18.0",
"@medusajs/core-flows": "2.18.0",
"@medusajs/framework": "2.18.0",
"@medusajs/icons": "2.18.0",
"@medusajs/js-sdk": "2.18.0",
"@medusajs/medusa": "2.18.0",
"@medusajs/types": "2.18.0",
"@medusajs/ui": "4.2.0",
"@tanstack/react-table": "8.20.5",
"@uiw/react-json-view": "2.0.0-alpha.43",
"react-hook-form": "7.85.0",
"zod": "4.4.3"
},
"engines": {
"node": ">=20"
},
"packageManager": "[email protected]",
"dependencies": {
"@medusajs/dashboard": "2.18.0"
}
}Node.js version
v25.9.0
Database and its version
PostgreSQL 16.2
Operating system name and version
Deepin 25
Browser name
Firefox
What happended?
Description
When building a Medusa plugin with admin UI extensions, TypeScript path aliases configured following the official TS aliases documentation are not resolved during the admin extensions build step. The aliases work correctly for the backend plugin source, but fail silently at build time for the admin UI.
Steps to Reproduce
- Create a Medusa plugin with admin UI extensions under
src/admin/. - Add a
tsconfig.jsoninsidesrc/admin/with path aliases as documented:
{
"compilerOptions": {
"paths": {
"@/*": ["./*"]
}
}
}- Use
@/aliases in admin source files, e.g.:
import { useCompanies } from "@/hooks/api";
import { DataTable } from "@/components";- Run
medusa plugin:build(ormedusa plugin:publish).
Root Cause
The @medusajs/admin-bundler plugin() command generates a Vite config internally without configuring resolve.alias for path aliases, and without including a plugin like vite-tsconfig-paths. The generated config is approximately:
const pluginConfig = {
build: {
lib: { entry: "src/admin/__admin-extensions__.js", ... },
...
},
plugins: [
react(),
medusa({ pluginMode: true, sources: ["src/admin"] }),
clearPluginBuild({ outDir })
],
// ❌ No resolve.alias for @/
// ❌ No vite-tsconfig-paths
};
await vite.build(pluginConfig);Because process.cwd() is the plugin package root (not src/admin/), Vite reads the root tsconfig.json which does not contain the @/* alias — only the admin-specific tsconfig does. As a result, @/ is treated as a bare package specifier (similar to @scope/package) and Rollup fails to resolve it.
The backend build (compiler.buildPluginBackend) works correctly because tsc is invoked with the correct tsconfig path, which includes the aliases. The admin build does not benefit from this.
Workaround
Replace all @/ alias imports with relative imports in every admin source file. This is tedious but works. Example:
// Before (breaks build)
import { useCompanies } from "@/hooks/api";
// After (works)
import { useCompanies } from "../../hooks/api/index";Suggested Fix
The plugin() function in @medusajs/admin-bundler should read the src/admin/tsconfig.json (or the tsconfig pointed to by the plugin's admin source directory) and apply any paths entries as Vite resolve.alias entries. Alternatively, adding vite-tsconfig-paths to the plugin config pointed at the admin tsconfig would work:
import tsconfigPaths from "vite-tsconfig-paths";
const pluginConfig = {
plugins: [
react(),
tsconfigPaths({ projects: [path.resolve(options.root, "src/admin/tsconfig.json")] }),
medusa({ pluginMode: true, sources: [...] }),
],
...
};Expected behavior
The admin extensions build should resolve @/ path aliases the same way the TypeScript compiler does, as the aliases are configured in the src/admin/tsconfig.json following the documented pattern.
Actual behavior
The build fails with Rollup resolution errors for every @/ alias import:
Plugin admin extensions build failed: [vite]: Rollup failed to resolve import "@/hooks/api"
from "src/admin/routes/b2b/page.tsx".
This is most likely unintended because it can break your application at runtime.
If you do want to externalize this module explicitly add it to `build.rollupOptions.external`Link to reproduction repo
Source: medusajs/medusa