feat(admin-sdk,admin-bundler,admin-shared,medusa): Restructure admin packages (#8988)

**What**
- Renames /admin-next -> /admin
- Renames @medusajs/admin-sdk -> @medusajs/admin-bundler
- Creates a new package called @medusajs/admin-sdk that will hold all tooling relevant to creating admin extensions. This is currently `defineRouteConfig` and `defineWidgetConfig`, but will eventually also export methods for adding custom fields, register translation, etc. 
  - cc: @shahednasser we should update the examples in the docs so these functions are imported from `@medusajs/admin-sdk`. People will also need to install the package in their project, as it's no longer a transient dependency.
  - cc: @olivermrbl we might want to publish a changelog when this is merged, as it is a breaking change, and will require people to import the `defineXConfig` from the new package instead of `@medusajs/admin-shared`.
- Updates CODEOWNERS so /admin packages does not require a review from the UI team.
This commit is contained in:
Kasper Fabricius Kristensen
2024-09-04 19:00:25 +00:00
committed by GitHub
parent beaa851302
commit 0fe1201435
1440 changed files with 122 additions and 86 deletions
@@ -0,0 +1,9 @@
import App from "@medusajs/dashboard"
import React from "react"
import { createRoot } from "react-dom/client"
import "./index.css"
const container = document.getElementById("root")
const root = createRoot(container!)
root.render(<App />)
@@ -0,0 +1,5 @@
@import "@medusajs/dashboard/css";
@tailwind base;
@tailwind components;
@tailwind utilities;
@@ -0,0 +1,13 @@
<!doctype html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no" />
<link rel="icon" href="data:," data-placeholder-favicon />
</head>
<body>
<div id="root"></div>
<script type="module" src="./entry.tsx"></script>
</body>
</html>
@@ -0,0 +1,5 @@
export { build } from "./lib/build"
export { develop } from "./lib/develop"
export { serve } from "./lib/serve"
export * from "./types"
@@ -0,0 +1,15 @@
import type { InlineConfig } from "vite"
import { BundlerOptions } from "../types"
import { getViteConfig } from "./config"
export async function build(options: BundlerOptions) {
const vite = await import("vite")
const viteConfig = await getViteConfig(options)
const buildConfig: InlineConfig = {
mode: "production",
logLevel: "error",
}
await vite.build(vite.mergeConfig(viteConfig, buildConfig))
}
@@ -0,0 +1,109 @@
import { VIRTUAL_MODULES } from "@medusajs/admin-shared"
import path from "path"
import { Config } from "tailwindcss"
import type { InlineConfig } from "vite"
import { BundlerOptions } from "../types"
export async function getViteConfig(
options: BundlerOptions
): Promise<InlineConfig> {
const { searchForWorkspaceRoot, mergeConfig } = await import("vite")
const { default: react } = await import("@vitejs/plugin-react")
const { default: medusa } = await import("@medusajs/admin-vite-plugin")
const getPort = await import("get-port")
const hmrPort = await getPort.default()
const root = path.resolve(__dirname, "./")
const backendUrl = options.backendUrl ?? ""
const storefrontUrl = options.storefrontUrl ?? ""
const baseConfig: InlineConfig = {
root,
base: options.path,
build: {
emptyOutDir: true,
outDir: path.resolve(process.cwd(), options.outDir),
},
optimizeDeps: {
include: ["@medusajs/dashboard", "react-dom/client"],
exclude: VIRTUAL_MODULES,
},
define: {
__BASE__: JSON.stringify(options.path),
__BACKEND_URL__: JSON.stringify(backendUrl),
__STOREFRONT_URL__: JSON.stringify(storefrontUrl),
},
server: {
fs: {
allow: [searchForWorkspaceRoot(process.cwd())],
},
hmr: {
port: hmrPort,
},
middlewareMode: true,
},
css: {
postcss: {
plugins: [
require("tailwindcss")({
config: createTailwindConfig(root, options.sources),
}),
],
},
},
plugins: [
react(),
medusa({
sources: options.sources,
}),
],
}
if (options.vite) {
const customConfig = options.vite(baseConfig)
return mergeConfig(baseConfig, customConfig)
}
return baseConfig
}
function createTailwindConfig(entry: string, sources: string[] = []) {
const root = path.join(entry, "**/*.{js,ts,jsx,tsx}")
const html = path.join(entry, "index.html")
let dashboard = ""
try {
dashboard = path.join(
path.dirname(require.resolve("@medusajs/dashboard")),
"**/*.{js,ts,jsx,tsx}"
)
} catch (_e) {
// ignore
}
let ui: string = ""
try {
ui = path.join(
path.dirname(require.resolve("@medusajs/ui")),
"**/*.{js,ts,jsx,tsx}"
)
} catch (_e) {
// ignore
}
const extensions = sources.map((s) => path.join(s, "**/*.{js,ts,jsx,tsx}"))
const config: Config = {
presets: [require("@medusajs/ui-preset")],
content: [html, root, dashboard, ui, ...extensions],
darkMode: "class",
}
return config
}
@@ -0,0 +1,33 @@
import express from "express"
import type { InlineConfig } from "vite"
import { BundlerOptions } from "../types"
import { getViteConfig } from "./config"
const router = express.Router()
export async function develop(options: BundlerOptions) {
const vite = await import("vite")
try {
const viteConfig = await getViteConfig(options)
const developConfig: InlineConfig = {
mode: "development",
logLevel: "warn",
}
const server = await vite.createServer(
vite.mergeConfig(viteConfig, developConfig)
)
router.use(server.middlewares)
} catch (error) {
console.error(error)
throw new Error(
"Failed to start admin development server. See error above."
)
}
return router
}
@@ -0,0 +1,56 @@
import compression from "compression"
import { Request, Response, Router, static as static_ } from "express"
import fs from "fs"
import { ServerResponse } from "http"
import path from "path"
type ServeOptions = {
outDir: string
}
const router = Router()
export async function serve(options: ServeOptions) {
const htmlPath = path.resolve(options.outDir, "index.html")
/**
* The admin UI should always be built at this point, but in the
* rare case that another plugin terminated a previous startup, the admin
* may not have been built correctly. Here we check if the admin UI
* build files exist, and if not, we throw an error, providing the
* user with instructions on how to fix their build.
*/
const indexExists = fs.existsSync(htmlPath)
if (!indexExists) {
throw new Error(
`Could not find index.html in the admin build directory. Make sure to run 'medusa build' before starting the server.`
)
}
const html = fs.readFileSync(htmlPath, "utf-8")
const sendHtml = (_req: Request, res: Response) => {
res.setHeader("Cache-Control", "no-cache")
res.setHeader("Vary", "Origin, Cache-Control")
res.send(html)
}
const setStaticHeaders = (res: ServerResponse) => {
res.setHeader("Cache-Control", "max-age=31536000, immutable")
res.setHeader("Vary", "Origin, Cache-Control")
}
router.use(compression())
router.get("/", sendHtml)
router.use(
static_(options.outDir, {
setHeaders: setStaticHeaders,
})
)
router.get(`/*`, sendHtml)
return router
}
@@ -0,0 +1,6 @@
import { AdminOptions } from "@medusajs/types"
export type BundlerOptions = Required<Pick<AdminOptions, "outDir" | "path">> &
Pick<AdminOptions, "vite" | "backendUrl" | "storefrontUrl"> & {
sources?: string[]
}