feat(dashboard,admin-sdk,admin-shared,admin-vite-plugin): Add support for UI extensions (#7383)

* intial work

* update lock

* add routes and fix HMR of configs

* cleanup

* rm imports

* rm debug from plugin

* address feedback

* address feedback
This commit is contained in:
Kasper Fabricius Kristensen
2024-05-23 14:02:19 +02:00
committed by GitHub
parent 521c252dee
commit f1176a0673
50 changed files with 1366 additions and 1098 deletions

View File

@@ -1,5 +1,9 @@
import { defineRouteConfig, defineWidgetConfig } from "@medusajs/admin-shared"
export { build } from "./lib/build"
export { develop } from "./lib/develop"
export { serve } from "./lib/serve"
export { defineRouteConfig, defineWidgetConfig }
export * from "./types"

View File

@@ -1,3 +1,4 @@
import type { InlineConfig } from "vite"
import { BundlerOptions } from "../types"
import { getViteConfig } from "./config"
@@ -5,13 +6,10 @@ export async function build(options: BundlerOptions) {
const vite = await import("vite")
const viteConfig = await getViteConfig(options)
try {
await vite.build(
vite.mergeConfig(viteConfig, { mode: "production", logLevel: "silent" })
)
} catch (error) {
console.error(error)
throw new Error("Failed to build admin panel")
const buildConfig: InlineConfig = {
mode: "production",
logLevel: "error",
}
await vite.build(vite.mergeConfig(viteConfig, buildConfig))
}

View File

@@ -1,3 +1,4 @@
import { VIRTUAL_MODULES } from "@medusajs/admin-shared"
import path from "path"
import { Config } from "tailwindcss"
import type { InlineConfig } from "vite"
@@ -10,7 +11,7 @@ export async function getViteConfig(
): Promise<InlineConfig> {
const { searchForWorkspaceRoot } = await import("vite")
const { default: react } = await import("@vitejs/plugin-react")
const { default: inject } = await import("@medusajs/admin-vite-plugin")
const { default: medusa } = await import("@medusajs/admin-vite-plugin")
const getPort = await import("get-port")
const hmrPort = await getPort.default()
@@ -20,7 +21,7 @@ export async function getViteConfig(
const backendUrl = options.backendUrl ?? ""
return {
root: path.resolve(__dirname, "./"),
root,
base: options.path,
build: {
emptyOutDir: true,
@@ -28,19 +29,15 @@ export async function getViteConfig(
},
optimizeDeps: {
include: ["@medusajs/dashboard", "react-dom/client"],
exclude: VIRTUAL_MODULES,
},
define: {
__BASE__: JSON.stringify(options.path),
__BACKEND_URL__: JSON.stringify(backendUrl),
},
server: {
open: true,
fs: {
allow: [
searchForWorkspaceRoot(process.cwd()),
path.resolve(__dirname, "../../medusa"),
path.resolve(__dirname, "../../app"),
],
allow: [searchForWorkspaceRoot(process.cwd())],
},
hmr: {
port: hmrPort,
@@ -51,20 +48,22 @@ export async function getViteConfig(
postcss: {
plugins: [
require("tailwindcss")({
config: createTailwindConfig(root),
config: createTailwindConfig(root, options.sources),
}),
],
},
},
/**
* TODO: Remove polyfills, they are currently only required for the
* `axios` dependency in the dashboard. Once we have the new SDK,
* we should remove this, and leave it up to the user to include
* polyfills if they need them.
*/
plugins: [
react(),
inject(),
medusa({
sources: options.sources,
}),
/**
* TODO: Remove polyfills, they are currently only required for the
* `axios` dependency in the dashboard. Once we have the new SDK,
* we should remove this, and leave it up to the user to include
* polyfills if they need them.
*/
nodePolyfills({
include: ["crypto", "util", "stream"],
}),
@@ -72,7 +71,7 @@ export async function getViteConfig(
}
}
function createTailwindConfig(entry: string) {
function createTailwindConfig(entry: string, sources: string[] = []) {
const root = path.join(entry, "**/*.{js,ts,jsx,tsx}")
const html = path.join(entry, "index.html")
@@ -98,9 +97,11 @@ function createTailwindConfig(entry: string) {
// 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],
content: [html, root, dashboard, ui, ...extensions],
darkMode: "class",
}

View File

@@ -1,4 +1,5 @@
import express from "express"
import type { InlineConfig } from "vite"
import { BundlerOptions } from "../types"
import { getViteConfig } from "./config"
@@ -10,14 +11,22 @@ export async function develop(options: BundlerOptions) {
try {
const viteConfig = await getViteConfig(options)
const developConfig: InlineConfig = {
mode: "development",
logLevel: "warn",
}
const server = await vite.createServer(
vite.mergeConfig(viteConfig, { logLevel: "info", mode: "development" })
vite.mergeConfig(viteConfig, developConfig)
)
router.use(server.middlewares)
} catch (error) {
console.error(error)
throw new Error("Could not start development server")
throw new Error(
"Failed to start admin development server. See error above."
)
}
return router

View File

@@ -1,3 +1,4 @@
import compression from "compression"
import { Request, Response, Router, static as static_ } from "express"
import fs from "fs"
import { ServerResponse } from "http"
@@ -24,7 +25,7 @@ export async function serve(options: ServeOptions) {
if (!indexExists) {
throw new Error(
`Could not find the admin UI build files. Please run \`npm run build\` or \`yarn build\` command and try again.`
`Could not find index.html in the admin build directory. Make sure to run 'medusa build' before starting the server.`
)
}
@@ -41,6 +42,8 @@ export async function serve(options: ServeOptions) {
res.setHeader("Vary", "Origin, Cache-Control")
}
router.use(compression())
router.get("/", sendHtml)
router.use(
static_(options.outDir, {

View File

@@ -1,4 +1,6 @@
import { AdminOptions } from "@medusajs/types"
export type BundlerOptions = Required<Pick<AdminOptions, "outDir" | "path">> &
Pick<AdminOptions, "vite" | "backendUrl">
Pick<AdminOptions, "vite" | "backendUrl"> & {
sources?: string[]
}